This commit is contained in:
Andreas Gal 2011-06-22 01:05:11 -04:00
commit d64691a95b

889
pdf.js
View File

@ -65,45 +65,46 @@ var Stream = (function() {
this.dict = dict; this.dict = dict;
} }
// required methods for a stream. if a particular stream does not
// implement these, an error should be thrown
constructor.prototype = { constructor.prototype = {
get length() { get length() {
return this.end - this.start; return this.end - this.start;
}, },
getByte: function() { getByte: function() {
var bytes = this.bytes;
if (this.pos >= this.end) if (this.pos >= this.end)
return -1; return;
return bytes[this.pos++]; return this.bytes[this.pos++];
}, },
// returns subarray of original buffer // returns subarray of original buffer
// should only be read // should only be read
getBytes: function(length) { getBytes: function(length) {
var bytes = this.bytes; var bytes = this.bytes;
var pos = this.pos; var pos = this.pos;
var strEnd = this.end;
if (!length)
return bytes.subarray(pos, strEnd);
var end = pos + length; var end = pos + length;
var strEnd = this.end; if (end > strEnd)
if (!end || end > strEnd)
end = strEnd; end = strEnd;
this.pos = end; this.pos = end;
return bytes.subarray(pos, end); return bytes.subarray(pos, end);
}, },
lookChar: function() { lookChar: function() {
var bytes = this.bytes;
if (this.pos >= this.end) if (this.pos >= this.end)
return; return;
return String.fromCharCode(bytes[this.pos]); return String.fromCharCode(this.bytes[this.pos]);
}, },
getChar: function() { getChar: function() {
var ch = this.lookChar(); if (this.pos >= this.end)
if (!ch) return;
return ch; return String.fromCharCode(this.bytes[this.pos++]);
this.pos++;
return ch;
}, },
skip: function(n) { skip: function(n) {
if (!n && !IsNum(n)) if (!n)
n = 1; n = 1;
this.pos += n; this.pos += n;
}, },
@ -135,6 +136,84 @@ var StringStream = (function() {
return constructor; return constructor;
})(); })();
// super class for the decoding streams
var DecodeStream = (function() {
function constructor() {
this.pos = 0;
this.bufferLength = 0;
this.eof = false;
this.buffer = null;
}
constructor.prototype = {
ensureBuffer: function(requested) {
var buffer = this.buffer;
var current = buffer ? buffer.byteLength : 0;
if (requested < current)
return buffer;
var size = 512;
while (size < requested)
size <<= 1;
var buffer2 = Uint8Array(size);
for (var i = 0; i < current; ++i)
buffer2[i] = buffer[i];
return this.buffer = buffer2;
},
getByte: function() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
}
return this.buffer[this.pos++];
},
getBytes: function(length) {
var pos = this.pos;
this.ensureBuffer(pos + length);
while (!this.eof && this.bufferLength < pos + length)
this.readBlock();
var end = pos + length;
var bufEnd = this.bufferLength;
if (end > bufEnd)
end = bufEnd;
this.pos = end;
return this.buffer.subarray(pos, end)
},
lookChar: function() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
}
return String.fromCharCode(this.buffer[this.pos]);
},
getChar: function() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
}
return String.fromCharCode(this.buffer[this.pos++]);
},
skip: function(n) {
if (!n)
n = 1;
this.pos += n;
}
};
return constructor;
})();
var FlateStream = (function() { var FlateStream = (function() {
const codeLenCodeMap = Uint32Array([ const codeLenCodeMap = Uint32Array([
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
@ -259,257 +338,195 @@ var FlateStream = (function() {
this.bytes = bytes; this.bytes = bytes;
this.bytesPos = bytesPos; this.bytesPos = bytesPos;
this.eof = false;
this.codeSize = 0; this.codeSize = 0;
this.codeBuf = 0; this.codeBuf = 0;
this.pos = 0; DecodeStream.call(this);
this.bufferLength = 0;
} }
constructor.prototype = { constructor.prototype = Object.create(DecodeStream.prototype);
getBits: function(bits) {
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
var bytes = this.bytes;
var bytesPos = this.bytesPos;
var b; constructor.prototype.getBits = function(bits) {
while (codeSize < bits) { var codeSize = this.codeSize;
if (typeof (b = bytes[bytesPos++]) == "undefined") var codeBuf = this.codeBuf;
error("Bad encoding in flate stream"); var bytes = this.bytes;
codeBuf |= b << codeSize; var bytesPos = this.bytesPos;
codeSize += 8;
}
b = codeBuf & ((1 << bits) - 1);
this.codeBuf = codeBuf >> bits;
this.codeSize = codeSize -= bits;
this.bytesPos = bytesPos;
return b;
},
getCode: function(table) {
var codes = table[0];
var maxLen = table[1];
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
var bytes = this.bytes;
var bytesPos = this.bytesPos;
while (codeSize < maxLen) { var b;
var b; while (codeSize < bits) {
if (typeof (b = bytes[bytesPos++]) == "undefined") if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad encoding in flate stream");
codeBuf |= (b << codeSize);
codeSize += 8;
}
var code = codes[codeBuf & ((1 << maxLen) - 1)];
var codeLen = code >> 16;
var codeVal = code & 0xffff;
if (codeSize == 0|| codeSize < codeLen || codeLen == 0)
error("Bad encoding in flate stream"); error("Bad encoding in flate stream");
this.codeBuf = (codeBuf >> codeLen); codeBuf |= b << codeSize;
this.codeSize = (codeSize - codeLen); codeSize += 8;
this.bytesPos = bytesPos; }
return codeVal; b = codeBuf & ((1 << bits) - 1);
}, this.codeBuf = codeBuf >> bits;
ensureBuffer: function(requested) { this.codeSize = codeSize -= bits;
var buffer = this.buffer; this.bytesPos = bytesPos;
var current = buffer ? buffer.length : 0; return b;
if (requested < current) };
return buffer; constructor.prototype.getCode = function(table) {
var size = 512; var codes = table[0];
while (size < requested) var maxLen = table[1];
size <<= 1; var codeSize = this.codeSize;
var buffer2 = Uint8Array(size); var codeBuf = this.codeBuf;
for (var i = 0; i < current; ++i) var bytes = this.bytes;
buffer2[i] = buffer[i]; var bytesPos = this.bytesPos;
return this.buffer = buffer2;
},
getByte: function() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
}
return this.buffer[this.pos++];
},
getBytes: function(length) {
var pos = this.pos;
while (!this.eof && this.bufferLength < pos + length)
this.readBlock();
var end = pos + length;
var bufEnd = this.bufferLength;
if (end > bufEnd)
end = bufEnd;
this.pos = end;
return this.buffer.subarray(pos, end)
},
lookChar: function() {
var pos = this.pos;
while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
}
return String.fromCharCode(this.buffer[pos]);
},
getChar: function() {
var ch = this.lookChar();
// shouldnt matter what the position is if we get past the eof
// so no need to check if ch is undefined
this.pos++;
return ch;
},
skip: function(n) {
if (!n)
n = 1;
this.pos += n;
},
generateHuffmanTable: function(lengths) {
var n = lengths.length;
// find max code length
var maxLen = 0;
for (var i = 0; i < n; ++i) {
if (lengths[i] > maxLen)
maxLen = lengths[i];
}
// build the table
var size = 1 << maxLen;
var codes = Uint32Array(size);
for (var len = 1, code = 0, skip = 2;
len <= maxLen;
++len, code <<= 1, skip <<= 1) {
for (var val = 0; val < n; ++val) {
if (lengths[val] == len) {
// bit-reverse the code
var code2 = 0;
var t = code;
for (var i = 0; i < len; ++i) {
code2 = (code2 << 1) | (t & 1);
t >>= 1;
}
// fill the table entries
for (var i = code2; i < size; i += skip)
codes[i] = (len << 16) | val;
++code;
}
}
}
return [codes, maxLen];
},
readBlock: function() {
function repeat(stream, array, len, offset, what) {
var repeat = stream.getBits(len) + offset;
while (repeat-- > 0)
array[i++] = what;
}
var bytes = this.bytes;
var bytesPos = this.bytesPos;
// read block header
var hdr = this.getBits(3);
if (hdr & 1)
this.eof = true;
hdr >>= 1;
while (codeSize < maxLen) {
var b; var b;
if (hdr == 0) { // uncompressed block if (typeof (b = bytes[bytesPos++]) == "undefined")
if (typeof (b = bytes[bytesPos++]) == "undefined") error("Bad encoding in flate stream");
error("Bad block header in flate stream"); codeBuf |= (b << codeSize);
var blockLen = b; codeSize += 8;
if (typeof (b = bytes[bytesPos++]) == "undefined") }
error("Bad block header in flate stream"); var code = codes[codeBuf & ((1 << maxLen) - 1)];
blockLen |= (b << 8); var codeLen = code >> 16;
if (typeof (b = bytes[bytesPos++]) == "undefined") var codeVal = code & 0xffff;
error("Bad block header in flate stream"); if (codeSize == 0|| codeSize < codeLen || codeLen == 0)
var check = b; error("Bad encoding in flate stream");
if (typeof (b = bytes[bytesPos++]) == "undefined") this.codeBuf = (codeBuf >> codeLen);
error("Bad block header in flate stream"); this.codeSize = (codeSize - codeLen);
check |= (b << 8); this.bytesPos = bytesPos;
if (check != (~this.blockLen & 0xffff)) return codeVal;
error("Bad uncompressed block length in flate stream"); };
var bufferLength = this.bufferLength; constructor.prototype.generateHuffmanTable = function(lengths) {
var buffer = this.ensureBuffer(bufferLength + blockLen); var n = lengths.length;
this.bufferLength = bufferLength + blockLen;
for (var n = bufferLength; n < blockLen; ++n) { // find max code length
if (typeof (b = bytes[bytesPos++]) == "undefined") { var maxLen = 0;
this.eof = true; for (var i = 0; i < n; ++i) {
break; if (lengths[i] > maxLen)
maxLen = lengths[i];
}
// build the table
var size = 1 << maxLen;
var codes = Uint32Array(size);
for (var len = 1, code = 0, skip = 2;
len <= maxLen;
++len, code <<= 1, skip <<= 1) {
for (var val = 0; val < n; ++val) {
if (lengths[val] == len) {
// bit-reverse the code
var code2 = 0;
var t = code;
for (var i = 0; i < len; ++i) {
code2 = (code2 << 1) | (t & 1);
t >>= 1;
} }
buffer[n] = b;
// fill the table entries
for (var i = code2; i < size; i += skip)
codes[i] = (len << 16) | val;
++code;
} }
}
}
return [codes, maxLen];
};
constructor.prototype.readBlock = function() {
function repeat(stream, array, len, offset, what) {
var repeat = stream.getBits(len) + offset;
while (repeat-- > 0)
array[i++] = what;
}
var bytes = this.bytes;
var bytesPos = this.bytesPos;
// read block header
var hdr = this.getBits(3);
if (hdr & 1)
this.eof = true;
hdr >>= 1;
var b;
if (hdr == 0) { // uncompressed block
if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
var blockLen = b;
if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
blockLen |= (b << 8);
if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
var check = b;
if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
check |= (b << 8);
if (check != (~this.blockLen & 0xffff))
error("Bad uncompressed block length in flate stream");
var bufferLength = this.bufferLength;
var buffer = this.ensureBuffer(bufferLength + blockLen);
this.bufferLength = bufferLength + blockLen;
for (var n = bufferLength; n < blockLen; ++n) {
if (typeof (b = bytes[bytesPos++]) == "undefined") {
this.eof = true;
break;
}
buffer[n] = b;
}
return;
}
var litCodeTable;
var distCodeTable;
if (hdr == 1) { // compressed block, fixed codes
litCodeTable = fixedLitCodeTab;
distCodeTable = fixedDistCodeTab;
} else if (hdr == 2) { // compressed block, dynamic codes
var numLitCodes = this.getBits(5) + 257;
var numDistCodes = this.getBits(5) + 1;
var numCodeLenCodes = this.getBits(4) + 4;
// build the code lengths code table
var codeLenCodeLengths = Array(codeLenCodeMap.length);
var i = 0;
while (i < numCodeLenCodes)
codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
// build the literal and distance code tables
var len = 0;
var i = 0;
var codes = numLitCodes + numDistCodes;
var codeLengths = new Array(codes);
while (i < codes) {
var code = this.getCode(codeLenCodeTab);
if (code == 16) {
repeat(this, codeLengths, 2, 3, len);
} else if (code == 17) {
repeat(this, codeLengths, 3, 3, len = 0);
} else if (code == 18) {
repeat(this, codeLengths, 7, 11, len = 0);
} else {
codeLengths[i++] = len = code;
}
}
litCodeTable =
this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
distCodeTable =
this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
} else {
error("Unknown block type in flate stream");
}
var pos = this.bufferLength;
while (true) {
var code1 = this.getCode(litCodeTable);
if (code1 == 256) {
this.bufferLength = pos;
return; return;
} }
if (code1 < 256) {
var litCodeTable; var buffer = this.ensureBuffer(pos + 1);
var distCodeTable; buffer[pos++] = code1;
if (hdr == 1) { // compressed block, fixed codes
litCodeTable = fixedLitCodeTab;
distCodeTable = fixedDistCodeTab;
} else if (hdr == 2) { // compressed block, dynamic codes
var numLitCodes = this.getBits(5) + 257;
var numDistCodes = this.getBits(5) + 1;
var numCodeLenCodes = this.getBits(4) + 4;
// build the code lengths code table
var codeLenCodeLengths = Array(codeLenCodeMap.length);
var i = 0;
while (i < numCodeLenCodes)
codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
// build the literal and distance code tables
var len = 0;
var i = 0;
var codes = numLitCodes + numDistCodes;
var codeLengths = new Array(codes);
while (i < codes) {
var code = this.getCode(codeLenCodeTab);
if (code == 16) {
repeat(this, codeLengths, 2, 3, len);
} else if (code == 17) {
repeat(this, codeLengths, 3, 3, len = 0);
} else if (code == 18) {
repeat(this, codeLengths, 7, 11, len = 0);
} else {
codeLengths[i++] = len = code;
}
}
litCodeTable = this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
distCodeTable = this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
} else { } else {
error("Unknown block type in flate stream");
}
var pos = this.bufferLength;
var buffer = this.buffer;
var limit = buffer ? buffer.length : 0;
while (true) {
var code1 = this.getCode(litCodeTable);
if (code1 < 256) {
if (pos + 1 >= limit) {
buffer = this.ensureBuffer(pos + 1);
limit = buffer.length;
}
buffer[pos++] = code1;
continue;
}
if (code1 == 256) {
this.bufferLength = pos;
return;
}
code1 -= 257; code1 -= 257;
code1 = lengthDecode[code1]; code1 = lengthDecode[code1];
var code2 = code1 >> 16; var code2 = code1 >> 16;
@ -522,10 +539,7 @@ var FlateStream = (function() {
if (code2 > 0) if (code2 > 0)
code2 = this.getBits(code2); code2 = this.getBits(code2);
var dist = (code1 & 0xffff) + code2; var dist = (code1 & 0xffff) + code2;
if (pos + len >= limit) { var buffer = this.ensureBuffer(pos + len);
buffer = this.ensureBuffer(pos + len);
limit = buffer.length;
}
for (var k = 0; k < len; ++k, ++pos) for (var k = 0; k < len; ++k, ++pos)
buffer[pos] = buffer[pos - dist]; buffer[pos] = buffer[pos - dist];
} }
@ -534,6 +548,183 @@ var FlateStream = (function() {
return constructor; return constructor;
})(); })();
var PredictorStream = (function() {
function constructor(stream, params) {
var predictor = this.predictor = params.get("Predictor") || 1;
if (predictor <= 1)
return stream; // no prediction
if (predictor !== 2 && (predictor < 10 || predictor > 15))
error("Unsupported predictor");
if (predictor === 2)
this.readBlock = this.readBlockTiff;
else
this.readBlock = this.readBlockPng;
this.stream = stream;
this.dict = stream.dict;
if (params.has("EarlyChange")) {
error("EarlyChange predictor parameter is not supported");
}
var colors = this.colors = params.get("Colors") || 1;
var bits = this.bits = params.get("BitsPerComponent") || 8;
var columns = this.columns = params.get("Columns") || 1;
var pixBytes = this.pixBytes = (colors * bits + 7) >> 3;
// add an extra pixByte to represent the pixel left of column 0
var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3;
DecodeStream.call(this);
}
constructor.prototype = Object.create(DecodeStream.prototype);
constructor.prototype.readBlockTiff = function() {
var buffer = this.buffer;
var pos = this.pos;
var rowBytes = this.rowBytes;
var pixBytes = this.pixBytes;
var buffer = this.buffer;
var bufferLength = this.bufferLength;
this.ensureBuffer(bufferLength + rowBytes);
var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes);
var bits = this.bits;
var colors = this.colors;
var rawBytes = this.stream.getBytes(rowBytes);
if (bits === 1) {
var inbuf = 0;
for (var i = 0; i < rowBytes; ++i) {
var c = rawBytes[i];
inBuf = (inBuf << 8) | c;
// bitwise addition is exclusive or
// first shift inBuf and then add
currentRow[i] = (c ^ (inBuf >> colors)) & 0xFF;
// truncate inBuf (assumes colors < 16)
inBuf &= 0xFFFF;
}
} else if (bits === 8) {
for (var i = 0; i < colors; ++i)
currentRow[i] = rawBytes[i];
for (; i < rowBytes; ++i)
currentRow[i] = currentRow[i - colors] + rawBytes[i];
} else {
var compArray = new Uint8Array(colors + 1);
var bitMask = (1 << bits) - 1;
var inbuf = 0, outbut = 0;
var inbits = 0, outbits = 0;
var j = 0, k = 0;
var columns = this.columns;
for (var i = 0; i < columns; ++i) {
for (var kk = 0; kk < colors; ++kk) {
if (inbits < bits) {
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
inbits += 8;
}
compArray[kk] = (compArray[kk] +
(inbuf >> (inbits - bits))) & bitMask;
inbits -= bits;
outbuf = (outbuf << bits) | compArray[kk];
outbits += bits;
if (outbits >= 8) {
currentRow[k++] = (outbuf >> (outbits - 8)) & 0xFF;
outbits -= 8;
}
}
}
if (outbits > 0) {
currentRow[k++] = (outbuf << (8 - outbits)) +
(inbuf & ((1 << (8 - outbits)) - 1))
}
}
this.bufferLength += rowBytes;
};
constructor.prototype.readBlockPng = function() {
var buffer = this.buffer;
var pos = this.pos;
var rowBytes = this.rowBytes;
var pixBytes = this.pixBytes;
var predictor = this.stream.getByte();
var rawBytes = this.stream.getBytes(rowBytes);
var buffer = this.buffer;
var bufferLength = this.bufferLength;
this.ensureBuffer(bufferLength + pixBytes);
var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes);
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
if (prevRow.length == 0)
prevRow = currentRow;
switch (predictor) {
case 0:
break;
case 1:
for (var i = 0; i < pixBytes; ++i)
currentRow[i] = rawBytes[i];
for (; i < rowBytes; ++i)
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF;
break;
case 2:
for (var i = 0; i < rowBytes; ++i)
currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF;
break;
case 3:
for (var i = 0; i < pixBytes; ++i)
currentRow[i] = (prevRow[i] >> 1) + rawBytes[i];
for (; i < rowBytes; ++i)
currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes])
>> 1) + rawBytes[i]) & 0xFF;
break;
case 4:
// we need to save the up left pixels values. the simplest way
// is to create a new buffer
for (var i = 0; i < pixBytes; ++i)
currentRow[i] = rawBytes[i];
for (; i < rowBytes; ++i) {
var up = prevRow[i];
var upLeft = lastRow[i - pixBytes];
var left = currentRow[i - pixBytes];
var p = left + up - upLeft;
var pa = p - left;
if (pa < 0)
pa = -pa;
var pb = p - up;
if (pb < 0)
pb = -pb;
var pc = p - upLeft;
if (pc < 0)
pc = -pc;
var c = rawBytes[i];
if (pa <= pb && pa <= pc)
currentRow[i] = left + c;
else if (pb <= pc)
currentRow[i] = up + c;
else
currentRow[i] = upLeft + c;
break;
}
default:
error("Unsupported predictor");
break;
}
this.bufferLength += rowBytes;
};
return constructor;
})();
// A JpegStream can't be read directly. We use the platform to render the underlying // A JpegStream can't be read directly. We use the platform to render the underlying
// JPEG data for us. // JPEG data for us.
var JpegStream = (function() { var JpegStream = (function() {
@ -558,196 +749,6 @@ var JpegStream = (function() {
return constructor; return constructor;
})(); })();
var PredictorStream = (function() {
function constructor(stream, params) {
var predictor = this.predictor = params.get("Predictor") || 1;
if (predictor <= 1)
return stream; // no prediction
if (predictor !== 2 && (predictor < 10 || predictor > 15))
error("Unsupported predictor");
if (predictor === 2)
this.readRow = this.readRowTiff;
else
this.readRow = this.readRowPng;
this.stream = stream;
this.dict = stream.dict;
if (params.has("EarlyChange")) {
error("EarlyChange predictor parameter is not supported");
}
var colors = this.colors = params.get("Colors") || 1;
var bits = this.bits = params.get("BitsPerComponent") || 8;
var columns = this.columns = params.get("Columns") || 1;
var pixBytes = this.pixBytes = (colors * bits + 7) >> 3;
// add an extra pixByte to represent the pixel left of column 0
var rowBytes = this.rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes;
this.currentRow = new Uint8Array(rowBytes);
this.bufferLength = rowBytes;
this.pos = rowBytes;
}
constructor.prototype = {
readRowTiff : function() {
var currentRow = this.currentRow;
var rowBytes = this.rowBytes;
var pixBytes = this.pixBytes;
var bits = this.bits;
var colors = this.colors;
var rawBytes = this.stream.getBytes(rowBytes - pixBytes);
if (bits === 1) {
var inbuf = 0;
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) {
var c = rawBytes[j];
inBuf = (inBuf << 8) | c;
// bitwise addition is exclusive or
// first shift inBuf and then add
currentRow[i] = (c ^ (inBuf >> colors)) & 0xFF;
// truncate inBuf (assumes colors < 16)
inBuf &= 0xFFFF;
}
} else if (bits === 8) {
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j)
currentRow[i] = currentRow[i - colors] + rawBytes[j];
} else {
var compArray = new Uint8Array(colors + 1);
var bitMask = (1 << bits) - 1;
var inbuf = 0, outbut = 0;
var inbits = 0, outbits = 0;
var j = 0, k = pixBytes;
var columns = this.columns;
for (var i = 0; i < columns; ++i) {
for (var kk = 0; kk < colors; ++kk) {
if (inbits < bits) {
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
inbits += 8;
}
compArray[kk] = (compArray[kk] +
(inbuf >> (inbits - bits))) & bitMask;
inbits -= bits;
outbuf = (outbuf << bits) | compArray[kk];
outbits += bits;
if (outbits >= 8) {
currentRow[k++] = (outbuf >> (outbits - 8)) & 0xFF;
outbits -= 8;
}
}
}
if (outbits > 0) {
currentRow[k++] = (outbuf << (8 - outbits)) +
(inbuf & ((1 << (8 - outbits)) - 1))
}
}
this.pos = pixBytes;
},
readRowPng : function() {
var currentRow = this.currentRow;
var rowBytes = this.rowBytes;
var pixBytes = this.pixBytes;
var predictor = this.stream.getByte();
var rawBytes = this.stream.getBytes(rowBytes - pixBytes);
switch (predictor) {
case 0:
break;
case 1:
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j)
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[j]) & 0xFF;
break;
case 2:
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j)
currentRow[i] = (currentRow[i] + rawBytes[j]) & 0xFF;
break;
case 3:
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j)
currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes])
>> 1) + rawBytes[j]) & 0xFF;
break;
case 4:
// we need to save the up left pixels values. the simplest way
// is to create a new buffer
var lastRow = currentRow;
var currentRow = new Uint8Array(rowBytes);
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) {
var up = lastRow[i];
var upLeft = lastRow[i - pixBytes];
var left = currentRow[i - pixBytes];
var p = left + up - upLeft;
var pa = p - left;
if (pa < 0)
pa = -pa;
var pb = p - up;
if (pb < 0)
pb = -pb;
var pc = p - upLeft;
if (pc < 0)
pc = -pc;
var c = rawBytes[j];
if (pa <= pb && pa <= pc)
currentRow[i] = left + c;
else if (pb <= pc)
currentRow[i] = up + c;
else
currentRow[i] = upLeft + c;
break;
this.currentRow = currentRow;
}
default:
error("Unsupported predictor");
break;
}
this.pos = pixBytes;
},
getByte : function() {
if (this.pos >= this.bufferLength)
this.readRow();
return this.currentRow[this.pos++];
},
getBytes : function(n) {
var i, bytes;
bytes = new Uint8Array(n);
for (i = 0; i < n; ++i) {
if (this.pos >= this.bufferLength)
this.readRow();
bytes[i] = this.currentRow[this.pos++];
}
return bytes;
},
getChar : function() {
return String.formCharCode(this.getByte());
},
lookChar : function() {
if (this.pos >= this.bufferLength)
this.readRow();
return String.formCharCode(this.currentRow[this.pos]);
},
skip : function(n) {
var i;
if (!n) {
n = 1;
}
while (n > this.bufferLength - this.pos) {
n -= this.bufferLength - this.pos;
this.readRow();
if (this.bufferLength === 0) break;
}
this.pos += n;
}
};
return constructor;
})();
var DecryptStream = (function() { var DecryptStream = (function() {
function constructor(str, fileKey, encAlgorithm, keyLength) { function constructor(str, fileKey, encAlgorithm, keyLength) {
TODO("decrypt stream is not implemented"); TODO("decrypt stream is not implemented");