diff --git a/README.md b/README.md index c6cf92ede..f5d4eee9d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,32 @@ For an online demo, visit: This demo provides an interactive interface for displaying and browsing PDFs using the pdf.js API. +**Getting the code** + +To get a local copy of the current code, clone it using git: + +```bash + git clone git://github.com/andreasgal/pdf.js.git pdfjs + cd pdfjs +``` + +Next, you need to start a local web server as some browsers don't allow opening +PDF files for a file:// url: + +```bash + make server +``` + +If everything worked out, you can now serve + + http://localhost:8888/web/viewer.html + +You can also view all the test pdf files on the right side serving + + http://localhost:8888/test/pdfs/?frame + + + **Hello world** For a "hello world" example, take a look at: @@ -38,6 +64,20 @@ in a custom project. +## Contributing + +pdf.js is a community-driver project, so contributors are always welcome. +Simply fork our repo and contribute away. A great place to start is our +open issues. For better consistency and long-term stability, please do look around the +code and try to follow our conventions. + +If you __don't want to hack__ on the project or have short spare times, you still +can help! Just open PDFs in the +[online demo](http://andreasgal.github.com/pdf.js/web/viewer.html) and report +any breakage in rendering. + + + ## Running the Tests pdf.js comes with browser-level regression tests that allow one to probe @@ -64,16 +104,6 @@ images. The test type `load` simply tests whether the file loads without raising any errors. -## Contributing - -pdf.js is a community-driver project, so contributors are always welcome. -Simply fork our repo and contribute away. A great place to start is our -open issues. - -For better consistency and long-term stability, please do look around the -code and try to follow our conventions. - - ## Additional resources Our demo site is here: @@ -97,8 +127,28 @@ Join our mailing list: Subscribe either using lists.mozilla.org or Google Groups: https://lists.mozilla.org/listinfo/dev-pdf-js + https://groups.google.com/group/mozilla.dev.pdf-js/topics Talk to us on IRC: #pdfjs on irc.mozilla.org + +## Additional resources to understand the structure of PDF + +A really basic overview of PDF is described here: + + http://partners.adobe.com/public/developer/en/livecycle/lc_pdf_overview_format.pdf + +A more detailed file example: + + http://gnupdf.org/Introduction_to_PDF + +The PDF specification itself is an ISO and not free available. However, there is +a "PDF Reference" from Adobe: + + http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/pdf_reference_1-7.pdf + +Recommanded chapters to read: "2. Overview", "3.4 File Structure", +"4.1 Graphics Objects" that lists the PDF commands. + diff --git a/crypto.js b/crypto.js index 42eeeda51..4eb6bb581 100644 --- a/crypto.js +++ b/crypto.js @@ -45,7 +45,7 @@ var ARCFourCipher = (function aRCFourCipher() { return constructor; })(); -var md5 = (function md5Md5() { +var calculateMD5 = (function calculateMD5() { var r = new Uint8Array([ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, @@ -452,11 +452,11 @@ var CipherTransformFactory = (function cipherTransformFactory() { hashData[i++] = 0xFF; hashData[i++] = 0xFF; } - var hash = md5(hashData, 0, i); + var hash = calculateMD5(hashData, 0, i); var keyLengthInBytes = keyLength >> 3; if (revision >= 3) { for (j = 0; j < 50; ++j) { - hash = md5(hash, 0, keyLengthInBytes); + hash = calculateMD5(hash, 0, keyLengthInBytes); } } var encryptionKey = hash.subarray(0, keyLengthInBytes); @@ -469,7 +469,7 @@ var CipherTransformFactory = (function cipherTransformFactory() { for (j = 0, n = fileId.length; j < n; ++j) hashData[i++] = fileId[j]; cipher = new ARCFourCipher(encryptionKey); - var checkData = cipher.encryptBlock(md5(hashData, 0, i)); + var checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); n = encryptionKey.length; var derrivedKey = new Uint8Array(n), k; for (j = 1; j <= 19; ++j) { @@ -544,7 +544,7 @@ var CipherTransformFactory = (function cipherTransformFactory() { key[i++] = 0x6C; key[i++] = 0x54; } - var hash = md5(key, 0, i); + var hash = calculateMD5(key, 0, i); return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); } diff --git a/pdf.js b/pdf.js index 66e09fdc1..6b6a5272e 100644 --- a/pdf.js +++ b/pdf.js @@ -3324,8 +3324,10 @@ var Page = (function pagePage() { }, get mediaBox() { var obj = this.inheritPageProp('MediaBox'); - return shadow(this, 'mediaBox', - ((IsArray(obj) && obj.length == 4) ? obj : null)); + // Reset invalid media box to letter size. + if (!IsArray(obj) || obj.length !== 4) + obj = [0, 0, 612, 792]; + return shadow(this, 'mediaBox', obj); }, get view() { var obj = this.inheritPageProp('CropBox'); @@ -4819,7 +4821,65 @@ var CanvasGraphics = (function canvasGraphics() { TODO('set flatness: ' + flatness); }, setGState: function canvasGraphicsSetGState(dictName) { - TODO('set graphics state from dict: ' + dictName); + var extGState = this.xref.fetchIfRef(this.res.get('ExtGState')); + if (IsDict(extGState) && extGState.has(dictName.name)) { + var gsState = this.xref.fetchIfRef(extGState.get(dictName.name)); + var self = this; + gsState.forEach(function(key, value) { + switch (key) { + case 'Type': + break; + case 'LW': + self.setLineWidth(value); + break; + case 'LC': + self.setLineCap(value); + break; + case 'LJ': + self.setLineJoin(value); + break; + case 'ML': + self.setMiterLimit(value); + break; + case 'D': + self.setDash(value[0], value[1]); + break; + case 'RI': + self.setRenderingIntent(value); + break; + case 'FL': + self.setFlatness(value); + break; + case 'Font': + self.setFont(value[0], value[1]); + break; + case 'OP': + case 'op': + case 'OPM': + case 'BG': + case 'BG2': + case 'UCR': + case 'UCR2': + case 'TR': + case 'TR2': + case 'HT': + case 'SM': + case 'SA': + case 'BM': + case 'SMask': + case 'CA': + case 'ca': + case 'AIS': + case 'TK': + TODO('graphic state operator ' + key); + break; + default: + warn('Unknown graphic state operator ' + key); + break; + } + }); + } + }, save: function canvasGraphicsSave() { this.ctx.save(); @@ -4986,11 +5046,17 @@ var CanvasGraphics = (function canvasGraphics() { this.current.leading = -leading; }, setFont: function canvasGraphicsSetFont(fontRef, size) { - var font = this.xref.fetchIfRef(this.res.get('Font')); - if (!IsDict(font)) - return; + var font; + // the tf command uses a name, but graphics state uses a reference + if (IsName(fontRef)) { + font = this.xref.fetchIfRef(this.res.get('Font')); + if (!IsDict(font)) + return; - font = font.get(fontRef.name); + font = font.get(fontRef.name); + } else if (IsRef(fontRef)) { + font = fontRef; + } font = this.xref.fetchIfRef(font); if (!font) error('Referenced font is not found'); diff --git a/test/driver.js b/test/driver.js index 4751910b2..4aa5149f6 100644 --- a/test/driver.js +++ b/test/driver.js @@ -50,7 +50,21 @@ function load() { r.send(null); } +function cleanup() { + var styleSheet = document.styleSheets[0]; + if (styleSheet) { + while (styleSheet.cssRules.length > 0) + styleSheet.deleteRule(0); + } + var guard = document.getElementById('content-end'); + var body = document.body; + while (body.lastChild !== guard) + body.removeChild(body.lastChild); +} + function nextTask() { + cleanup(); + if (currentTaskIdx == manifest.length) { return done(); } diff --git a/test/pdfs/extgstate.pdf b/test/pdfs/extgstate.pdf new file mode 100644 index 000000000..711c45147 --- /dev/null +++ b/test/pdfs/extgstate.pdf @@ -0,0 +1,105 @@ +%PDF-1.4 +%öäüß +1 0 obj +<< +/Type /Catalog +/Version /1.4 +/Pages 2 0 R +>> +endobj +2 0 obj +<< +/Type /Pages +/Kids [3 0 R] +/Count 1 +>> +endobj +3 0 obj +<< +/Type /Page +/MediaBox [0 0 612 792] +/Resources 4 0 R +/Parent 2 0 R +/Contents 5 0 R +>> +endobj +4 0 obj +<< +/ExtGState 6 0 R +/Font 7 0 R +/XObject << +>> +>> +endobj +5 0 obj +<< +/Length 8 0 R +>> +stream +/GS1 gs +/F0 12 Tf +BT +100 700 Td +(I should be courier!) Tj +ET +50 600 m +400 600 l +S + +endstream +endobj +6 0 obj +<< +/GS1 9 0 R +>> +endobj +7 0 obj +<< +/F0 10 0 R +>> +endobj +8 0 obj +82 +endobj +9 0 obj +<< +/Type /ExtGState +/LW 10 +/LC 1 +/LJ 2 +/ML 0.3000000119 +/D [[0.0917000026 183.3300018311] + 0] +/Font [10 0 R 36] +>> +endobj +10 0 obj +<< +/Type /Font +/Subtype /Type1 +/BaseFont /Courier +/Encoding /WinAnsiEncoding +>> +endobj +xref +0 11 +0000000000 65535 f +0000000015 00000 n +0000000078 00000 n +0000000135 00000 n +0000000239 00000 n +0000000304 00000 n +0000000441 00000 n +0000000473 00000 n +0000000505 00000 n +0000000523 00000 n +0000000653 00000 n +trailer +<< +/Root 1 0 R +/ID [ ] +/Size 11 +>> +startxref +749 +%%EOF diff --git a/test/test_manifest.json b/test/test_manifest.json index 231857fa8..39d1f50ab 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -151,5 +151,11 @@ "link": true, "rounds": 1, "type": "load" + }, + { "id": "extgstate", + "file": "pdfs/extgstate.pdf", + "link": false, + "rounds": 1, + "type": "load" } ] diff --git a/test/test_slave.html b/test/test_slave.html index b46e29d6b..57d8d7a83 100644 --- a/test/test_slave.html +++ b/test/test_slave.html @@ -14,6 +14,7 @@

   

Inflight requests:

+