From 19fa6a5260444d5da0f5888357f70a4215fe6d95 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 28 Aug 2012 17:19:31 -0700 Subject: [PATCH 1/7] Adds support for color key mask. --- src/image.js | 64 ++++++++++++++++++++++++++----------- test/pdfs/colorkeymask.pdf | Bin 0 -> 161533 bytes test/test_manifest.json | 6 ++++ 3 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 test/pdfs/colorkeymask.pdf diff --git a/src/image.js b/src/image.js index 59f70f99a..907607ebe 100644 --- a/src/image.js +++ b/src/image.js @@ -97,7 +97,12 @@ var PDFImage = (function PDFImageClosure() { if (smask) { this.smask = new PDFImage(xref, res, smask, false); } else if (mask) { - this.mask = new PDFImage(xref, res, mask, false); + if (isStream(mask)) { + this.mask = new PDFImage(xref, res, mask, false); + } else { + // Color key mask (just an array). + this.mask = mask; + } } } /** @@ -129,11 +134,15 @@ var PDFImage = (function PDFImageClosure() { maskPromise.resolve(null); } else { smaskPromise.resolve(null); - if (mask && isStream(mask)) { - handleImageData(handler, xref, res, mask, maskPromise); - } else if (mask) { - TODO('handle color key masking'); - maskPromise.resolve(null); + if (mask) { + if (isStream(mask)) { + handleImageData(handler, xref, res, mask, maskPromise); + } else if (isArray(mask)) { + maskPromise.resolve(mask); + } else { + warn('Unsupported mask format.'); + maskPromise.resolve(null); + } } else { maskPromise.resolve(null); } @@ -279,7 +288,7 @@ var PDFImage = (function PDFImageClosure() { } return output; }, - getOpacity: function PDFImage_getOpacity(width, height) { + getOpacity: function PDFImage_getOpacity(width, height, image) { var smask = this.smask; var mask = this.mask; var originalWidth = this.width; @@ -294,18 +303,37 @@ var PDFImage = (function PDFImageClosure() { if (sw != width || sh != height) buf = PDFImage.resize(buf, smask.bpc, 1, sw, sh, width, height); } else if (mask) { - var sw = mask.width; - var sh = mask.height; - buf = new Uint8Array(sw * sh); - mask.numComps = 1; - mask.fillGrayBuffer(buf); + if (mask instanceof PDFImage) { + var sw = mask.width; + var sh = mask.height; + buf = new Uint8Array(sw * sh); + mask.numComps = 1; + mask.fillGrayBuffer(buf); - // Need to invert values in buffer - for (var i = 0, ii = sw * sh; i < ii; ++i) - buf[i] = 255 - buf[i]; + // Need to invert values in buffer + for (var i = 0, ii = sw * sh; i < ii; ++i) + buf[i] = 255 - buf[i]; - if (sw != width || sh != height) - buf = PDFImage.resize(buf, mask.bpc, 1, sw, sh, width, height); + if (sw != width || sh != height) + buf = PDFImage.resize(buf, mask.bpc, 1, sw, sh, width, height); + } else if (isArray(mask)) { + // Color key mask: if any of the compontents are outside the range + // then they should be painted. + buf = new Uint8Array(width * height); + for (var i = 0, ii = width * height; i < ii; ++i) { + var opacity = 0; + for (var j = 0; j < this.numComps; ++j) { + var color = image[i * this.numComps + j]; + if (color < mask[j * 2] || color > mask[j * 2 + 1]) { + opacity = 255; + break; + } + } + buf[i] = opacity; + } + } else { + error('Unknown mask format.'); + } } else { buf = new Uint8Array(width * height); for (var i = 0, ii = width * height; i < ii; ++i) @@ -357,7 +385,7 @@ var PDFImage = (function PDFImageClosure() { comps = PDFImage.resize(comps, this.bpc, 3, originalWidth, originalHeight, width, height); var compsPos = 0; - var opacity = this.getOpacity(width, height); + var opacity = this.getOpacity(width, height, imgArray); var opacityPos = 0; var length = width * actualHeight * 4; diff --git a/test/pdfs/colorkeymask.pdf b/test/pdfs/colorkeymask.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a056d9cbc63587ec39f82705b9cf4040e719cef4 GIT binary patch literal 161533 zcmeH`-EJJm5rus{Pcb(F>uDK38kK|n;=ijg>`MFDYO2f>OQQ7cQk)b22l@{+m8 z8zc{s%xp_E9o0qmX%q?vIdOiJ)>QB5^L=&i?D5xM&h`$Pd;j|PKmOUw+G)Ff{;F*r zJZL7rUtVt8ANPl&r+;ZC&)#2m?c{86)oq)}>H22Xx3lKq!=_tZ?k2|XZbzSN);HJb zmeccg^0@ok@}hhCct2h@{KD|(;qLKgo5{D`<#O?8 z{jU9SIvmVT=6m}`^ZCiFJwBN29Uq?@9UctXo_5>y&E}%pw)fN6_2rBH=f93&|9JCe z$ayFI7=G0cKe25Ob|2q)!#I8WhOgfBPtN;A-=%jfrs;n#7UO-VzfG@CiTl3WtkPd! z&)fOOYwz4Vp55Mjw%85q8XfNX^LgK0x3iP!yqP?@ee3>o+U_47{pxi)EI)kr{8e|+ zr=NRw)E?gXxycWA?)rAoZV_fFTZ z*PHX}#l;}(9rey{p7%S6zj-r=(M&$XnjKDu=MAbYwm%QL&*$yBIf&FT8h^?Ef*e0=A@|M~1Qx_|Q}9xA2`jjMrA z#x+HWh%z*82Rw4C`v?>p)-LPpBYE;%A*u{C9mXF z^%i(k=zVAPqa!wlGBi#SpNxQ$(o!O#42|1?Ps*#J?&MXRFqxnz5mAQD1Y&$<9LXz> zQskAql2_GR;8CIXoz;(y*c{5xI7xgm0!~UxiHI^ZZU;UouZp^pS8>8*f}%u389Eb) z@tJWXuRKbTSMo|;Rd0buh2D2oKRRM_C`02U@yQ4{DJ>-;%FwtS_@ull>P}w836lwm z5)ozSOd!T*#*w`8C`De$D|uDD1s)Z8-&y_Wh|Qr4jg!PDBjBX8l!z!p<96Va@~Wsi zc@-y2CMZfol%X?$7@rwO^2(zWc_pvpRrMBlROo$Y^`j#;hcYxy5}%BKlhRTmq704O zfltb-qVD8XoG_W7C=pSH&IDq7W*o^Yk5c57ypmVdTi{Wl_np;`j@TT^&^SqaG6GIY zONodwG;RkzDX)sUlUH%VWP+kZL>W30i1C?mB(FS5kyr9cUR7^_M}^*ZRzEsob0|aO zB=N}zI4Lb9BFfOX9r&cYD(X&N#R-!MiV_iJ=u9BSXU37d@+d`K$t!tPy#*c>df!?7 z=!ngs42_e-CnMmbw3LV_L*sVflk%#lJ9!l+OeQEwM3kX3ff%0|NAk*}6nQ1Dw4C`v?>p)-LPpBYE;%A*u{C9mXF^%i(k z=zVAPqa!wlGBi#SpNxQ$(o!O#42|1?Ps*#J?&MXRFqxnz5mAQD1Y&$<9LXz>QskAq zl2_GR;8CIXoz;(y*c{5xI7xgm0!~UxiHI^ZZU;UouZp^pS8>8*f}%u389Eb)@tJWX zuRKbTSMo|;Rd0buh2D2oKRRM_C`02U@yQ4{DJ>-;%FwtS_@ull>P}w836lwm5)ozS zOd!T*#*w`8C`De$D|uDD1s)Z8-&y_Wh|Qr4jg!PDBjBX8l!z!p<96Va@~Wsic@-y2 zCMZfol%X?$7@rwO^2(zWc_pvpRrMBlROo$Y^`j#;hcYxy5}%BKlhRTmq704Ofltb- zqVD8XoG_W7C=pSH&IDq7W*o^Yk5c57ypmVdTi{Wl_np;`j@TT^&^SqaG6GIYONodw zG;RkzDX)sUlUH%VWP+kZL>W30i1C?mB(FS5kyr9cUR7^_M}^*ZRzEsob0|aOB=N}z zI4Lb9BFfOX9r&cYD(X&N#R-!MiV_iJ=u9BSXU37d@+d`K$t!tPy#*c>df!?7=!ngs z42_e-CnMmbw3LV_L*sVflk%#lJ9!l+OeQEwM3kX3ff%0|NAk*}6nQ1Dw4C`v?>p)-LPpBYE;%A*u{C9mXF^%i(k=zVAP zqa!wlGBi#SpNxQ$(o!O#42|1?Ps*#J?&MXRFqxnz5mAQD1Y&$<9LXz>QskAql2_GR z;8CIXoz;(y*c{5xI7xgm0!~UxiHI^ZZU;UouZp^pS8>8*f}%u389Eb)@tJWXuRKbT zSMo|;Rd0buh2D2oKRRM_C`02U@yQ4{DJ>-;%FwtS_@ull>P}w836lwm5)ozSOd!T* z#*w`8C`De$D|uDD1s)Z8-&y_Wh|Qr4jg!PDBjBX8l!z!p<96Va@~Wsic@-y2CMZfo zl%X?$7@rwO^2(zWc_pvpRrMBlROo$Y^`j#;hcYxy5}%BKlhRTmq704Ofltb-qVD8X zoG_W7C=pSH&IDq7W*o^Yk5c57ypmVdTi{Wl_np;`j@TT^&^SqaG6GIYONodwG;Rkz zDX)sUlUH%VWP+kZL>W30i1C?mB(FS5kyr9cUR7^_M}^*ZRzEsob0|aOB=N}zI4Lb9 zBFfOX9r&cYD(X&N#R-!MiV_iJ=u9BSXU37d@+d`K$t!tPy#*c>df!?7=!ngs42_e- zCnMmbw3LV_L*sVflk%#lJ9!l+OeQEwM3kX3ff%0|NAk*}6nQ1DBpqZR4uDWeI8;+hflV|U*yLNKA=ohcoSIxtRw`(tlQb% z@!o9O{`C3FzQ6v>WU@QG+AOYLE-$uw>&?|qUwkqA&SrgibJ3Me{gU9_rhCy$+mmK` z`>*zJKEFS2U$nPpvw6Gw+jjNK+0nr#XZuIfPtFdfpPt=6{PgT-w*Twd+2L$@@;|>Z zoXrmIWa&4H Date: Wed, 29 Aug 2012 09:57:41 -0500 Subject: [PATCH 2/7] Fixes 1810 reftest address --- test/pdfs/issue1810.pdf.link | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pdfs/issue1810.pdf.link b/test/pdfs/issue1810.pdf.link index b8689c298..8c84c7505 100644 --- a/test/pdfs/issue1810.pdf.link +++ b/test/pdfs/issue1810.pdf.link @@ -1 +1 @@ -http://www.freepatentsonline.com/pdf/documents/uspt/D661/USD661296/USD661296S1.pdf +http://assets.sbnation.com/assets/1167519/USD661296S1.pdf From 4550ffe14ed1e75d3209d0398f445521b0f8b4b0 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 29 Aug 2012 10:31:59 -0500 Subject: [PATCH 3/7] Fixes fonts on linux --- src/fonts.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/fonts.js b/src/fonts.js index 4aef0962a..97fb63be2 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -2938,6 +2938,7 @@ var Font = (function FontClosure() { } this.toFontChar = toFontChar; } + var unitsPerEm = properties.unitsPerEm || 1000; // defaulting to 1000 var fields = { // PostScript Font Program @@ -2958,7 +2959,7 @@ var Font = (function FontClosure() { '\x00\x00\x00\x00' + // checksumAdjustement '\x5F\x0F\x3C\xF5' + // magicNumber '\x00\x00' + // Flags - '\x03\xE8' + // unitsPerEM (defaulting to 1000) + safeString16(unitsPerEm) + // unitsPerEM '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date '\x00\x00' + // xMin @@ -4413,6 +4414,12 @@ var CFFParser = (function CFFParserClosure() { var charStringOffset = topDict.getByName('CharStrings'); cff.charStrings = this.parseCharStrings(charStringOffset); + var fontMatrix = topDict.getByName('FontMatrix'); + if (fontMatrix) { + // estimating unitsPerEM for the font + properties.unitsPerEm = 1 / fontMatrix[0]; + } + var charset, encoding; if (cff.isCIDFont) { var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj; From d26ecff294999df4bf94ae8c8a1524849914d8bf Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 29 Aug 2012 09:36:12 -0700 Subject: [PATCH 4/7] Reduce math for color key mask. --- src/image.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/image.js b/src/image.js index 907607ebe..19c66ade2 100644 --- a/src/image.js +++ b/src/image.js @@ -320,11 +320,14 @@ var PDFImage = (function PDFImageClosure() { // Color key mask: if any of the compontents are outside the range // then they should be painted. buf = new Uint8Array(width * height); + var numComps = this.numComps; for (var i = 0, ii = width * height; i < ii; ++i) { var opacity = 0; - for (var j = 0; j < this.numComps; ++j) { - var color = image[i * this.numComps + j]; - if (color < mask[j * 2] || color > mask[j * 2 + 1]) { + var imageOffset = i * numComps; + for (var j = 0; j < numComps; ++j) { + var color = image[imageOffset + j]; + var maskOffset = j * 2; + if (color < mask[maskOffset] || color > mask[maskOffset + 1]) { opacity = 255; break; } From 93f9efde390a9811482480cb740ba660a8217419 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 29 Aug 2012 12:19:09 -0500 Subject: [PATCH 5/7] Fixes ascent and descent values for windows gdi --- src/fonts.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/fonts.js b/src/fonts.js index 97fb63be2..0b6a58aba 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -4420,6 +4420,13 @@ var CFFParser = (function CFFParserClosure() { properties.unitsPerEm = 1 / fontMatrix[0]; } + var fontBBox = topDict.getByName('FontBBox'); + if (fontBBox) { + // adjusting ascent/descent + properties.ascent = fontBBox[3]; + properties.descent = fontBBox[1]; + } + var charset, encoding; if (cff.isCIDFont) { var fdArrayIndex = this.parseIndex(topDict.getByName('FDArray')).obj; From e32ecc44d38c2bcba70e6955beca37042a0c07b4 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 29 Aug 2012 12:58:12 -0500 Subject: [PATCH 6/7] Fixes CFF test and CFF int16 parsing --- src/fonts.js | 2 +- test/unit/font_spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fonts.js b/src/fonts.js index 0b6a58aba..1b20e771d 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -4500,7 +4500,7 @@ var CFFParser = (function CFFParserClosure() { return parseFloatOperand(pos); } else if (value === 28) { value = dict[pos++]; - value = (value << 8) | dict[pos++]; + value = ((value << 24) | (dict[pos++] << 16)) >> 16; return value; } else if (value === 29) { value = dict[pos++]; diff --git a/test/unit/font_spec.js b/test/unit/font_spec.js index 9f0969324..b2436778d 100644 --- a/test/unit/font_spec.js +++ b/test/unit/font_spec.js @@ -42,7 +42,7 @@ describe('font', function() { } describe('CFFParser', function() { - var parser = new CFFParser(fontData); + var parser = new CFFParser(fontData, {}); var cff = parser.parse(); it('parses header', function() { From 621686ca672a0b6001d51384d821c72dead20e4e Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 29 Aug 2012 16:11:56 -0500 Subject: [PATCH 7/7] Fixes incorrect font type and prevents future this.objs.objs[fonts[i]] failures --- src/api.js | 17 ++++++++++++++--- src/fonts.js | 22 +++++++++++++++++++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/api.js b/src/api.js index 4e7ce4e76..6c862a91b 100644 --- a/src/api.js +++ b/src/api.js @@ -311,13 +311,19 @@ var PDFPageProxy = (function PDFPageProxyClosure() { ensureFonts: function PDFPageProxy_ensureFonts(fonts, callback) { this.stats.time('Font Loading'); // Convert the font names to the corresponding font obj. + var fontObjs = []; for (var i = 0, ii = fonts.length; i < ii; i++) { - fonts[i] = this.objs.objs[fonts[i]].data; + var obj = this.objs.objs[fonts[i]].data; + if (obj.error) { + warn('Error during font loading: ' + obj.error); + continue; + } + fontObjs.push(obj); } // Load all the fonts FontLoader.bind( - fonts, + fontObjs, function pageEnsureFontsFontObjs(fontObjs) { this.stats.timeEnd('Font Loading'); @@ -565,7 +571,12 @@ var WorkerTransport = (function WorkerTransportClosure() { // At this point, only the font object is created but the font is // not yet attached to the DOM. This is done in `FontLoader.bind`. - var font = new Font(name, file, properties); + var font; + try { + font = new Font(name, file, properties); + } catch (e) { + font = new ErrorFont(e); + } this.objs.resolve(id, font); break; default: diff --git a/src/fonts.js b/src/fonts.js index 4aef0962a..5f5c98264 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -1577,13 +1577,19 @@ var Font = (function FontClosure() { return; } + // Some fonts might use wrong font types for Type1C or CIDFontType0C + var subtype = properties.subtype; + if (subtype == 'Type1C' && (type != 'Type1' && type != 'MMType1')) + type = 'Type1'; + if (subtype == 'CIDFontType0C' && type != 'CIDFontType0') + type = 'CIDFontType0'; + var data; switch (type) { case 'Type1': case 'CIDFontType0': this.mimetype = 'font/opentype'; - var subtype = properties.subtype; var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ? new CFFFont(file, properties) : new Type1Font(name, file, properties); @@ -3309,6 +3315,20 @@ var Font = (function FontClosure() { return Font; })(); +var ErrorFont = (function ErrorFontClosure() { + function ErrorFont(error) { + this.error = error; + } + + ErrorFont.prototype = { + charsToGlyphs: function ErrorFont_charsToGlyphs() { + return []; + } + }; + + return ErrorFont; +})(); + var CallothersubrCmd = (function CallothersubrCmdClosure() { function CallothersubrCmd(index) { this.index = index;