From f48ab3cfd1fd81eaed522adae5023173f1a76902 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 24 Aug 2011 17:18:56 +0200 Subject: [PATCH 01/10] Support lsb div format --- fonts.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 9049255e7..9dc739796 100755 --- a/fonts.js +++ b/fonts.js @@ -1485,14 +1485,18 @@ var Type1Parser = function() { // TODO Clean this code if (value == 13) { if (charstring.length == 2) { + lsb = charstring[0]; width = charstring[1]; } else if (charstring.length == 4 && charstring[3] == 'div') { + lsb = charstring[0]; width = charstring[1] / charstring[2]; + } else if (charstring.length == 4 && charstring[2] == 'div') { + lsb = charstring[0] / charstring[1]; + width = charstring[3]; } else { error('Unsupported hsbw format: ' + charstring); } - lsb = charstring[0]; charstring.push(lsb, 'hmoveto'); charstring.splice(0, 1); continue; From 6460ffcd253f9bf441a1317d7ddcdcffb80b5df0 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Wed, 24 Aug 2011 17:26:14 +0200 Subject: [PATCH 02/10] Remove div arguments once used for lsb --- fonts.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fonts.js b/fonts.js index 9dc739796..9b306ff0e 100755 --- a/fonts.js +++ b/fonts.js @@ -1486,19 +1486,21 @@ var Type1Parser = function() { if (value == 13) { if (charstring.length == 2) { lsb = charstring[0]; + charstring.splice(0, 1); width = charstring[1]; } else if (charstring.length == 4 && charstring[3] == 'div') { lsb = charstring[0]; + charstring.splice(0, 1); width = charstring[1] / charstring[2]; } else if (charstring.length == 4 && charstring[2] == 'div') { lsb = charstring[0] / charstring[1]; + charstring.splice(0, 3); width = charstring[3]; } else { error('Unsupported hsbw format: ' + charstring); } charstring.push(lsb, 'hmoveto'); - charstring.splice(0, 1); continue; } command = charStringDictionary[value]; From ff40fc4b45296aca2905fd9652020a0896fee54a Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Wed, 24 Aug 2011 18:45:14 -0500 Subject: [PATCH 03/10] Fixing encryption key size for the algorithm 1 --- crypto.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto.js b/crypto.js index 652f53b2c..4aaca9520 100644 --- a/crypto.js +++ b/crypto.js @@ -543,7 +543,7 @@ var CipherTransformFactory = (function() { key[i++] = 0x54; } var hash = md5(key, 0, i); - return hash.subarray(0, Math.min(key.length, 16)); + return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); } function buildCipherConstructor(cf, name, num, gen, key) { From b170f8a2f2d3801361a5bbae6f05f53b852c7c9b Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Wed, 24 Aug 2011 19:08:23 -0500 Subject: [PATCH 04/10] Fix shavian.pdf regression and related optimization --- pdf.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 41445533c..d470ef067 100644 --- a/pdf.js +++ b/pdf.js @@ -208,6 +208,11 @@ var DecodeStream = (function() { this.readBlock(); var end = this.bufferLength; + + // checking if bufferLength is still 0 then + // the buffer has to be initialized + if (!end) + this.buffer = new Uint8Array(0); } this.pos = end; @@ -3340,11 +3345,11 @@ var Page = (function() { var xref = this.xref; var content = xref.fetchIfRef(this.content); var resources = xref.fetchIfRef(this.resources); - if (IsArray(this.content)) { + if (IsArray(content)) { // fetching items var i, n = content.length; for (i = 0; i < n; ++i) - content[i] = xref.fetchIfRef(this.content[i]); + content[i] = xref.fetchIfRef(content[i]); content = new StreamsSequenceStream(content); } this.code = gfx.compile(content, xref, resources, fonts, images); From 3f16be334eb6dd904b77fff0343d4e2c1bd091e4 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 25 Aug 2011 02:29:22 +0200 Subject: [PATCH 05/10] Add built-in encoding for Type1 if there is no encoding built yet (fix some missing chars in pypy.pdf page 7) --- fonts.js | 69 +++++++++++++++++++++++++++++++++++++------------------- pdf.js | 8 +++++-- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/fonts.js b/fonts.js index 9b306ff0e..e7055b96a 100755 --- a/fonts.js +++ b/fonts.js @@ -1284,8 +1284,6 @@ var Font = (function Font() { var charcode = chars.charCodeAt(i); var unicode = encoding[charcode]; if ('undefined' == typeof(unicode)) { - // FIXME/issue 233: we're hitting this in test/pdf/sizes.pdf - // at the moment, for unknown reasons. warn('Unencoded charcode ' + charcode); unicode = charcode; } @@ -1590,13 +1588,12 @@ var Type1Parser = function() { while (i < count && (eexecStr[i] == ' ' || eexecStr[i] == '\n')) ++i; - var t = ''; + var token = ''; while (i < count && !(eexecStr[i] == ' ' || eexecStr[i] == '\n')) - t += eexecStr[i++]; - - return t; - } + token += eexecStr[i++]; + return token; + }; var c = eexecStr[i]; if ((glyphsSection || subrsSection) && c == 'R') { @@ -1680,18 +1677,28 @@ var Type1Parser = function() { return program; }, - this.extractFontHeader = function t1_extractFontProgram(stream) { + this.extractFontHeader = function t1_extractFontHeader(stream, properties) { var headerString = ''; for (var i = 0; i < stream.length; i++) headerString += String.fromCharCode(stream[i]); - var info = { - textMatrix: null - }; - var token = ''; var count = headerString.length; for (var i = 0; i < count; i++) { + var getToken = function() { + var char = headerString[i]; + while (i < count && (char == ' ' || char == '\n' || char == '/')) + char = headerString[++i]; + + var token = ''; + while (i < count && !(char == ' ' || char == '\n' || char == '/')) { + token += char; + char = headerString[++i]; + } + + return token; + }; + var c = headerString[i]; if (c == ' ' || c == '\n') { switch (token) { @@ -1705,7 +1712,25 @@ var Type1Parser = function() { // Make the angle into the right direction matrix[2] *= -1; - info.textMatrix = matrix; + properties.textMatrix = matrix; + break; + case '/Encoding': + if (!properties.builtInEncoding) + break; + + var size = parseInt(getToken()); + getToken(); // read in 'array' + + for (var j = 0; j < size; j++) { + var token = getToken(); + if (token == 'dup') { + var index = parseInt(getToken()); + var glyph = getToken(); + properties.encoding[index] = GlyphsUnicode[glyph]; + getToken(); // read the in 'put' + j = index; + } + } break; } token = ''; @@ -1713,8 +1738,6 @@ var Type1Parser = function() { token += c; } } - - return info; }; }; @@ -1798,13 +1821,11 @@ var CFF = function(name, file, properties) { var length2 = file.dict.get('Length2'); var headerBlock = file.getBytes(length1); - var header = type1Parser.extractFontHeader(headerBlock); - for (var info in header) - properties[info] = header[info]; + type1Parser.extractFontHeader(headerBlock, properties); // Decrypt the data blocks and retrieve it's content var eexecBlock = file.getBytes(length2); - var data = type1Parser.extractFontProgram(eexecBlock); + var data = type1Parser.extractFontProgram(eexecBlock, properties); for (var info in data.properties) properties[info] = data.properties[info]; @@ -1874,15 +1895,14 @@ CFF.prototype = { getOrderedCharStrings: function cff_getOrderedCharStrings(glyphs) { var charstrings = []; + var missings = []; for (var i = 0; i < glyphs.length; i++) { var glyph = glyphs[i]; var unicode = GlyphsUnicode[glyph.glyph]; if (!unicode) { - if (glyph.glyph != '.notdef') { - warn(glyph.glyph + - ' does not have an entry in the glyphs unicode dictionary'); - } + if (glyph.glyph != '.notdef') + missings.push(glyph.glyph); } else { charstrings.push({ glyph: glyph, @@ -1894,6 +1914,9 @@ CFF.prototype = { } } + if (missings.length) + warn(missings + ' does not have unicode in the glyphs dictionary'); + charstrings.sort(function charstrings_sort(a, b) { return a.unicode - b.unicode; }); diff --git a/pdf.js b/pdf.js index 4408bc49e..138d4bbf4 100644 --- a/pdf.js +++ b/pdf.js @@ -4191,6 +4191,7 @@ var PartialEvaluator = (function() { fd = fontDict.get('FontDescriptor'); } + var builtInEncoding = false; var encodingMap = {}; var glyphMap = {}; var charset = []; @@ -4261,9 +4262,11 @@ var PartialEvaluator = (function() { if (!baseEncoding) { var type = subType.name; if (type == 'TrueType') { - baseEncoding = Encodings.WinAnsiEncoding.slice(0); + baseEncoding = Encodings.WinAnsiEncoding.slice(); } else if (type == 'Type1') { - baseEncoding = Encodings.StandardEncoding.slice(0); + baseEncoding = Encodings.StandardEncoding.slice(); + if (!diffEncoding.length) + builtInEncoding = true; } else { error('Unknown type of font'); } @@ -4419,6 +4422,7 @@ var PartialEvaluator = (function() { subtype: fileType, widths: glyphWidths, encoding: encodingMap, + builtInEncoding: builtInEncoding, charset: charset, firstChar: fontDict.get('FirstChar'), lastChar: fontDict.get('LastChar'), From 528e89693b15154913f2fb0d2df9da7b8ce052d6 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 25 Aug 2011 02:38:19 +0200 Subject: [PATCH 06/10] Fix regression #372 --- pdf.js | 1 + 1 file changed, 1 insertion(+) diff --git a/pdf.js b/pdf.js index 138d4bbf4..abfd1dcc1 100644 --- a/pdf.js +++ b/pdf.js @@ -4288,6 +4288,7 @@ var PartialEvaluator = (function() { } if (fontDict.has('ToUnicode')) { + encodingMap['empty'] = true; var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); if (IsName(cmapObj)) { error('ToUnicode file cmap translation not implemented'); From 93437352d08eb937e2134796ab7ecc79ea3873c8 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Thu, 25 Aug 2011 02:56:03 +0200 Subject: [PATCH 07/10] Move splice() after the width assigment --- fonts.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fonts.js b/fonts.js index e7055b96a..b81f4a2ed 100755 --- a/fonts.js +++ b/fonts.js @@ -1484,16 +1484,16 @@ var Type1Parser = function() { if (value == 13) { if (charstring.length == 2) { lsb = charstring[0]; - charstring.splice(0, 1); width = charstring[1]; + charstring.splice(0, 1); } else if (charstring.length == 4 && charstring[3] == 'div') { lsb = charstring[0]; - charstring.splice(0, 1); width = charstring[1] / charstring[2]; + charstring.splice(0, 1); } else if (charstring.length == 4 && charstring[2] == 'div') { lsb = charstring[0] / charstring[1]; - charstring.splice(0, 3); width = charstring[3]; + charstring.splice(0, 3); } else { error('Unsupported hsbw format: ' + charstring); } From dacd239ed20865f18da915af1bb196979b10df3e Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Wed, 24 Aug 2011 21:40:17 -0500 Subject: [PATCH 08/10] Add patterns to ImageMask; fix for non-multiple-8 width --- pdf.js | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/pdf.js b/pdf.js index e1fce54ce..ab3b37684 100644 --- a/pdf.js +++ b/pdf.js @@ -5112,15 +5112,18 @@ var CanvasGraphics = (function() { var tmpCanvas = new this.ScratchCanvas(w, h); var tmpCtx = tmpCanvas.getContext('2d'); + if (imageObj.imageMask) { + var fillColor = this.current.fillColor; + tmpCtx.fillStyle = (fillColor && fillColor.type === 'Pattern') ? + fillColor.getPattern(ctx) : fillColor; + tmpCtx.fillRect(0, 0, w, h); + } var imgData = tmpCtx.getImageData(0, 0, w, h); var pixels = imgData.data; if (imageObj.imageMask) { - var inverseDecode = imageObj.decode && imageObj.decode[0] > 0; - // TODO fillColor pattern support - var fillColor = this.current.fillColor; - imageObj.fillUsingStencilMask(pixels, fillColor, - inverseDecode); + var inverseDecode = !!imageObj.decode && imageObj.decode[0] > 0; + imageObj.applyStencilMask(pixels, inverseDecode); } else imageObj.fillRgbaBuffer(pixels); @@ -6000,26 +6003,27 @@ var PDFImage = (function() { } return buf; }, - fillUsingStencilMask: function fillUsingStencilMask(buffer, - cssRgb, inverseDecode) { - var m = /rgb\((\d+),(\d+),(\d+)\)/.exec(cssRgb); // parse CSS color - var r = m[1] | 0, g = m[2] | 0, b = m[3] | 0; - var bufferLength = this.width * this.height; - var imgArray = this.image.getBytes((bufferLength + 7) >> 3); - var i, mask; - var bufferPos = 0, imgArrayPos = 0; - for (i = 0; i < bufferLength; i++) { - var buf = imgArray[imgArrayPos++]; - for (mask = 128; mask > 0; mask >>= 1) { - if (!(buf & mask) != inverseDecode) { - buffer[bufferPos++] = r; - buffer[bufferPos++] = g; - buffer[bufferPos++] = b; - buffer[bufferPos++] = 255; - } else { - buffer[bufferPos + 3] = 0; - bufferPos += 4; + applyStencilMask: function fillUsingStencilMask(buffer, + inverseDecode) { + var width = this.width, height = this.height; + var bitStrideLength = (width + 7) >> 3; + var imgArray = this.image.getBytes(bitStrideLength * height); + var imgArrayPos = 0; + var i, j, mask, buf; + // removing making non-masked pixels transparent + var bufferPos = 3; // alpha component offset + for (i = 0; i < height; i++) { + mask = 0; + for (j = 0; j < width; j++) { + if (!mask) { + buf = imgArray[imgArrayPos++]; + mask = 128; } + if (!(buf & mask) == inverseDecode) { + buffer[bufferPos] = 0; + } + bufferPos += 4; + mask >>= 1; } } }, From 824d6e4e71b1d6e20b5701c286c756aa1720f27c Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Wed, 24 Aug 2011 22:02:44 -0500 Subject: [PATCH 09/10] using tmpCtx instead of ctx --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index ab3b37684..9739128f9 100644 --- a/pdf.js +++ b/pdf.js @@ -5115,7 +5115,7 @@ var CanvasGraphics = (function() { if (imageObj.imageMask) { var fillColor = this.current.fillColor; tmpCtx.fillStyle = (fillColor && fillColor.type === 'Pattern') ? - fillColor.getPattern(ctx) : fillColor; + fillColor.getPattern(tmpCtx) : fillColor; tmpCtx.fillRect(0, 0, w, h); } var imgData = tmpCtx.getImageData(0, 0, w, h); From f90144d38fff0b80838a2604156e77be26e8ddad Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Wed, 24 Aug 2011 22:57:44 -0500 Subject: [PATCH 10/10] Changing function name --- pdf.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 9739128f9..e4ef1b63e 100644 --- a/pdf.js +++ b/pdf.js @@ -6003,8 +6003,7 @@ var PDFImage = (function() { } return buf; }, - applyStencilMask: function fillUsingStencilMask(buffer, - inverseDecode) { + applyStencilMask: function applyStencilMask(buffer, inverseDecode) { var width = this.width, height = this.height; var bitStrideLength = (width + 7) >> 3; var imgArray = this.image.getBytes(bitStrideLength * height);