readXRefStream and PNG predictor 12

This commit is contained in:
notmasteryet 2011-06-17 07:37:14 -05:00
parent 8ab68cf17a
commit a2d7c18aee

176
pdf.js
View File

@ -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);
} }
}; };