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…
Reference in New Issue
Block a user