From 3aa6e38f01c37851d8815d5d5710532699a2a038 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 21 Aug 2011 21:05:10 -0500 Subject: [PATCH 01/13] Switching to the document outline view if the document structure is present --- pdf.js | 39 +++-- web/images/nav-outline.svg | 202 ++++++++++++++++++++++++++ web/images/nav-thumbs.svg | 283 +++++++++++++++++++++++++++++++++++++ web/viewer.css | 76 +++++++++- web/viewer.html | 11 ++ web/viewer.js | 63 +++++++++ 6 files changed, 657 insertions(+), 17 deletions(-) create mode 100644 web/images/nav-outline.svg create mode 100644 web/images/nav-thumbs.svg diff --git a/pdf.js b/pdf.js index 0ff3381f5..0d44822dd 100644 --- a/pdf.js +++ b/pdf.js @@ -3395,6 +3395,9 @@ var Page = (function() { TODO('other link types'); break; } + } else if (annotation.has('Dest')) { + // simple destination link + link.dest = annotation.get('Dest').name; } links.push(link); } @@ -3449,11 +3452,12 @@ var Catalog = (function() { var outlineDict = this.xref.fetch(i.obj); if (!outlineDict.has('Title')) error('Invalid outline item'); - var dest = outlineDict.get('Dest'); - if (!dest && outlineDict.get('A')) { - var a = this.xref.fetchIfRef(outlineDict.get('A')); - dest = a.get('D'); - } + var dest = outlineDict.get('A'); + if (dest) + dest = this.xref.fetchIfRef(dest).get('D'); + else if (outlineDict.has('Dest')) + dest = outlineDict.get('Dest').name; + var outlineItem = { dest: dest, title: convertIfUnicode(outlineDict.get('Title')), @@ -3477,7 +3481,8 @@ var Catalog = (function() { } } } - return shadow(this, 'documentOutline', root); + obj = root.items.length > 0 ? root.items : null; + return shadow(this, 'documentOutline', obj); }, get numPages() { var obj = this.toplevelPagesDict.get('Count'); @@ -3511,15 +3516,25 @@ var Catalog = (function() { }, get destinations() { var xref = this.xref; + var dests = {}, nameTreeRef, nameDictionaryRef; var obj = this.catDict.get('Names'); - obj = obj ? xref.fetch(obj) : this.catDict; - obj = obj.get('Dests'); - var dests = {}; - if (obj) { + if (obj) + nameTreeRef = xref.fetch(obj).get('Dests'); + else if(this.catDict.has('Dests')) + nameDictionaryRef = this.catDict.get('Dests'); + + if (nameDictionaryRef) { + // reding simple destination dictionary + obj = xref.fetch(nameDictionaryRef); + obj.forEach(function(key, value) { + dests[key] = xref.fetch(value).get('D'); + }); + } + if (nameTreeRef) { // reading name tree var processed = new RefSet(); - processed.put(obj); - var queue = [obj]; + processed.put(nameTreeRef); + var queue = [nameTreeRef]; while (queue.length > 0) { var i, n; obj = xref.fetch(queue.shift()); diff --git a/web/images/nav-outline.svg b/web/images/nav-outline.svg new file mode 100644 index 000000000..4d4323ce3 --- /dev/null +++ b/web/images/nav-outline.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/images/nav-thumbs.svg b/web/images/nav-thumbs.svg new file mode 100644 index 000000000..8737b8cb6 --- /dev/null +++ b/web/images/nav-thumbs.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/viewer.css b/web/viewer.css index 54f648adb..e18d9681e 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -60,10 +60,10 @@ span#info { /* === Sidebar === */ #sidebar { position: fixed; - width: 200px; + width: 350px; top: 62px; bottom: 18px; - left: -140px; + left: -290px; transition: left 0.25s ease-in-out 1s; -moz-transition: left 0.25s ease-in-out 1s; -webkit-transition: left 0.25s ease-in-out 1s; @@ -78,7 +78,7 @@ span#info { #sidebarBox { background-color: rgba(0, 0, 0, 0.7); - width: 150px; + width: 300px; height: 100%; border-top-right-radius: 8px; border-bottom-right-radius: 8px; @@ -98,14 +98,73 @@ span#info { top: 10px; bottom: 10px; left: 10px; - width: 130px; + width: 280px; } .thumbnail { width: 104px; height: 134px; background-color: white; - margin: 5px; + margin-top: 5px; + margin-bottom: 5px; + margin-left:auto; + margin-right:auto; +} + +#outlineScrollView { + position: absolute; + background-color: #fff; + overflow: auto; + top: 10px; + bottom: 10px; + left: 10px; + width: 280px; +} + +#outlineView { + padding-top: 4px; + padding-bottom: 100px; + padding-left: 6px; + padding-right: 6px; + font-size: smaller; +} + +.outlineItem > .outlineItems { + margin-left: 20px; +} + +.outlineItem > a { + text-decoration: none; + color: black; +} + +.outlineItem > a:hover { + background: #ff0; + box-shadow: 0px 2px 10px #ff0; +} + +#sidebarControls { + position:absolute; + width: 120px; + height: 32px; + left: 15px; + bottom: 35px; +} + +#sidebarControls > button { + box-shadow: 0px 4px 10px #000; + -moz-box-shadow: 0px 4px 10px #000; + -webkit-box-shadow: 0px 4px 10px #000; +} + +#sidebarControls > button[disabled] > img { + opacity: 0.5; +} + +#sidebarControls > button[data-selected] { + box-shadow: 0px 4px 10px #ff0; + -moz-box-shadow: 0px 4px 10px #ff0; + -webkit-box-shadow: 0px 4px 10px #ff0; } /* === Content view === */ @@ -128,3 +187,10 @@ canvas { padding: 8px 0px; } +#sidebarView canvas:hover { + background: #ff0; + box-shadow: 0px 2px 10px #ff0; + -moz-box-shadow: 0px 2px 10px #ff0; + -webkit-box-shadow: 0px 2px 10px #ff0; +} + diff --git a/web/viewer.html b/web/viewer.html index 285dadb01..6232ce4b3 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -56,6 +56,17 @@
+ +
+ + +
diff --git a/web/viewer.js b/web/viewer.js index 8fe011b29..95a32128c 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -128,6 +128,33 @@ var PDFView = { this.page = parseInt(document.location.hash.substring(1)) || 1; this.pagesRefMap = pagesRefMap; this.destinations = pdf.catalog.destinations; + if (pdf.catalog.documentOutline) { + this.outline = new DocumentOutlineView(pdf.catalog.documentOutline); + var outlineSwitchButton = document.getElementById('outlineSwitch'); + outlineSwitchButton.removeAttribute('disabled'); + this.switchSidebarView('outline'); + } + }, + + switchSidebarView: function(view) { + var thumbsScrollView = document.getElementById('sidebarScrollView'); + var outlineScrollView = document.getElementById('outlineScrollView'); + var thumbsSwitchButton = document.getElementById('thumbsSwitch'); + var outlineSwitchButton = document.getElementById('outlineSwitch'); + switch(view) { + case 'thumbs': + thumbsScrollView.style.display = 'block'; + outlineScrollView.style.display = 'none'; + thumbsSwitchButton.setAttribute('data-selected', true); + outlineSwitchButton.removeAttribute('data-selected'); + break; + case 'outline': + thumbsScrollView.style.display = 'none'; + outlineScrollView.style.display = 'block'; + thumbsSwitchButton.removeAttribute('data-selected'); + outlineSwitchButton.setAttribute('data-selected', true); + break; + } }, getVisiblePages: function() { @@ -289,6 +316,42 @@ var ThumbnailView = function(container, page) { }; }; +var DocumentOutlineView = function(outline) { + var outlineView = document.getElementById('outlineView'); + + function bindItemLink(domObj, item) { + domObj.href = ''; + domObj.onclick = function(e) { + PDFView.navigateTo(item.dest); + return false; + }; + } + + var queue = [{parent: outlineView, items: outline}]; + while (queue.length > 0) { + var levelData = queue.shift(); + var i, n = levelData.items.length; + for (i = 0; i < n; i++) { + var item = levelData.items[i]; + var div = document.createElement('div'); + div.className = 'outlineItem'; + var a = document.createElement('a'); + bindItemLink(a, item); + a.textContent = item.title; + div.appendChild(a); + + if (item.items.length > 0) { + var itemsDiv = document.createElement('div'); + itemsDiv.className = 'outlineItems'; + div.appendChild(itemsDiv); + queue.push({parent: itemsDiv, items: item.items}); + } + + levelData.parent.appendChild(div); + } + } +}; + window.addEventListener('load', function(evt) { var params = document.location.search.substring(1).split('&'); for (var i = 0; i < params.length; i++) { From 94eac2466e3002e78e512169a4a51197c14d0c4c Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 21 Aug 2011 21:16:17 -0500 Subject: [PATCH 02/13] Document outline item link (for an-open-web) --- pdf.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pdf.js b/pdf.js index 0d44822dd..185db1f5d 100644 --- a/pdf.js +++ b/pdf.js @@ -3455,8 +3455,11 @@ var Catalog = (function() { var dest = outlineDict.get('A'); if (dest) dest = this.xref.fetchIfRef(dest).get('D'); - else if (outlineDict.has('Dest')) - dest = outlineDict.get('Dest').name; + else if (outlineDict.has('Dest')) { + dest = outlineDict.get('Dest'); + if (IsName(dest)) + dest = dest.name; + } var outlineItem = { dest: dest, From d664652b866cb544b7ef95443d07b6cd261c5732 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Mon, 22 Aug 2011 18:55:49 -0500 Subject: [PATCH 03/13] Lifting up this.xref; buttons tooltips --- pdf.js | 7 ++++--- web/viewer.html | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index 185db1f5d..c43a9d61c 100644 --- a/pdf.js +++ b/pdf.js @@ -3438,9 +3438,10 @@ var Catalog = (function() { return str; } var obj = this.catDict.get('Outlines'); + var xref = this.xref; var root = { items: [] }; if (IsRef(obj)) { - obj = this.xref.fetch(obj).get('First'); + obj = xref.fetch(obj).get('First'); var processed = new RefSet(); if (IsRef(obj)) { var queue = [{obj: obj, parent: root}]; @@ -3449,12 +3450,12 @@ var Catalog = (function() { processed.put(obj); while (queue.length > 0) { var i = queue.shift(); - var outlineDict = this.xref.fetch(i.obj); + var outlineDict = xref.fetch(i.obj); if (!outlineDict.has('Title')) error('Invalid outline item'); var dest = outlineDict.get('A'); if (dest) - dest = this.xref.fetchIfRef(dest).get('D'); + dest = xref.fetchIfRef(dest).get('D'); else if (outlineDict.has('Dest')) { dest = outlineDict.get('Dest'); if (IsName(dest)) diff --git a/web/viewer.html b/web/viewer.html index 6232ce4b3..2766412e0 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -60,11 +60,11 @@
- -
From d58dac0fd384a803d41b92928706446bdbaae53c Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Mon, 22 Aug 2011 22:50:17 -0500 Subject: [PATCH 04/13] Encoding for standard fonts; symbols encoding --- fonts.js | 3 -- pdf.js | 109 ++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/fonts.js b/fonts.js index 3d47ef4a2..9049255e7 100755 --- a/fonts.js +++ b/fonts.js @@ -404,9 +404,6 @@ var Font = (function Font() { (fontName.indexOf('Italic') != -1); this.loadedName = fontName.split('-')[0]; this.loading = false; - this.charsToUnicode = function(s) { - return s; - }; return; } diff --git a/pdf.js b/pdf.js index 469eec578..53d3b9853 100644 --- a/pdf.js +++ b/pdf.js @@ -3851,6 +3851,44 @@ var Encodings = { 'ucircumflex', 'udieresis', 'yacute', 'thorn', 'ydieresis' ]); }, + get symbolsEncoding() { + return shadow(this, 'symbolsEncoding', + [,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, + 'space', 'exclam', 'universal', 'numbersign', 'existential', 'percent', + 'ampersand', 'suchthat', 'parenleft', 'parenright', 'asteriskmath', + 'plus', 'comma', 'minus', 'period', 'slash', 'zero', 'one', 'two', + 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', + 'semicolon', 'less', 'equal', 'greater', 'question', 'congruent', + 'Alpha', 'Beta', 'Chi', 'Delta', 'Epsilon', 'Phi', 'Gamma', 'Eta', + 'Iota', 'theta1', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Omicron', 'Pi', + 'Theta', 'Rho', 'Sigma', 'Tau', 'Upsilon', 'sigma1', 'Omega', 'Xi', + 'Psi', 'Zeta', 'bracketleft', 'therefore', 'bracketright', + 'perpendicular', 'underscore', 'radicalex', 'alpha', 'beta', 'chi', + 'delta', 'epsilon', 'phi', 'gamma', 'eta', 'iota', 'phi1', 'kappa', + 'lambda', 'mu', 'nu', 'omicron', 'pi', 'theta', 'rho', 'sigma', 'tau', + 'upsilon', 'omega1', 'omega', 'xi', 'psi', 'zeta', 'braceleft', 'bar', + 'braceright', 'similar',,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 'Euro', + 'Upsilon1', 'minute', 'lessequal', 'fraction', 'infinity', 'florin', + 'club', 'diamond', 'heart', 'spade', 'arrowboth', 'arrowleft', 'arrowup', + 'arrowright', 'arrowdown', 'degree', 'plusminus', 'second', + 'greaterequal', 'multiply', 'proportional', 'partialdiff', 'bullet', + 'divide', 'notequal', 'equivalence', 'approxequal', 'ellipsis', + 'arrowvertex', 'arrowhorizex', 'carriagereturn', 'aleph', 'Ifraktur', + 'Rfraktur', 'weierstrass', 'circlemultiply', 'circleplus', 'emptyset', + 'intersection', 'union', 'propersuperset', 'reflexsuperset', 'notsubset', + 'propersubset', 'reflexsubset', 'element', 'notelement', 'angle', + 'gradient', 'registerserif', 'copyrightserif', 'trademarkserif', + 'product', 'radical', 'dotmath', 'logicalnot', 'logicaland', 'logicalor', + 'arrowdblboth', 'arrowdblleft', 'arrowdblup', 'arrowdblright', + 'arrowdbldown', 'lozenge', 'angleleft', 'registersans', 'copyrightsans', + 'trademarksans', 'summation', 'parenlefttp', 'parenleftex', + 'parenleftbt', 'bracketlefttp', 'bracketleftex', 'bracketleftbt', + 'bracelefttp', 'braceleftmid', 'braceleftbt', 'braceex', ,'angleright', + 'integral', 'integraltp', 'integralex', 'integralbt', 'parenrighttp', + 'parenrightex', 'parenrightbt', 'bracketrighttp', 'bracketrightex', + 'bracketrightbt', 'bracerighttp', 'bracerightmid', 'bracerightbt' + ]); + }, get zapfDingbatsEncoding() { return shadow(this, 'zapfDingbatsEncoding', [,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, @@ -4118,24 +4156,6 @@ var PartialEvaluator = (function() { fd = fontDict.get('FontDescriptor'); } - if (!fd) { - var baseFontName = fontDict.get('BaseFont'); - if (!IsName(baseFontName)) - return null; - // Using base font name as a font name. - return { - name: baseFontName.name.replace(/[\+,\-]/g, '_'), - fontDict: fontDict, - properties: {} - }; - } - - var descriptor = xref.fetch(fd); - - var fontName = xref.fetchIfRef(descriptor.get('FontName')); - assertWellFormed(IsName(fontName), 'invalid font name'); - fontName = fontName.name.replace(/[\+,\-]/g, '_'); - var encodingMap = {}; var charset = []; if (compositeFont) { @@ -4200,14 +4220,6 @@ var PartialEvaluator = (function() { GlyphsUnicode[data.name]; } } - - // Get the font charset if any - var charset = descriptor.get('CharSet'); - if (charset) { - assertWellFormed(IsString(charset), 'invalid charset'); - charset = charset.split('/'); - charset.shift(); - } } else if (IsName(encoding)) { var encoding = Encodings[encoding.name]; if (!encoding) @@ -4217,11 +4229,10 @@ var PartialEvaluator = (function() { for (var j = 0; j < encoding.length; j++) encodingMap[index++] = GlyphsUnicode[encoding[j]]; + // firstChar and width are required + // (except for 14 standard fonts) var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); - var widths = xref.fetchIfRef(fontDict.get('Widths')); - assertWellFormed(IsArray(widths) && IsInt(firstChar), - 'invalid font Widths or FirstChar'); - + var widths = xref.fetchIfRef(fontDict.get('Widths')) || []; for (var j = 0; j < widths.length; j++) { if (widths[j]) charset.push(encoding[j + firstChar]); @@ -4296,6 +4307,36 @@ var PartialEvaluator = (function() { } } + if (!fd) { + var baseFontName = fontDict.get('BaseFont'); + if (!IsName(baseFontName)) + return null; + // Using base font name as a font name. + baseFontName = baseFontName.name.replace(/[\+,\-]/g, '_'); + if (baseFontName == 'Symbol') { + // special case for symbols + var encoding = Encodings.symbolsEncoding; + for (var i = 0, n = encoding.length, j; i < n; i++) { + if (!(j = encoding[i])) + continue; + encodingMap[i] = GlyphsUnicode[j] || 0; + } + } + return { + name: baseFontName, + fontDict: fontDict, + properties: { + encoding: encodingMap + } + }; + } + + var descriptor = xref.fetch(fd); + + var fontName = xref.fetchIfRef(descriptor.get('FontName')); + assertWellFormed(IsName(fontName), 'invalid font name'); + fontName = fontName.name.replace(/[\+,\-]/g, '_'); + var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3'); if (fontFile) { fontFile = xref.fetchIfRef(fontFile); @@ -4307,6 +4348,14 @@ var PartialEvaluator = (function() { } } + if (descriptor.has('CharSet')) { + // Get the font charset if any (meaningful only in Type 1) + charset = descriptor.get('CharSet'); + assertWellFormed(IsString(charset), 'invalid charset'); + charset = charset.split('/'); + charset.shift(); + } + var widths = fontDict.get('Widths'); if (widths) { var glyphWidths = {}; From 35cc5f9965838474c47f94d787a85915e2bead67 Mon Sep 17 00:00:00 2001 From: mohansun Date: Tue, 23 Aug 2011 21:46:11 -0300 Subject: [PATCH 05/13] fix for the issue:https://github.com/andreasgal/pdf.js/issues/360 --- web/viewer.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index f0ecd4667..698b8974d 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -27,9 +27,12 @@ var PDFView = { var cssUnits = 96.0 / 72.0; for (var i = 0; i < pages.length; i++) pages[i].update(val / 100 * cssUnits); - - // Jump the scroll position to the correct page. - document.location.hash = this.page; + + if(document.location.hash == '#' + this.page) + this.pages[this.page-1].draw(); + else + // Jump the scroll position to the correct page. + document.location.hash = this.page; var event = document.createEvent("UIEvents"); event.initUIEvent("scalechange", false, false, window, val); From 1babe72c382722c1c2081129d7e4e9ed9410984e Mon Sep 17 00:00:00 2001 From: mohansun Date: Tue, 23 Aug 2011 22:00:12 -0300 Subject: [PATCH 06/13] Fix for few html tag errors (as reported by Safari 5.0.6) --- web/viewer.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/viewer.html b/web/viewer.html index e740c2bc0..0e779c60c 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -2,7 +2,7 @@ Simple pdf.js page viewer - + @@ -26,7 +26,7 @@
- + / -- @@ -38,7 +38,7 @@ - + @@ -51,7 +51,7 @@
- +
From 36d9462016a83d3c968e99269f699a6bbe3e2e0e Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Tue, 23 Aug 2011 16:58:41 -0500 Subject: [PATCH 07/13] comment fix --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index c43a9d61c..962f76398 100644 --- a/pdf.js +++ b/pdf.js @@ -3528,7 +3528,7 @@ var Catalog = (function() { nameDictionaryRef = this.catDict.get('Dests'); if (nameDictionaryRef) { - // reding simple destination dictionary + // reading simple destination dictionary obj = xref.fetch(nameDictionaryRef); obj.forEach(function(key, value) { dests[key] = xref.fetch(value).get('D'); From b90c6945b81db9de81f0a55f25b0bd75d01f770b Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Tue, 23 Aug 2011 17:06:45 -0500 Subject: [PATCH 08/13] Sanitizing base font name before comparison with 'Symbol' --- pdf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdf.js b/pdf.js index 53d3b9853..47363401b 100644 --- a/pdf.js +++ b/pdf.js @@ -4313,7 +4313,7 @@ var PartialEvaluator = (function() { return null; // Using base font name as a font name. baseFontName = baseFontName.name.replace(/[\+,\-]/g, '_'); - if (baseFontName == 'Symbol') { + if (/^Symbol(_?(Bold|Italic))*$/.test(baseFontName)) { // special case for symbols var encoding = Encodings.symbolsEncoding; for (var i = 0, n = encoding.length, j; i < n; i++) { From aeba156d6beafc53b1207caab62232e4c5bde39a Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 23 Aug 2011 18:08:47 -0700 Subject: [PATCH 09/13] Redid encoding --- pdf.js | 229 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 123 insertions(+), 106 deletions(-) diff --git a/pdf.js b/pdf.js index 1a0327819..410cb5e3a 100644 --- a/pdf.js +++ b/pdf.js @@ -4213,118 +4213,135 @@ var PartialEvaluator = (function() { '9.7.5.3'); } } - } else if (fontDict.has('Encoding')) { - var encoding = xref.fetchIfRef(fontDict.get('Encoding')); - if (IsDict(encoding)) { - // Build a map of between codes and glyphs - // Load the base encoding - var baseName = encoding.get('BaseEncoding'); - if (baseName) { - var base = Encodings[baseName.name]; - for (var j = 0, end = base.length; j < end; j++) - encodingMap[j] = GlyphsUnicode[base[j]] || 0; - } else { - TODO('need to load default encoding'); - } - - // Load the differences between the base and original - var differences = encoding.get('Differences'); - var index = 0; - for (var j = 0; j < differences.length; j++) { - var data = differences[j]; - if (IsNum(data)) { - index = data; - } else { - encodingMap[index++] = (subType.name == 'TrueType') ? j : - GlyphsUnicode[data.name]; + } else { + var baseEncoding = null, diffEncoding = []; + if (fontDict.has('Encoding')) { + var encoding = xref.fetchIfRef(fontDict.get('Encoding')); + if (IsDict(encoding)) { + // Build a map of between codes and glyphs + // Load the base encoding + var baseName = encoding.get('BaseEncoding'); + if (baseName) { + baseEncoding = Encodings[baseName.name].slice(); } - } - } else if (IsName(encoding)) { - var encoding = Encodings[encoding.name]; - if (!encoding) - error('Unknown font encoding'); - var index = 0; - for (var j = 0; j < encoding.length; j++) - encodingMap[index++] = GlyphsUnicode[encoding[j]]; - - // firstChar and width are required - // (except for 14 standard fonts) - var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); - var widths = xref.fetchIfRef(fontDict.get('Widths')) || []; - for (var j = 0; j < widths.length; j++) { - if (widths[j]) - charset.push(encoding[j + firstChar]); - } - } - } else if (fontDict.has('ToUnicode')) { - encodingMap = {empty: true}; - var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); - if (IsName(cmapObj)) { - error('ToUnicode file cmap translation not implemented'); - } else if (IsStream(cmapObj)) { - var encoding = Encodings['WinAnsiEncoding']; - var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); - - var tokens = []; - var token = ''; - - var cmap = cmapObj.getBytes(cmapObj.length); - for (var i = 0; i < cmap.length; i++) { - var byte = cmap[i]; - if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) { - switch (token) { - case 'useCMap': - error('useCMap is not implemented'); - break; - - case 'beginbfchar': - case 'beginbfrange': - case 'begincodespacerange': - token = ''; - tokens = []; - break; - - case 'endcodespacerange': - TODO('Support CMap ranges'); - break; - - case 'endbfrange': - for (var j = 0; j < tokens.length; j += 3) { - var startRange = parseInt('0x' + tokens[j]); - var endRange = parseInt('0x' + tokens[j + 1]); - var code = parseInt('0x' + tokens[j + 2]); - - for (var k = startRange; k <= endRange; k++) { - charset.push(encoding[code++] || '.notdef'); - } - } - break; - - case 'endbfchar': - for (var j = 0; j < tokens.length; j += 2) { - var index = parseInt('0x' + tokens[j]); - var code = parseInt('0x' + tokens[j + 1]); - encodingMap[index] = GlyphsUnicode[encoding[code]]; - charset.push(encoding[code] || '.notdef'); - } - break; - - default: - if (token.length) { - tokens.push(token); - token = ''; - } - break; + // Load the differences between the base and original + var differences = encoding.get('Differences'); + var index = 0; + for (var j = 0; j < differences.length; j++) { + var data = differences[j]; + if (IsNum(data)) { + index = data; + } else { + diffEncoding[index++] = data.name; + } + } + } else if (IsName(encoding)) { + baseEncoding = Encodings[encoding.name].slice(); + } + } + + if (!baseEncoding) { + var type = subType.name; + if (type == 'TrueType') { + baseEncoding = Encodings.WinAnsiEncoding.slice(0); + } else if (type == 'Type1') { + baseEncoding = Encodings.StandardEncoding.slice(0); + } else { + error('Unknown type of font'); + } + } + + // merge in the differences + var length = baseEncoding.length > diffEncoding.length ? + baseEncoding.length : diffEncoding.length; + for (var i = 0, ii = length; i < ii; ++i) { + var diffGlyph = diffEncoding[i]; + var baseGlyph = baseEncoding[i]; + if (diffGlyph) + encodingMap[i] = GlyphsUnicode[diffGlyph]; + else if (baseGlyph) + encodingMap[i] = GlyphsUnicode[baseGlyph]; + } + + if (fontDict.has('ToUnicode')) { + encodingMap = {empty: true}; + var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); + if (IsName(cmapObj)) { + error('ToUnicode file cmap translation not implemented'); + } else if (IsStream(cmapObj)) { + var encoding = Encodings['WinAnsiEncoding']; + var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); + + var tokens = []; + var token = ''; + + var cmap = cmapObj.getBytes(cmapObj.length); + for (var i = 0; i < cmap.length; i++) { + var byte = cmap[i]; + if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) { + switch (token) { + case 'useCMap': + error('useCMap is not implemented'); + break; + + case 'beginbfchar': + case 'beginbfrange': + case 'begincodespacerange': + token = ''; + tokens = []; + break; + + case 'endcodespacerange': + TODO('Support CMap ranges'); + break; + + case 'endbfrange': + for (var j = 0; j < tokens.length; j += 3) { + var startRange = parseInt('0x' + tokens[j]); + var endRange = parseInt('0x' + tokens[j + 1]); + var code = parseInt('0x' + tokens[j + 2]); + + for (var k = startRange; k <= endRange; k++) { + charset.push(encoding[code++] || '.notdef'); + } + } + break; + + case 'endbfchar': + for (var j = 0; j < tokens.length; j += 2) { + var index = parseInt('0x' + tokens[j]); + var code = parseInt('0x' + tokens[j + 1]); + encodingMap[index] = GlyphsUnicode[encoding[code]]; + charset.push(encoding[code] || '.notdef'); + } + break; + + default: + if (token.length) { + tokens.push(token); + token = ''; + } + break; + } + } else if (byte == 0x5B || byte == 0x5D) { + error('CMAP list parsing is not implemented'); + } else { + token += String.fromCharCode(byte); } - } else if (byte == 0x5B || byte == 0x5D) { - error('CMAP list parsing is not implemented'); - } else { - token += String.fromCharCode(byte); } } } - } + +/* // firstChar and width are required + // (except for 14 standard fonts) + var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); + var widths = xref.fetchIfRef(fontDict.get('Widths')) || []; + for (var j = 0; j < widths.length; j++) { + if (widths[j]) + charset.push(encoding[j + firstChar]); + } +*/ } if (!fd) { var baseFontName = fontDict.get('BaseFont'); From 5499cbc1b0a7d6bcbbf2dbd098c3dbd3e9572981 Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 23 Aug 2011 18:17:30 -0700 Subject: [PATCH 10/13] figuring out charset --- pdf.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pdf.js b/pdf.js index 410cb5e3a..ed28fa4d9 100644 --- a/pdf.js +++ b/pdf.js @@ -4264,7 +4264,7 @@ var PartialEvaluator = (function() { encodingMap[i] = GlyphsUnicode[baseGlyph]; } - if (fontDict.has('ToUnicode')) { + if (fontDict.has('ToUnicode') && false) { encodingMap = {empty: true}; var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); if (IsName(cmapObj)) { @@ -4333,15 +4333,15 @@ var PartialEvaluator = (function() { } } -/* // firstChar and width are required + // firstChar and width are required // (except for 14 standard fonts) var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); var widths = xref.fetchIfRef(fontDict.get('Widths')) || []; for (var j = 0; j < widths.length; j++) { if (widths[j]) - charset.push(encoding[j + firstChar]); + charset.push(encodingMap[j + firstChar]); } -*/ } + } if (!fd) { var baseFontName = fontDict.get('BaseFont'); From 51fa9f579c62c38c0885d6b72111d2570c482feb Mon Sep 17 00:00:00 2001 From: sbarman Date: Tue, 23 Aug 2011 18:33:17 -0700 Subject: [PATCH 11/13] final fix for issue #215 --- pdf.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/pdf.js b/pdf.js index ed28fa4d9..11519c891 100644 --- a/pdf.js +++ b/pdf.js @@ -4176,6 +4176,7 @@ var PartialEvaluator = (function() { } var encodingMap = {}; + var glyphMap = {}; var charset = []; if (compositeFont) { // Special CIDFont support @@ -4258,19 +4259,20 @@ var PartialEvaluator = (function() { for (var i = 0, ii = length; i < ii; ++i) { var diffGlyph = diffEncoding[i]; var baseGlyph = baseEncoding[i]; - if (diffGlyph) + if (diffGlyph) { + glyphMap[i] = diffGlyph; encodingMap[i] = GlyphsUnicode[diffGlyph]; - else if (baseGlyph) + } else if (baseGlyph) { + glyphMap[i] = baseGlyph; encodingMap[i] = GlyphsUnicode[baseGlyph]; + } } - if (fontDict.has('ToUnicode') && false) { - encodingMap = {empty: true}; + if (fontDict.has('ToUnicode')) { var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); if (IsName(cmapObj)) { error('ToUnicode file cmap translation not implemented'); } else if (IsStream(cmapObj)) { - var encoding = Encodings['WinAnsiEncoding']; var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')); var tokens = []; @@ -4279,7 +4281,8 @@ var PartialEvaluator = (function() { var cmap = cmapObj.getBytes(cmapObj.length); for (var i = 0; i < cmap.length; i++) { var byte = cmap[i]; - if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) { + if (byte == 0x20 || byte == 0x0A || byte == 0x3C || + byte == 0x3E) { switch (token) { case 'useCMap': error('useCMap is not implemented'); @@ -4301,10 +4304,6 @@ var PartialEvaluator = (function() { var startRange = parseInt('0x' + tokens[j]); var endRange = parseInt('0x' + tokens[j + 1]); var code = parseInt('0x' + tokens[j + 2]); - - for (var k = startRange; k <= endRange; k++) { - charset.push(encoding[code++] || '.notdef'); - } } break; @@ -4312,8 +4311,7 @@ var PartialEvaluator = (function() { for (var j = 0; j < tokens.length; j += 2) { var index = parseInt('0x' + tokens[j]); var code = parseInt('0x' + tokens[j + 1]); - encodingMap[index] = GlyphsUnicode[encoding[code]]; - charset.push(encoding[code] || '.notdef'); + encodingMap[index] = code; } break; @@ -4339,7 +4337,7 @@ var PartialEvaluator = (function() { var widths = xref.fetchIfRef(fontDict.get('Widths')) || []; for (var j = 0; j < widths.length; j++) { if (widths[j]) - charset.push(encodingMap[j + firstChar]); + charset.push(glyphMap[j + firstChar]); } } From 1046417ec1bfc32f849a0363197b2f369fb695a5 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Tue, 23 Aug 2011 20:52:36 -0500 Subject: [PATCH 12/13] Misc bookmarks/links small fixes : 5180.sfnt.pdf and TCPDF examples --- pdf.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pdf.js b/pdf.js index 1a0327819..ebb9807c6 100644 --- a/pdf.js +++ b/pdf.js @@ -3370,7 +3370,7 @@ var Page = (function() { var links = []; for (i = 0; i < n; ++i) { var annotation = xref.fetch(annotations[i]); - if (!IsDict(annotation, 'Annot')) + if (!IsDict(annotation)) continue; var subtype = annotation.get('Subtype'); if (!IsName(subtype) || subtype.name != 'Link') @@ -3525,7 +3525,7 @@ var Catalog = (function() { var dests = {}, nameTreeRef, nameDictionaryRef; var obj = this.catDict.get('Names'); if (obj) - nameTreeRef = xref.fetch(obj).get('Dests'); + nameTreeRef = xref.fetchIfRef(obj).get('Dests'); else if(this.catDict.has('Dests')) nameDictionaryRef = this.catDict.get('Dests'); @@ -3533,6 +3533,7 @@ var Catalog = (function() { // reading simple destination dictionary obj = xref.fetch(nameDictionaryRef); obj.forEach(function(key, value) { + if (!value) return; dests[key] = xref.fetch(value).get('D'); }); } @@ -3557,7 +3558,8 @@ var Catalog = (function() { } var names = obj.get('Names'); for (i = 0, n = names.length; i < n; i += 2) { - dests[names[i]] = xref.fetch(names[i + 1]).get('D'); + var dest = xref.fetch(names[i + 1]); + dests[names[i]] = IsDict(dest) ? dest.get('D') : dest; } } } From 7e6815ab82fb71ad2018b2061cda0f6c004535f4 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Tue, 23 Aug 2011 21:07:48 -0500 Subject: [PATCH 13/13] Fixing multi-item page content --- pdf.js | 54 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/pdf.js b/pdf.js index 11519c891..41445533c 100644 --- a/pdf.js +++ b/pdf.js @@ -289,6 +289,32 @@ var FakeStream = (function() { return constructor; })(); +var StreamsSequenceStream = (function() { + function constructor(streams) { + this.streams = streams; + DecodeStream.call(this); + } + + constructor.prototype = Object.create(DecodeStream.prototype); + + constructor.prototype.readBlock = function() { + var streams = this.streams; + if (streams.length == 0) { + this.eof = true; + return; + } + var stream = streams.shift(); + var chunk = stream.getBytes(); + var bufferLength = this.bufferLength; + var newLength = bufferLength + chunk.length; + var buffer = this.ensureBuffer(newLength); + buffer.set(chunk, bufferLength); + this.bufferLength = newLength; + }; + + return constructor; +})(); + var FlateStream = (function() { var codeLenCodeMap = new Uint32Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 @@ -3312,28 +3338,16 @@ var Page = (function() { } var xref = this.xref; - var content; + var content = xref.fetchIfRef(this.content); var resources = xref.fetchIfRef(this.resources); - if (!IsArray(this.content)) { - // content is not an array, shortcut - content = xref.fetchIfRef(this.content); - this.code = gfx.compile(content, xref, resources, fonts, images); - return; + if (IsArray(this.content)) { + // fetching items + var i, n = content.length; + for (i = 0; i < n; ++i) + content[i] = xref.fetchIfRef(this.content[i]); + content = new StreamsSequenceStream(content); } - // the content is an array, compiling all items - var i, n = this.content.length, compiledItems = []; - for (i = 0; i < n; ++i) { - content = xref.fetchIfRef(this.content[i]); - compiledItems.push(gfx.compile(content, xref, resources, fonts, - images)); - } - // creating the function that executes all compiled items - this.code = function(gfx) { - var i, n = compiledItems.length; - for (i = 0; i < n; ++i) { - compiledItems[i](gfx); - } - }; + this.code = gfx.compile(content, xref, resources, fonts, images); }, display: function(gfx) { assert(this.code instanceof Function,