return value;
}
+function bytesToString(bytes) {
+ var str = "";
+ var length = bytes.length;
+ for (var n = 0; n < length; ++n)
+ str += String.fromCharCode(bytes[n]);
+ return str;
+}
+
var Stream = (function() {
function constructor(arrayBuffer, start, length, dict) {
this.bytes = Uint8Array(arrayBuffer);
var pos = this.pos;
var end = pos + length;
var strEnd = this.end;
- if (end > strEnd)
+ if (!end || end > strEnd)
end = strEnd;
-
+
this.pos = end;
return bytes.subarray(pos, end);
},
]), 5];
function constructor(stream) {
- this.stream = stream;
+ var bytes = stream.getBytes();
+ var bytesPos = 0;
+
this.dict = stream.dict;
- var cmf = stream.getByte();
- var flg = stream.getByte();
+ var cmf = bytes[bytesPos++];
+ var flg = bytes[bytesPos++];
if (cmf == -1 || flg == -1)
error("Invalid header in flate stream");
if ((cmf & 0x0f) != 0x08)
error("Bad FCHECK in flate stream");
if (flg & 0x20)
error("FDICT bit set in flate stream");
+
+ this.bytes = bytes;
+ this.bytesPos = bytesPos;
this.eof = false;
this.codeSize = 0;
this.codeBuf = 0;
constructor.prototype = {
getBits: function(bits) {
- var stream = this.stream;
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
+ var bytes = this.bytes;
+ var bytesPos = this.bytesPos;
+
var b;
while (codeSize < bits) {
- if ((b = stream.getByte()) == -1)
+ if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad encoding in flate stream");
codeBuf |= b << codeSize;
codeSize += 8;
b = codeBuf & ((1 << bits) - 1);
this.codeBuf = codeBuf >> bits;
this.codeSize = codeSize -= bits;
+ this.bytesPos = bytesPos;
return b;
},
getCode: function(table) {
var maxLen = table[1];
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
- var stream = this.stream;
+ var bytes = this.bytes;
+ var bytesPos = this.bytesPos;
+
while (codeSize < maxLen) {
var b;
- if ((b = stream.getByte()) == -1)
+ if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad encoding in flate stream");
codeBuf |= (b << codeSize);
codeSize += 8;
error("Bad encoding in flate stream");
this.codeBuf = (codeBuf >> codeLen);
this.codeSize = (codeSize - codeLen);
+ this.bytesPos = bytesPos;
return codeVal;
},
ensureBuffer: function(requested) {
return this.buffer = buffer2;
},
getByte: function() {
- var bufferLength = this.bufferLength;
var pos = this.pos;
- if (bufferLength <= pos) {
+ while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
return this.buffer.subarray(pos, end)
},
lookChar: function() {
- var bufferLength = this.bufferLength;
var pos = this.pos;
- if (bufferLength <= pos) {
+ while (this.bufferLength <= pos) {
if (this.eof)
return;
this.readBlock();
},
getChar: function() {
var ch = this.lookChar();
- if (!ch)
- return;
+ // 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;
- while (n-- > 0)
- this.getChar();
+ this.pos += n;
},
generateHuffmanTable: function(lengths) {
var n = lengths.length;
array[i++] = what;
}
- var stream = this.stream;
+ var bytes = this.bytes;
+ var bytesPos = this.bytesPos;
// read block header
var hdr = this.getBits(3);
var b;
if (hdr == 0) { // uncompressed block
- if ((b = stream.getByte()) == -1)
+ if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
var blockLen = b;
- if ((b = stream.getByte()) == -1)
+ if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
blockLen |= (b << 8);
- if ((b = stream.getByte()) == -1)
+ if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
var check = b;
- if ((b = stream.getByte()) == -1)
+ if (typeof (b = bytes[bytesPos++]) == "undefined")
error("Bad block header in flate stream");
check |= (b << 8);
if (check != (~this.blockLen & 0xffff))
var buffer = this.ensureBuffer(bufferLength + blockLen);
this.bufferLength = bufferLength + blockLen;
for (var n = bufferLength; n < blockLen; ++n) {
- if ((b = stream.getByte()) == -1) {
+ if (typeof (b = bytes[bytesPos++]) == "undefined") {
this.eof = true;
break;
}
return constructor;
})();
+// A JpegStream can't be read directly. We use the platform to render the underlying
+// JPEG data for us.
+var JpegStream = (function() {
+ function constructor(bytes, dict) {
+ // TODO: per poppler, some images may have "junk" before that need to be removed
+ this.dict = dict;
+
+ // create DOM image
+ var img = new Image();
+ img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes));
+ this.domImage = img;
+ }
+
+ constructor.prototype = {
+ getImage: function() {
+ return this.domImage;
+ }
+ };
+
+ return constructor;
+})();
+
var PredictorStream = (function() {
function constructor(stream, params) {
this.stream = stream;
+ this.dict = stream.dict;
this.predictor = params.get("Predictor") || 1;
if (this.predictor <= 1) {
return stream; // no prediction
this.encAlgorithm,
this.keyLength);
}
- stream = this.filter(stream, dict);
+ stream = this.filter(stream, dict, length);
stream.parameters = dict;
return stream;
},
- filter: function(stream, dict) {
+ filter: function(stream, dict, length) {
var filter = dict.get2("Filter", "F");
var params = dict.get2("DecodeParms", "DP");
if (IsName(filter))
- return this.makeFilter(stream, filter.name, params);
+ return this.makeFilter(stream, filter.name, length, params);
if (IsArray(filter)) {
var filterArray = filter;
var paramsArray = params;
params = null;
if (IsArray(paramsArray) && (i in paramsArray))
params = paramsArray[i];
- stream = this.makeFilter(stream, filter.name, params);
+ stream = this.makeFilter(stream, filter.name, length, params);
}
}
}
return stream;
},
- makeFilter: function(stream, name, params) {
+ makeFilter: function(stream, name, length, params) {
if (name == "FlateDecode" || name == "Fl") {
if (params) {
return new PredictorStream(new FlateStream(stream), params);
}
return new FlateStream(stream);
+ } else if (name == "DCTDecode") {
+ var bytes = stream.getBytes(length);
+ return new JpegStream(bytes, stream.dict);
} else {
error("filter '" + name + "' not supported yet");
}
var fontName = "";
var fontDescriptor = font.get("FontDescriptor");
- if (fontDescriptor.num) {
+ if (fontDescriptor && fontDescriptor.num) {
var fontDescriptor = this.xref.fetchIfRef(fontDescriptor);
fontName = fontDescriptor.get("FontName").name.replace("+", "_");
Fonts.active = fontName;
}
+ if (!fontName) {
+ // TODO: fontDescriptor is not available, fallback to default font
+ this.current.fontSize = size;
+ this.ctx.font = this.current.fontSize + 'px sans-serif';
+ return;
+ }
+
this.current.fontSize = size;
this.ctx.font = this.current.fontSize +'px "' + fontName + '", Symbol';
},
},
showText: function(text) {
this.ctx.save();
- this.ctx.translate(0, 2 * this.current.y);
- this.ctx.scale(1, -1);
this.ctx.transform.apply(this.ctx, this.current.textMatrix);
+ this.ctx.scale(1, -1);
+ this.ctx.translate(0, -2 * this.current.y);
this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y);
this.current.x += this.ctx.measureText(text).width;
if (w < 1 || h < 1)
error("Invalid image width or height");
-
+
var ctx = this.ctx;
// scale the image to the unit square
- ctx.scale(1/w, 1/h);
+ ctx.scale(1/w, -1/h);
+
+ // If the platform can render the image format directly, the
+ // stream has a getImage property which directly returns a
+ // suitable DOM Image object.
+ if (image.getImage) {
+ var domImage = image.getImage();
+ ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
+ 0, -h, w, h);
+ this.restore();
+ return;
+ }
var interpolate = dict.get2("Interpolate", "I");
if (!IsBool(interpolate))
switch (numComps) {
case 1:
for (var i = 0; i < length; i += 4) {
- var p = imgArray[imageIdx++];
+ var p = imgArray[imgIdx++];
pixels[i] = p;
pixels[i+1] = p;
pixels[i+2] = p;
switch (numComps) {
case 1:
for (var i = 0; i < length; i += 4) {
- var p = imgArray[imageIdx++];
+ var p = imgArray[imgIdx++];
pixels[i] = p;
pixels[i+1] = p;
pixels[i+2] = p;
}
}
tmpCtx.putImageData(imgData, 0, 0);
- ctx.drawImage(tmpCanvas, 0, 0);
+ ctx.drawImage(tmpCanvas, 0, -h);
this.restore();
},