readXRefStream and PNG predictor 12
This commit is contained in:
		
							parent
							
								
									8ab68cf17a
								
							
						
					
					
						commit
						a2d7c18aee
					
				
							
								
								
									
										176
									
								
								pdf.js
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								pdf.js
									
									
									
									
									
								
							| @ -506,6 +506,94 @@ var FlateStream = (function() { | |||||||
|     return constructor; |     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() { | var DecryptStream = (function() { | ||||||
|     function constructor(str, fileKey, encAlgorithm, keyLength) { |     function constructor(str, fileKey, encAlgorithm, keyLength) { | ||||||
|         // TODO
 |         // TODO
 | ||||||
| @ -1079,7 +1167,9 @@ var Parser = (function() { | |||||||
|                                            this.encAlgorithm, |                                            this.encAlgorithm, | ||||||
|                                            this.keyLength); |                                            this.keyLength); | ||||||
|             } |             } | ||||||
|             return this.filter(stream, dict); |             stream = this.filter(stream, dict); | ||||||
|  |             stream.parameters = dict;  | ||||||
|  |             return stream; | ||||||
|         }, |         }, | ||||||
|         filter: function(stream, dict) { |         filter: function(stream, dict) { | ||||||
|             var filter = dict.get2("Filter", "F"); |             var filter = dict.get2("Filter", "F"); | ||||||
| @ -1104,8 +1194,9 @@ var Parser = (function() { | |||||||
|         }, |         }, | ||||||
|         makeFilter: function(stream, name, params) { |         makeFilter: function(stream, name, params) { | ||||||
|             if (name == "FlateDecode" || name == "Fl") { |             if (name == "FlateDecode" || name == "Fl") { | ||||||
|                 if (params) |                 if (params) { | ||||||
|                     error("params not supported yet for FlateDecode"); |                     return new PredictorStream(new FlateStream(stream), params); | ||||||
|  |                 } | ||||||
|                 return new FlateStream(stream); |                 return new FlateStream(stream); | ||||||
|             } else { |             } else { | ||||||
|                 error("filter '" + name + "' not supported yet"); |                 error("filter '" + name + "' not supported yet"); | ||||||
| @ -1198,10 +1289,10 @@ var XRef = (function() { | |||||||
|         this.stream = stream; |         this.stream = stream; | ||||||
|         this.entries = []; |         this.entries = []; | ||||||
|         this.xrefstms = {}; |         this.xrefstms = {}; | ||||||
|         this.readXRef(startXRef); |         var trailerDict = this.readXRef(startXRef); | ||||||
| 
 | 
 | ||||||
|         // get the root dictionary (catalog) object
 |         // 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"); |             error("Invalid root reference"); | ||||||
| 
 | 
 | ||||||
|         // prepare the XRef cache
 |         // prepare the XRef cache
 | ||||||
| @ -1256,18 +1347,18 @@ var XRef = (function() { | |||||||
|                 error("Invalid XRef table"); |                 error("Invalid XRef table"); | ||||||
| 
 | 
 | ||||||
|             // get the 'Prev' pointer
 |             // get the 'Prev' pointer
 | ||||||
|             var more = false; |             var prev; | ||||||
|             obj = dict.get("Prev"); |             obj = dict.get("Prev"); | ||||||
|             if (IsInt(obj)) { |             if (IsInt(obj)) { | ||||||
|                 this.prev = obj; |                 prev = obj; | ||||||
|                 more = true; |  | ||||||
|             } else if (IsRef(obj)) { |             } else if (IsRef(obj)) { | ||||||
|                 // certain buggy PDF generators generate "/Prev NNN 0 R" instead
 |                 // certain buggy PDF generators generate "/Prev NNN 0 R" instead
 | ||||||
|                 // of "/Prev NNN"
 |                 // of "/Prev NNN"
 | ||||||
|                 this.prev = obj.num; |                 prev = obj.num; | ||||||
|                 more = true; |             } | ||||||
|  |             if (prev) { | ||||||
|  |               this.readXRef(prev); | ||||||
|             } |             } | ||||||
|             this.trailerDict = dict; |  | ||||||
| 
 | 
 | ||||||
|             // check for 'XRefStm' key
 |             // check for 'XRefStm' key
 | ||||||
|             if (IsInt(obj = dict.get("XRefStm"))) { |             if (IsInt(obj = dict.get("XRefStm"))) { | ||||||
| @ -1277,11 +1368,64 @@ var XRef = (function() { | |||||||
|                 this.xrefstms[pos] = 1; // avoid infinite recursion
 |                 this.xrefstms[pos] = 1; // avoid infinite recursion
 | ||||||
|                 this.readXRef(pos); |                 this.readXRef(pos); | ||||||
|             } |             } | ||||||
| 
 |             return dict; | ||||||
|             return more; |  | ||||||
|         }, |         }, | ||||||
|         readXRefStream: function(parser) { |         readXRefStream: function(stream) { | ||||||
|             error("Invalid XRef 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) { |         readXRef: function(startXRef) { | ||||||
|             var stream = this.stream; |             var stream = this.stream; | ||||||
| @ -1565,7 +1709,7 @@ var PDFDoc = (function() { | |||||||
|         }, |         }, | ||||||
|         getPage: function(n) { |         getPage: function(n) { | ||||||
|             var linearization = this.linearization; |             var linearization = this.linearization; | ||||||
|             assert(!linearization, "linearized page access not implemented"); |             // assert(!linearization, "linearized page access not implemented");
 | ||||||
|             return this.catalog.getPage(n); |             return this.catalog.getPage(n); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user