diff --git a/src/canvas.js b/src/canvas.js index 995899cf0..fdb537372 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -985,9 +985,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { var height = canvas.height; var bl = Util.applyTransform([0, 0], inv); - var br = Util.applyTransform([0, width], inv); - var ul = Util.applyTransform([height, 0], inv); - var ur = Util.applyTransform([height, width], inv); + var br = Util.applyTransform([0, height], inv); + var ul = Util.applyTransform([width, 0], inv); + var ur = Util.applyTransform([width, height], inv); var x0 = Math.min(bl[0], br[0], ul[0], ur[0]); var y0 = Math.min(bl[1], br[1], ul[1], ur[1]); @@ -1037,8 +1037,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { }, paintJpegXObject: function canvasGraphicsPaintJpegXObject(objId, w, h) { - var image = this.objs.get(objId); - if (!image) { + var domImage = this.objs.get(objId); + if (!domImage) { error('Dependent image isn\'t ready yet'); } @@ -1048,7 +1048,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { // scale the image to the unit square ctx.scale(1 / w, -1 / h); - var domImage = image.getImage(); ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, 0, -h, w, h); diff --git a/src/core.js b/src/core.js index 5cefaac68..412ce1a97 100644 --- a/src/core.js +++ b/src/core.js @@ -562,8 +562,8 @@ var PDFDoc = (function PDFDocClosure() { switch (type) { case 'JpegStream': - var IR = data[2]; - new JpegImageLoader(id, IR, this.objs); + var imageData = data[2]; + loadJpegStream(id, imageData, this.objs); break; case 'Font': var name = data[2]; diff --git a/src/fonts.js b/src/fonts.js index a80cd15f7..fcec676cb 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -884,6 +884,13 @@ var Font = (function FontClosure() { String.fromCharCode(value & 0xff); }; + function safeString16(value) { + // clamp value to the 16-bit int range + value = value > 0x7FFF ? 0x7FFF : value < -0x8000 ? -0x8000 : value; + return String.fromCharCode((value >> 8) & 0xff) + + String.fromCharCode(value & 0xff); + }; + function string32(value) { return String.fromCharCode((value >> 24) & 0xff) + String.fromCharCode((value >> 16) & 0xff) + @@ -1778,6 +1785,12 @@ var Font = (function FontClosure() { } properties.hasShortCmap = hasShortCmap; + // remove glyph references outside range of avaialable glyphs + for (var i = 0, ii = ids.length; i < ii; i++) { + if (ids[i] >= numGlyphs) + ids[i] = 0; + } + createGlyphNameMap(glyphs, ids, properties); this.glyphNameMap = properties.glyphNameMap; @@ -1903,9 +1916,9 @@ var Font = (function FontClosure() { '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date '\x00\x00' + // xMin - string16(properties.descent) + // yMin + safeString16(properties.descent) + // yMin '\x0F\xFF' + // xMax - string16(properties.ascent) + // yMax + safeString16(properties.ascent) + // yMax string16(properties.italicAngle ? 2 : 0) + // macStyle '\x00\x11' + // lowestRecPPEM '\x00\x00' + // fontDirectionHint @@ -1917,15 +1930,15 @@ var Font = (function FontClosure() { 'hhea': (function fontFieldsHhea() { return stringToArray( '\x00\x01\x00\x00' + // Version number - string16(properties.ascent) + // Typographic Ascent - string16(properties.descent) + // Typographic Descent + safeString16(properties.ascent) + // Typographic Ascent + safeString16(properties.descent) + // Typographic Descent '\x00\x00' + // Line Gap '\xFF\xFF' + // advanceWidthMax '\x00\x00' + // minLeftSidebearing '\x00\x00' + // minRightSidebearing '\x00\x00' + // xMaxExtent - string16(properties.capHeight) + // caretSlopeRise - string16(Math.tan(properties.italicAngle) * + safeString16(properties.capHeight) + // caretSlopeRise + safeString16(Math.tan(properties.italicAngle) * properties.xHeight) + // caretSlopeRun '\x00\x00' + // caretOffset '\x00\x00' + // -reserved- @@ -2095,9 +2108,9 @@ var Font = (function FontClosure() { break; case 'Type1': var glyphName = this.differences[charcode] || this.encoding[charcode]; + if (!isNum(width)) + width = this.widths[glyphName]; if (this.noUnicodeAdaptation) { - if (!isNum(width)) - width = this.widths[glyphName]; unicode = GlyphsUnicode[glyphName] || charcode; break; } @@ -2142,7 +2155,8 @@ var Font = (function FontClosure() { break; } - var unicodeChars = this.toUnicode ? this.toUnicode[charcode] : charcode; + var unicodeChars = !('toUnicode' in this) ? charcode : + this.toUnicode[charcode] || charcode; if (typeof unicodeChars === 'number') unicodeChars = String.fromCharCode(unicodeChars); diff --git a/src/image.js b/src/image.js index 0688d07ef..15c31b034 100644 --- a/src/image.js +++ b/src/image.js @@ -130,11 +130,11 @@ var PDFImage = (function PDFImageClosure() { var buf = new Uint8Array(width * height); if (smask) { - if (smask.image.getImage) { + if (smask.image.src) { // smask is a DOM image var tempCanvas = new ScratchCanvas(width, height); var tempCtx = tempCanvas.getContext('2d'); - var domImage = smask.image.getImage(); + var domImage = smask.image; tempCtx.drawImage(domImage, 0, 0, domImage.width, domImage.height, 0, 0, width, height); var data = tempCtx.getImageData(0, 0, width, height).data; @@ -229,29 +229,11 @@ var PDFImage = (function PDFImageClosure() { return PDFImage; })(); -var JpegImageLoader = (function JpegImageLoaderClosure() { - function JpegImageLoader(objId, imageData, objs) { - var src = 'data:image/jpeg;base64,' + window.btoa(imageData); - - var img = new Image(); - img.onload = (function onloadClosure() { - this.loaded = true; - - objs.resolve(objId, this); - - if (this.onLoad) - this.onLoad(); - }).bind(this); - img.src = src; - this.domImage = img; - } - - JpegImageLoader.prototype = { - getImage: function jpegImageLoaderGetImage() { - return this.domImage; - } - }; - - return JpegImageLoader; -})(); +function loadJpegStream(id, imageData, objs) { + var img = new Image(); + img.onload = (function jpegImageLoaderOnload() { + objs.resolve(id, img); + }); + img.src = 'data:image/jpeg;base64,' + window.btoa(imageData); +} diff --git a/src/obj.js b/src/obj.js index b78964a63..2f7488a76 100644 --- a/src/obj.js +++ b/src/obj.js @@ -598,7 +598,7 @@ var XRef = (function XRefClosure() { e = parser.getObj(); } // Don't cache streams since they are mutable (except images). - if (!isStream(e) || e.getImage) + if (!isStream(e) || e instanceof JpegStream) this.cache[num] = e; return e; } diff --git a/src/pattern.js b/src/pattern.js index bf68253b3..dbe2e5c23 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -183,7 +183,11 @@ Shadings.Dummy = (function DummyClosure() { })(); var TilingPattern = (function TilingPatternClosure() { - var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; + var PaintType = { + COLORED: 1, + UNCOLORED: 2 + }; + var MAX_PATTERN_SIZE = 512; function TilingPattern(IR, color, ctx, objs) { var IRQueue = IR[2]; @@ -209,13 +213,13 @@ var TilingPattern = (function TilingPatternClosure() { var width = botRight[0] - topLeft[0]; var height = botRight[1] - topLeft[1]; - // TODO: hack to avoid OOM, we would idealy compute the tiling + // TODO: hack to avoid OOM, we would ideally compute the tiling // pattern to be only as large as the acual size in device space // This could be computed with .mozCurrentTransform, but still // needs to be implemented - while (Math.abs(width) > 512 || Math.abs(height) > 512) { - width = 512; - height = 512; + while (Math.abs(width) > MAX_PATTERN_SIZE || + Math.abs(height) > MAX_PATTERN_SIZE) { + width = height = MAX_PATTERN_SIZE; } var tmpCanvas = new ScratchCanvas(width, height); @@ -225,11 +229,11 @@ var TilingPattern = (function TilingPatternClosure() { var graphics = new CanvasGraphics(tmpCtx, objs); switch (paintType) { - case PAINT_TYPE_COLORED: + case PaintType.COLORED: tmpCtx.fillStyle = ctx.fillStyle; tmpCtx.strokeStyle = ctx.strokeStyle; break; - case PAINT_TYPE_UNCOLORED: + case PaintType.UNCOLORED: color = Util.makeCssRgb.apply(this, color); tmpCtx.fillStyle = color; tmpCtx.strokeStyle = color; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 325987de6..7a36acd58 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -17,3 +17,4 @@ !devicen.pdf !cmykjpeg.pdf !issue840.pdf +!freeculture.pdf diff --git a/test/pdfs/bpl13210.pdf.link b/test/pdfs/bpl13210.pdf.link new file mode 100644 index 000000000..7cde56a22 --- /dev/null +++ b/test/pdfs/bpl13210.pdf.link @@ -0,0 +1 @@ +http://h20000.www2.hp.com/bc/docs/support/SupportManual/bpl13210/bpl13210.pdf diff --git a/test/pdfs/freeculture.pdf b/test/pdfs/freeculture.pdf new file mode 100644 index 000000000..8b27e9355 Binary files /dev/null and b/test/pdfs/freeculture.pdf differ diff --git a/test/pdfs/geothermal.pdf.link b/test/pdfs/geothermal.pdf.link new file mode 100644 index 000000000..6a255647f --- /dev/null +++ b/test/pdfs/geothermal.pdf.link @@ -0,0 +1 @@ +http://geothermal.inel.gov/publications/future_of_geothermal_energy.pdf diff --git a/test/test_manifest.json b/test/test_manifest.json index 05c627242..ab8a618c0 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -87,6 +87,13 @@ "rounds": 1, "type": "eq" }, + { "id": "freeculture", + "file": "pdfs/freeculture.pdf", + "md5": "dcdf3a8268e6a18938a42d5149efcfca", + "rounds": 1, + "pageLimit": 5, + "type": "eq" + }, { "id": "wnv_chinese-pdf", "file": "pdfs/wnv_chinese.pdf", "md5": "db682638e68391125e8982d3c984841e", @@ -296,11 +303,28 @@ "rounds": 1, "type": "eq" }, + { "id": "bpl13210", + "file": "pdfs/bpl13210.pdf", + "md5": "8a08512baa9fa95378d9ad4b995947c7", + "link": true, + "pageLimit": 5, + "rounds": 1, + "type": "eq" + }, { "id": "tutorial", "file": "pdfs/tutorial.pdf", "md5": "6e122f618c27f3aa9a689423e3be6b8d", "link": true, "rounds": 1, "type": "eq" + }, + { "id": "geothermal.pdf", + "file": "pdfs/geothermal.pdf", + "md5": "ecffc0ce38ffdf1e90dc952f186e9a91", + "rounds": 1, + "link": true, + "pageLimit": 5, + "skipPages": [1], + "type": "eq" } ]