]> git.parisson.com Git - pdf.js.git/commitdiff
readXRefStream and PNG predictor 12
authornotmasteryet <async.processingjs@yahoo.com>
Fri, 17 Jun 2011 12:37:14 +0000 (07:37 -0500)
committernotmasteryet <async.processingjs@yahoo.com>
Fri, 17 Jun 2011 12:37:14 +0000 (07:37 -0500)
pdf.js

diff --git a/pdf.js b/pdf.js
index 17537d233ac3f0d063bc64b445e6c79c07408c96..dc2302d2d3af201e50cd0dd67c9a309fb4ead25a 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -506,6 +506,94 @@ var FlateStream = (function() {
     return constructor;
 })();
 
+var PredictorStream = (function() {
+    function constructor(stream, params) {
+        this.stream = stream;
+        this.predictor = params.get("Predictor") || 1;
+        if (this.predictor <= 1) {
+            return stream; // no prediction
+        }
+        if (params.has("EarlyChange")) {
+            error("EarlyChange predictor parameter is not supported");
+        }
+        this.colors = params.get("Colors") || 1;
+        this.bitsPerComponent = params.get("BitsPerComponent") || 8;
+        this.columns = params.get("Columns") || 1;
+        if (this.colors !== 1 || this.bitsPerComponent !== 8) {
+            error("Multi-color and multi-byte predictors are not supported");
+        }
+        if (this.predictor < 10 || this.predictor > 15) {
+            error("Unsupported predictor");
+        }
+        this.currentRow = new Uint8Array(this.columns);
+        this.pos = 0;
+        this.bufferLength = 0;
+    }
+
+    constructor.prototype = {
+        readRow : function() {
+            var lastRow = this.currentRow;
+            var predictor = this.stream.getByte();
+            var currentRow = this.stream.getBytes(this.columns), i;
+            switch (predictor) {
+            default:
+                error("Unsupported predictor");
+                break;
+            case 0:
+                break;
+            case 2:
+                for (i = 0; i < currentRow.length; ++i) {
+                  currentRow[i] = (lastRow[i] + currentRow[i]) & 0xFF;
+                }
+                break;
+            }
+            this.pos = 0;
+            this.bufferLength = currentRow.length;
+            this.currentRow = currentRow;
+        },
+        getByte : function() {
+            if (this.pos >= this.bufferLength) {
+               this.readRow();
+            }
+            return this.currentRow[this.pos++];
+        },
+        getBytes : function(n) {
+            var i, bytes;
+            bytes = new Uint8Array(n);
+            for (i = 0; i < n; ++i) {
+              if (this.pos >= this.bufferLength) {
+                this.readRow();
+              }
+              bytes[i] = this.currentRow[this.pos++];
+            }
+            return bytes;
+        },
+        getChar : function() {
+            return String.formCharCode(this.getByte());
+        },
+        lookChar : function() {
+            if (this.pos >= this.bufferLength) {
+               this.readRow();
+            }
+            return String.formCharCode(this.currentRow[this.pos]);
+        },
+        skip : function(n) {
+            var i;
+            if (!n) {
+                n = 1;
+            }
+            while (n > this.bufferLength - this.pos) {
+                n -= this.bufferLength - this.pos;
+                this.readRow();
+                if (this.bufferLength === 0) break;
+            }
+            this.pos += n;
+        }
+    };
+
+    return constructor;
+})();
+
 var DecryptStream = (function() {
     function constructor(str, fileKey, encAlgorithm, keyLength) {
         // TODO
@@ -1079,7 +1167,9 @@ var Parser = (function() {
                                            this.encAlgorithm,
                                            this.keyLength);
             }
-            return this.filter(stream, dict);
+            stream = this.filter(stream, dict);
+            stream.parameters = dict; 
+            return stream;
         },
         filter: function(stream, dict) {
             var filter = dict.get2("Filter", "F");
@@ -1104,8 +1194,9 @@ var Parser = (function() {
         },
         makeFilter: function(stream, name, params) {
             if (name == "FlateDecode" || name == "Fl") {
-                if (params)
-                    error("params not supported yet for FlateDecode");
+                if (params) {
+                    return new PredictorStream(new FlateStream(stream), params);
+                }
                 return new FlateStream(stream);
             } else {
                 error("filter '" + name + "' not supported yet");
@@ -1198,10 +1289,10 @@ var XRef = (function() {
         this.stream = stream;
         this.entries = [];
         this.xrefstms = {};
-        this.readXRef(startXRef);
+        var trailerDict = this.readXRef(startXRef);
 
         // get the root dictionary (catalog) object
-        if (!IsRef(this.root = this.trailerDict.get("Root")))
+        if (!IsRef(this.root = trailerDict.get("Root")))
             error("Invalid root reference");
 
         // prepare the XRef cache
@@ -1256,18 +1347,18 @@ var XRef = (function() {
                 error("Invalid XRef table");
 
             // get the 'Prev' pointer
-            var more = false;
+            var prev;
             obj = dict.get("Prev");
             if (IsInt(obj)) {
-                this.prev = obj;
-                more = true;
+                prev = obj;
             } else if (IsRef(obj)) {
                 // certain buggy PDF generators generate "/Prev NNN 0 R" instead
                 // of "/Prev NNN"
-                this.prev = obj.num;
-                more = true;
+                prev = obj.num;
+            }
+            if (prev) {
+              this.readXRef(prev);
             }
-            this.trailerDict = dict;
 
             // check for 'XRefStm' key
             if (IsInt(obj = dict.get("XRefStm"))) {
@@ -1277,11 +1368,64 @@ var XRef = (function() {
                 this.xrefstms[pos] = 1; // avoid infinite recursion
                 this.readXRef(pos);
             }
-
-            return more;
-        },
-        readXRefStream: function(parser) {
-            error("Invalid XRef stream");
+            return dict;
+        },
+        readXRefStream: function(stream) {
+            var streamParameters = stream.parameters;
+            var length = streamParameters.get("Length");
+            var byteWidths = streamParameters.get("W");
+            var range = streamParameters.get("Index");
+            if (!range) {
+                range = [0, streamParameters.get("Size")];
+            }
+            var i, j;
+            while (range.length > 0) {
+                var first = range[0], n = range[1];
+                if (!IsInt(first) || !IsInt(n)) {
+                    error("Invalid XRef range fields");
+                }
+                var typeFieldWidth = byteWidths[0], offsetFieldWidth = byteWidths[1], generationFieldWidth = byteWidths[2];
+                if (!IsInt(typeFieldWidth) || !IsInt(offsetFieldWidth) || !IsInt(generationFieldWidth)) {
+                    error("Invalid XRef entry fields length");
+                }
+                for (i = 0; i < n; ++i) {
+                    var type = 0, offset = 0, generation = 0;
+                    for (j = 0; j < typeFieldWidth; ++j) {
+                       type = (type << 8) | stream.getByte();
+                    }
+                    for (j = 0; j < offsetFieldWidth; ++j) {
+                       offset = (offset << 8) | stream.getByte();
+                    }
+                    for (j = 0; j < generationFieldWidth; ++j) {
+                       generation = (generation << 8) | stream.getByte();
+                    }
+                    var entry = { offset: offset, gen: generation };
+                    if (typeFieldWidth > 0) {
+                        switch (type) {
+                        case 0:
+                           entry.free = true;
+                           break;
+                        case 1:
+                           entry.uncompressed = true;
+                           break;
+                        case 2:
+                           break;
+                        default:
+                           error("Invalid XRef entry type");
+                           break;
+                        }
+                    }
+                    if (!this.entries[first + i]) {
+                        this.entries[first + i] = entry;
+                    }
+                }
+                range.splice(0, 2);
+            }
+            var prev = streamParameters.get("Prev");
+            if (IsInt(prev)) {
+                this.readXRef(prev);
+            }
+            return streamParameters;
         },
         readXRef: function(startXRef) {
             var stream = this.stream;
@@ -1565,7 +1709,7 @@ var PDFDoc = (function() {
         },
         getPage: function(n) {
             var linearization = this.linearization;
-            assert(!linearization, "linearized page access not implemented");
+            // assert(!linearization, "linearized page access not implemented");
             return this.catalog.getPage(n);
         }
     };