|
|
|
@ -49,6 +49,14 @@ function shadow(obj, prop, value) {
@@ -49,6 +49,14 @@ function shadow(obj, prop, value) {
|
|
|
|
|
return value; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function bytesToString(bytes) { |
|
|
|
|
var str = ""; |
|
|
|
|
var length = bytes.length; |
|
|
|
|
for (var n = 0; n < length; ++n) |
|
|
|
|
str += String.fromCharCode(bytes[n]); |
|
|
|
|
return str; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var Stream = (function() { |
|
|
|
|
function constructor(arrayBuffer, start, length, dict) { |
|
|
|
|
this.bytes = Uint8Array(arrayBuffer); |
|
|
|
@ -75,7 +83,7 @@ var Stream = (function() {
@@ -75,7 +83,7 @@ var Stream = (function() {
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
var end = pos + length; |
|
|
|
|
var strEnd = this.end; |
|
|
|
|
if (end > strEnd) |
|
|
|
|
if (!end || end > strEnd) |
|
|
|
|
end = strEnd; |
|
|
|
|
|
|
|
|
|
this.pos = end; |
|
|
|
@ -234,10 +242,12 @@ var FlateStream = (function() {
@@ -234,10 +242,12 @@ var FlateStream = (function() {
|
|
|
|
|
]), 5]; |
|
|
|
|
|
|
|
|
|
function constructor(stream) { |
|
|
|
|
this.stream = stream; |
|
|
|
|
var bytes = stream.getBytes(); |
|
|
|
|
var bytesPos = 0; |
|
|
|
|
|
|
|
|
|
this.dict = stream.dict; |
|
|
|
|
var cmf = stream.getByte(); |
|
|
|
|
var flg = stream.getByte(); |
|
|
|
|
var cmf = bytes[bytesPos++]; |
|
|
|
|
var flg = bytes[bytesPos++]; |
|
|
|
|
if (cmf == -1 || flg == -1) |
|
|
|
|
error("Invalid header in flate stream"); |
|
|
|
|
if ((cmf & 0x0f) != 0x08) |
|
|
|
@ -246,6 +256,9 @@ var FlateStream = (function() {
@@ -246,6 +256,9 @@ var FlateStream = (function() {
|
|
|
|
|
error("Bad FCHECK in flate stream"); |
|
|
|
|
if (flg & 0x20) |
|
|
|
|
error("FDICT bit set in flate stream"); |
|
|
|
|
|
|
|
|
|
this.bytes = bytes; |
|
|
|
|
this.bytesPos = bytesPos; |
|
|
|
|
this.eof = false; |
|
|
|
|
this.codeSize = 0; |
|
|
|
|
this.codeBuf = 0; |
|
|
|
@ -256,12 +269,14 @@ var FlateStream = (function() {
@@ -256,12 +269,14 @@ var FlateStream = (function() {
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
getBits: function(bits) { |
|
|
|
|
var stream = this.stream; |
|
|
|
|
var codeSize = this.codeSize; |
|
|
|
|
var codeBuf = this.codeBuf; |
|
|
|
|
var bytes = this.bytes; |
|
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
|
|
|
|
|
|
var b; |
|
|
|
|
while (codeSize < bits) { |
|
|
|
|
if ((b = stream.getByte()) == -1) |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
|
codeBuf |= b << codeSize; |
|
|
|
|
codeSize += 8; |
|
|
|
@ -269,6 +284,7 @@ var FlateStream = (function() {
@@ -269,6 +284,7 @@ var FlateStream = (function() {
|
|
|
|
|
b = codeBuf & ((1 << bits) - 1); |
|
|
|
|
this.codeBuf = codeBuf >> bits; |
|
|
|
|
this.codeSize = codeSize -= bits; |
|
|
|
|
this.bytesPos = bytesPos; |
|
|
|
|
return b; |
|
|
|
|
}, |
|
|
|
|
getCode: function(table) { |
|
|
|
@ -276,10 +292,12 @@ var FlateStream = (function() {
@@ -276,10 +292,12 @@ var FlateStream = (function() {
|
|
|
|
|
var maxLen = table[1]; |
|
|
|
|
var codeSize = this.codeSize; |
|
|
|
|
var codeBuf = this.codeBuf; |
|
|
|
|
var stream = this.stream; |
|
|
|
|
var bytes = this.bytes; |
|
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
|
|
|
|
|
|
while (codeSize < maxLen) { |
|
|
|
|
var b; |
|
|
|
|
if ((b = stream.getByte()) == -1) |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
|
codeBuf |= (b << codeSize); |
|
|
|
|
codeSize += 8; |
|
|
|
@ -291,6 +309,7 @@ var FlateStream = (function() {
@@ -291,6 +309,7 @@ var FlateStream = (function() {
|
|
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
|
this.codeBuf = (codeBuf >> codeLen); |
|
|
|
|
this.codeSize = (codeSize - codeLen); |
|
|
|
|
this.bytesPos = bytesPos; |
|
|
|
|
return codeVal; |
|
|
|
|
}, |
|
|
|
|
ensureBuffer: function(requested) { |
|
|
|
@ -307,9 +326,8 @@ var FlateStream = (function() {
@@ -307,9 +326,8 @@ var FlateStream = (function() {
|
|
|
|
|
return this.buffer = buffer2; |
|
|
|
|
}, |
|
|
|
|
getByte: function() { |
|
|
|
|
var bufferLength = this.bufferLength; |
|
|
|
|
var pos = this.pos; |
|
|
|
|
if (bufferLength <= pos) { |
|
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
|
if (this.eof) |
|
|
|
|
return; |
|
|
|
|
this.readBlock(); |
|
|
|
@ -332,9 +350,8 @@ var FlateStream = (function() {
@@ -332,9 +350,8 @@ var FlateStream = (function() {
|
|
|
|
|
return this.buffer.subarray(pos, end) |
|
|
|
|
}, |
|
|
|
|
lookChar: function() { |
|
|
|
|
var bufferLength = this.bufferLength; |
|
|
|
|
var pos = this.pos; |
|
|
|
|
if (bufferLength <= pos) { |
|
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
|
if (this.eof) |
|
|
|
|
return; |
|
|
|
|
this.readBlock(); |
|
|
|
@ -343,16 +360,15 @@ var FlateStream = (function() {
@@ -343,16 +360,15 @@ var FlateStream = (function() {
|
|
|
|
|
}, |
|
|
|
|
getChar: function() { |
|
|
|
|
var ch = this.lookChar(); |
|
|
|
|
if (!ch) |
|
|
|
|
return; |
|
|
|
|
// shouldnt matter what the position is if we get past the eof
|
|
|
|
|
// so no need to check if ch is undefined
|
|
|
|
|
this.pos++; |
|
|
|
|
return ch; |
|
|
|
|
}, |
|
|
|
|
skip: function(n) { |
|
|
|
|
if (!n) |
|
|
|
|
n = 1; |
|
|
|
|
while (n-- > 0) |
|
|
|
|
this.getChar(); |
|
|
|
|
this.pos += n; |
|
|
|
|
}, |
|
|
|
|
generateHuffmanTable: function(lengths) { |
|
|
|
|
var n = lengths.length; |
|
|
|
@ -398,7 +414,8 @@ var FlateStream = (function() {
@@ -398,7 +414,8 @@ var FlateStream = (function() {
|
|
|
|
|
array[i++] = what; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var stream = this.stream; |
|
|
|
|
var bytes = this.bytes; |
|
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
|
|
|
|
|
|
// read block header
|
|
|
|
|
var hdr = this.getBits(3); |
|
|
|
@ -408,16 +425,16 @@ var FlateStream = (function() {
@@ -408,16 +425,16 @@ var FlateStream = (function() {
|
|
|
|
|
|
|
|
|
|
var b; |
|
|
|
|
if (hdr == 0) { // uncompressed block
|
|
|
|
|
if ((b = stream.getByte()) == -1) |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
var blockLen = b; |
|
|
|
|
if ((b = stream.getByte()) == -1) |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
blockLen |= (b << 8); |
|
|
|
|
if ((b = stream.getByte()) == -1) |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
var check = b; |
|
|
|
|
if ((b = stream.getByte()) == -1) |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
check |= (b << 8); |
|
|
|
|
if (check != (~this.blockLen & 0xffff)) |
|
|
|
@ -426,7 +443,7 @@ var FlateStream = (function() {
@@ -426,7 +443,7 @@ var FlateStream = (function() {
|
|
|
|
|
var buffer = this.ensureBuffer(bufferLength + blockLen); |
|
|
|
|
this.bufferLength = bufferLength + blockLen; |
|
|
|
|
for (var n = bufferLength; n < blockLen; ++n) { |
|
|
|
|
if ((b = stream.getByte()) == -1) { |
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") { |
|
|
|
|
this.eof = true; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
@ -509,7 +526,7 @@ var FlateStream = (function() {
@@ -509,7 +526,7 @@ var FlateStream = (function() {
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
var FilterPredictor = (function() { |
|
|
|
|
function constructor(str, type, width, colors, bits) { |
|
|
|
|
this.str = str; |
|
|
|
@ -674,59 +691,108 @@ var FilterPredictor = (function() {
@@ -674,59 +691,108 @@ var FilterPredictor = (function() {
|
|
|
|
|
}; |
|
|
|
|
return constructor; |
|
|
|
|
})(); |
|
|
|
|
*/ |
|
|
|
|
// A JpegStream can't be read directly. We use the platform to render the underlying
|
|
|
|
|
// JPEG data for us.
|
|
|
|
|
var JpegStream = (function() { |
|
|
|
|
function constructor(bytes, dict) { |
|
|
|
|
// TODO: per poppler, some images may have "junk" before that need to be removed
|
|
|
|
|
this.dict = dict; |
|
|
|
|
|
|
|
|
|
// create DOM image
|
|
|
|
|
var img = new Image(); |
|
|
|
|
img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes)); |
|
|
|
|
this.domImage = img; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
getByte: function() { |
|
|
|
|
// dummy method to pass IsStream test
|
|
|
|
|
error("shouldnt be called"); |
|
|
|
|
}, |
|
|
|
|
getImage: function() { |
|
|
|
|
return this.domImage; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
var PredictorStream = (function() { |
|
|
|
|
function constructor(stream, params) { |
|
|
|
|
this.stream = stream; |
|
|
|
|
this.predictor = params.get("Predictor") || 1; |
|
|
|
|
if (this.predictor <= 1) { |
|
|
|
|
var predictor = params.get("Predictor") || 1; |
|
|
|
|
this.predictor = predictor; |
|
|
|
|
|
|
|
|
|
if (predictor <= 1) |
|
|
|
|
return stream; // no prediction
|
|
|
|
|
} |
|
|
|
|
if (predictor !== 2 && (predictor < 10 || predictor > 15)) |
|
|
|
|
error("Unsupported predictor"); |
|
|
|
|
|
|
|
|
|
if (predictor === 2) |
|
|
|
|
this.readRow = this.readRowTiff; |
|
|
|
|
else |
|
|
|
|
this.readRow = this.readRowPng; |
|
|
|
|
|
|
|
|
|
this.stream = stream; |
|
|
|
|
this.dict = stream.dict; |
|
|
|
|
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.bitsPerComponent !== 8) { |
|
|
|
|
error("Multi-byte predictors are not supported"); |
|
|
|
|
} |
|
|
|
|
if (this.predictor < 10 || this.predictor > 15) { |
|
|
|
|
error("Unsupported predictor"); |
|
|
|
|
} |
|
|
|
|
this.currentRow = new Uint8Array(this.columns * this.colors); |
|
|
|
|
this.pos = 0; |
|
|
|
|
this.bufferLength = 0; |
|
|
|
|
var colors = params.get("Colors") || 1; |
|
|
|
|
this.colors = colors; |
|
|
|
|
var bits = params.get("BitsPerComponent") || 8; |
|
|
|
|
this.bits = bits; |
|
|
|
|
var columns = params.get("Columns") || 1; |
|
|
|
|
this.columns = columns; |
|
|
|
|
|
|
|
|
|
var pixBytes = (colors * bits + 7) >> 3; |
|
|
|
|
this.pixBytes = pixBytes; |
|
|
|
|
// add an extra pixByte to represent the pixel left column 0
|
|
|
|
|
var rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes; |
|
|
|
|
this.rowBytes = rowBytes; |
|
|
|
|
|
|
|
|
|
this.currentRow = new Uint8Array(rowBytes); |
|
|
|
|
this.pos = rowBytes; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
readRow : function() { |
|
|
|
|
var lastRow = this.currentRow; |
|
|
|
|
var colors = this.colors; |
|
|
|
|
readRowTiff : function() { |
|
|
|
|
}, |
|
|
|
|
readRowPng : function() { |
|
|
|
|
// swap the buffers
|
|
|
|
|
var currentRow = this.currentRow; |
|
|
|
|
|
|
|
|
|
var rowBytes = this.rowBytes; |
|
|
|
|
var pixBytes = this.pixBytes; |
|
|
|
|
|
|
|
|
|
var predictor = this.stream.getByte(); |
|
|
|
|
var currentRow = this.stream.getBytes(this.columns * colors), i; |
|
|
|
|
var rawBytes = this.stream.getBytes(rowBytes - pixBytes); |
|
|
|
|
var i; |
|
|
|
|
|
|
|
|
|
switch (predictor) { |
|
|
|
|
default: |
|
|
|
|
error("Unsupported predictor"); |
|
|
|
|
break; |
|
|
|
|
case 0: |
|
|
|
|
break; |
|
|
|
|
case 1: |
|
|
|
|
for (i = colors; i < currentRow.length; ++i) { |
|
|
|
|
currentRow[i] = (currentRow[i - colors] + currentRow[i]) & 0xFF; |
|
|
|
|
} |
|
|
|
|
for (i = pixBytes; i < rowBytes; ++i) |
|
|
|
|
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF; |
|
|
|
|
break; |
|
|
|
|
case 2: |
|
|
|
|
for (i = 0; i < currentRow.length; ++i) { |
|
|
|
|
currentRow[i] = (lastRow[i] + currentRow[i]) & 0xFF; |
|
|
|
|
} |
|
|
|
|
for (i = pixBytes; i < rowBytes; ++i) |
|
|
|
|
currentRow[i] = (currentRow[i] + rawBytes[i]) & 0xFF; |
|
|
|
|
break; |
|
|
|
|
case 3: |
|
|
|
|
for (i = 0; i < color; ++i) { |
|
|
|
|
currentRow[i] = ((lastRow[i] >> 1) + currentRow[i]) & 0xFF; |
|
|
|
|
} |
|
|
|
|
for (; i < currentRow.length; ++i) { |
|
|
|
|
currentRow[i] = (((lastRow[i] + currentRow[i]) >> 1) + currentRow[i]) & 0xFF; |
|
|
|
|
for (i = pixBytes; i < rowBytes; ++i) |
|
|
|
|
currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes]) |
|
|
|
|
>> 1) + rawBytes[i]) & 0xFF; |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
for (i = pixBytes; i < rowBytes; ++i) { |
|
|
|
|
var left = currentRow[i - pixBytes]; |
|
|
|
|
var up = currentRow[i]; |
|
|
|
|
var upLeft = |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
error("Unsupported predictor"); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
this.pos = 0; |
|
|
|
@ -1362,15 +1428,15 @@ var Parser = (function() {
@@ -1362,15 +1428,15 @@ var Parser = (function() {
|
|
|
|
|
this.encAlgorithm, |
|
|
|
|
this.keyLength); |
|
|
|
|
} |
|
|
|
|
stream = this.filter(stream, dict); |
|
|
|
|
stream = this.filter(stream, dict, length); |
|
|
|
|
stream.parameters = dict; |
|
|
|
|
return stream; |
|
|
|
|
}, |
|
|
|
|
filter: function(stream, dict) { |
|
|
|
|
filter: function(stream, dict, length) { |
|
|
|
|
var filter = dict.get2("Filter", "F"); |
|
|
|
|
var params = dict.get2("DecodeParms", "DP"); |
|
|
|
|
if (IsName(filter)) |
|
|
|
|
return this.makeFilter(stream, filter.name, params); |
|
|
|
|
return this.makeFilter(stream, filter.name, length, params); |
|
|
|
|
if (IsArray(filter)) { |
|
|
|
|
var filterArray = filter; |
|
|
|
|
var paramsArray = params; |
|
|
|
@ -1381,15 +1447,15 @@ var Parser = (function() {
@@ -1381,15 +1447,15 @@ var Parser = (function() {
|
|
|
|
|
params = null; |
|
|
|
|
if (IsArray(paramsArray) && (i in paramsArray)) |
|
|
|
|
params = paramsArray[i]; |
|
|
|
|
stream = this.makeFilter(stream, filter.name, params); |
|
|
|
|
stream = this.makeFilter(stream, filter.name, length, params); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return stream; |
|
|
|
|
}, |
|
|
|
|
makeFilter: function(stream, name, params) { |
|
|
|
|
makeFilter: function(stream, name, length, params) { |
|
|
|
|
if (name == "FlateDecode" || name == "Fl") { |
|
|
|
|
var flateStr = new FlateStream(stream); |
|
|
|
|
/* var flateStr = new FlateStream(stream); |
|
|
|
|
if (IsDict(params)) { |
|
|
|
|
var predType = params.get("Predictor"); |
|
|
|
|
if (predType && predType > 1) { |
|
|
|
@ -1409,12 +1475,14 @@ var Parser = (function() {
@@ -1409,12 +1475,14 @@ var Parser = (function() {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return flateStr; |
|
|
|
|
/* |
|
|
|
|
*/ |
|
|
|
|
if (params) { |
|
|
|
|
return new PredictorStream(new FlateStream(stream), params); |
|
|
|
|
} |
|
|
|
|
return new FlateStream(stream); |
|
|
|
|
*/ |
|
|
|
|
} else if (name == "DCTDecode") { |
|
|
|
|
var bytes = stream.getBytes(length); |
|
|
|
|
return new JpegStream(bytes, stream.dict); |
|
|
|
|
} else { |
|
|
|
|
error("filter '" + name + "' not supported yet"); |
|
|
|
|
} |
|
|
|
@ -1989,6 +2057,7 @@ var CanvasExtraState = (function() {
@@ -1989,6 +2057,7 @@ var CanvasExtraState = (function() {
|
|
|
|
|
this.fontSize = 0.0; |
|
|
|
|
this.textMatrix = IDENTITY_MATRIX; |
|
|
|
|
this.leading = 0.0; |
|
|
|
|
this.colorSpace = null; |
|
|
|
|
// Current point (in user coordinates)
|
|
|
|
|
this.x = 0.0; |
|
|
|
|
this.y = 0.0; |
|
|
|
@ -2283,6 +2352,9 @@ var CanvasGraphics = (function() {
@@ -2283,6 +2352,9 @@ var CanvasGraphics = (function() {
|
|
|
|
|
const NORMAL_CLIP = {}; |
|
|
|
|
const EO_CLIP = {}; |
|
|
|
|
|
|
|
|
|
// Used for tiling patterns
|
|
|
|
|
const PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; |
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
translateFont: function(fontDict, xref, resources) { |
|
|
|
|
var descriptor = xref.fetch(fontDict.get("FontDescriptor")); |
|
|
|
@ -2597,11 +2669,17 @@ var CanvasGraphics = (function() {
@@ -2597,11 +2669,17 @@ var CanvasGraphics = (function() {
|
|
|
|
|
|
|
|
|
|
var fontName = ""; |
|
|
|
|
var fontDescriptor = font.get("FontDescriptor"); |
|
|
|
|
if (fontDescriptor.num) { |
|
|
|
|
if (fontDescriptor && fontDescriptor.num) { |
|
|
|
|
var fontDescriptor = this.xref.fetchIfRef(fontDescriptor); |
|
|
|
|
fontName = fontDescriptor.get("FontName").name.replace("+", "_"); |
|
|
|
|
Fonts.active = fontName; |
|
|
|
|
} |
|
|
|
|
if (!fontName) { |
|
|
|
|
// TODO: fontDescriptor is not available, fallback to default font
|
|
|
|
|
this.current.fontSize = size; |
|
|
|
|
this.ctx.font = this.current.fontSize + 'px sans-serif'; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.current.fontSize = size; |
|
|
|
|
this.ctx.font = this.current.fontSize +'px "' + fontName + '"'; |
|
|
|
@ -2630,9 +2708,9 @@ var CanvasGraphics = (function() {
@@ -2630,9 +2708,9 @@ var CanvasGraphics = (function() {
|
|
|
|
|
}, |
|
|
|
|
showText: function(text) { |
|
|
|
|
this.ctx.save(); |
|
|
|
|
this.ctx.translate(0, 2 * this.current.y); |
|
|
|
|
this.ctx.scale(1, -1); |
|
|
|
|
this.ctx.transform.apply(this.ctx, this.current.textMatrix); |
|
|
|
|
this.ctx.scale(1, -1); |
|
|
|
|
this.ctx.translate(0, -2 * this.current.y); |
|
|
|
|
this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); |
|
|
|
|
this.current.x += this.ctx.measureText(text).width; |
|
|
|
|
|
|
|
|
@ -2674,6 +2752,10 @@ var CanvasGraphics = (function() {
@@ -2674,6 +2752,10 @@ var CanvasGraphics = (function() {
|
|
|
|
|
}, |
|
|
|
|
setFillColorSpace: function(space) { |
|
|
|
|
// TODO real impl
|
|
|
|
|
if (space.name === "Pattern") |
|
|
|
|
this.current.colorSpace = "Pattern"; |
|
|
|
|
else |
|
|
|
|
this.current.colorSpace = "DeviceRGB"; |
|
|
|
|
}, |
|
|
|
|
setStrokeColor: function(/*...*/) { |
|
|
|
|
// TODO real impl
|
|
|
|
@ -2697,7 +2779,125 @@ var CanvasGraphics = (function() {
@@ -2697,7 +2779,125 @@ var CanvasGraphics = (function() {
|
|
|
|
|
}, |
|
|
|
|
setFillColorN: function(/*...*/) { |
|
|
|
|
// TODO real impl
|
|
|
|
|
this.setFillColor.apply(this, arguments); |
|
|
|
|
var colorSpace = this.current.colorSpace; |
|
|
|
|
if (!colorSpace) { |
|
|
|
|
var stateStack = this.stateStack; |
|
|
|
|
var i = stateStack.length - 1; |
|
|
|
|
while (!colorSpace && i >= 0) { |
|
|
|
|
colorSpace = stateStack[i--].colorSpace; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (this.current.colorSpace == "Pattern") { |
|
|
|
|
var patternName = arguments[0]; |
|
|
|
|
if (IsName(patternName)) { |
|
|
|
|
var xref = this.xref; |
|
|
|
|
var patternRes = xref.fetchIfRef(this.res.get("Pattern")); |
|
|
|
|
if (!patternRes) |
|
|
|
|
error("Unable to find pattern resource"); |
|
|
|
|
|
|
|
|
|
var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); |
|
|
|
|
|
|
|
|
|
const types = [null, this.tilingFill]; |
|
|
|
|
var typeNum = pattern.dict.get("PatternType"); |
|
|
|
|
var patternFn = types[typeNum]; |
|
|
|
|
if (!patternFn) |
|
|
|
|
error("Unhandled pattern type"); |
|
|
|
|
patternFn.call(this, pattern); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// TODO real impl
|
|
|
|
|
this.setFillColor.apply(this, arguments); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
tilingFill: function(pattern) { |
|
|
|
|
function applyMatrix(point, m) { |
|
|
|
|
var x = point[0] * m[0] + point[1] * m[2] + m[4]; |
|
|
|
|
var y = point[0] * m[1] + point[1] * m[3] + m[5]; |
|
|
|
|
return [x,y]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
function multiply(m, tm) { |
|
|
|
|
var a = m[0] * tm[0] + m[1] * tm[2]; |
|
|
|
|
var b = m[0] * tm[1] + m[1] * tm[3]; |
|
|
|
|
var c = m[2] * tm[0] + m[3] * tm[2]; |
|
|
|
|
var d = m[2] * tm[1] + m[3] * tm[3]; |
|
|
|
|
var e = m[4] * tm[0] + m[5] * tm[2] + tm[4]; |
|
|
|
|
var f = m[4] * tm[1] + m[5] * tm[3] + tm[5]; |
|
|
|
|
return [a, b, c, d, e, f] |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
this.save(); |
|
|
|
|
var dict = pattern.dict; |
|
|
|
|
var ctx = this.ctx; |
|
|
|
|
|
|
|
|
|
var paintType = dict.get("PaintType"); |
|
|
|
|
switch (paintType) { |
|
|
|
|
case PAINT_TYPE_COLORED: |
|
|
|
|
// should go to default for color space
|
|
|
|
|
ctx.fillStyle = this.makeCssRgb(1, 1, 1); |
|
|
|
|
ctx.strokeStyle = this.makeCssRgb(0, 0, 0); |
|
|
|
|
break; |
|
|
|
|
case PAINT_TYPE_UNCOLORED: |
|
|
|
|
default: |
|
|
|
|
error("Unsupported paint type"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TODO("TilingType"); |
|
|
|
|
|
|
|
|
|
var matrix = dict.get("Matrix") || IDENTITY_MATRIX; |
|
|
|
|
|
|
|
|
|
var bbox = dict.get("BBox"); |
|
|
|
|
var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; |
|
|
|
|
|
|
|
|
|
var xstep = dict.get("XStep"); |
|
|
|
|
var ystep = dict.get("YStep"); |
|
|
|
|
|
|
|
|
|
// top left corner should correspond to the top left of the bbox
|
|
|
|
|
var topLeft = applyMatrix([x0,y0], matrix); |
|
|
|
|
// we want the canvas to be as large as the step size
|
|
|
|
|
var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix); |
|
|
|
|
|
|
|
|
|
var tmpCanvas = document.createElement("canvas"); |
|
|
|
|
tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]); |
|
|
|
|
tmpCanvas.height = Math.ceil(botRight[1] - topLeft[1]); |
|
|
|
|
|
|
|
|
|
// set the new canvas element context as the graphics context
|
|
|
|
|
var tmpCtx = tmpCanvas.getContext("2d"); |
|
|
|
|
var savedCtx = ctx; |
|
|
|
|
this.ctx = tmpCtx; |
|
|
|
|
|
|
|
|
|
// normalize transform matrix so each step
|
|
|
|
|
// takes up the entire tmpCanvas (need to remove white borders)
|
|
|
|
|
if (matrix[1] === 0 && matrix[2] === 0) { |
|
|
|
|
matrix[0] = tmpCanvas.width / xstep; |
|
|
|
|
matrix[3] = tmpCanvas.height / ystep; |
|
|
|
|
topLeft = applyMatrix([x0,y0], matrix); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// move the top left corner of bounding box to [0,0]
|
|
|
|
|
matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]); |
|
|
|
|
|
|
|
|
|
this.transform.apply(this, matrix); |
|
|
|
|
|
|
|
|
|
if (bbox && IsArray(bbox) && 4 == bbox.length) { |
|
|
|
|
this.rectangle.apply(this, bbox); |
|
|
|
|
this.clip(); |
|
|
|
|
this.endPath(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var xref = this.xref; |
|
|
|
|
var res = xref.fetchIfRef(dict.get("Resources")); |
|
|
|
|
if (!pattern.code) |
|
|
|
|
pattern.code = this.compile(pattern, xref, res, []); |
|
|
|
|
this.execute(pattern.code, xref, res); |
|
|
|
|
|
|
|
|
|
this.ctx = savedCtx; |
|
|
|
|
this.restore(); |
|
|
|
|
|
|
|
|
|
TODO("Inverse pattern is painted"); |
|
|
|
|
var pattern = this.ctx.createPattern(tmpCanvas, "repeat"); |
|
|
|
|
this.ctx.fillStyle = pattern; |
|
|
|
|
}, |
|
|
|
|
setStrokeGray: function(gray) { |
|
|
|
|
this.setStrokeRGBColor(gray, gray, gray); |
|
|
|
@ -2787,8 +2987,8 @@ var CanvasGraphics = (function() {
@@ -2787,8 +2987,8 @@ var CanvasGraphics = (function() {
|
|
|
|
|
var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); |
|
|
|
|
|
|
|
|
|
// 10 samples seems good enough for now, but probably won't work
|
|
|
|
|
// if there are sharp color changes. Ideally, we could see the
|
|
|
|
|
// current image size and base the # samples on that.
|
|
|
|
|
// if there are sharp color changes. Ideally, we would implement
|
|
|
|
|
// the spec faithfully and add lossless optimizations.
|
|
|
|
|
var step = (t1 - t0) / 10; |
|
|
|
|
|
|
|
|
|
for (var i = t0; i <= t1; i += step) { |
|
|
|
@ -2801,8 +3001,8 @@ var CanvasGraphics = (function() {
@@ -2801,8 +3001,8 @@ var CanvasGraphics = (function() {
|
|
|
|
|
// HACK to draw the gradient onto an infinite rectangle.
|
|
|
|
|
// PDF gradients are drawn across the entire image while
|
|
|
|
|
// Canvas only allows gradients to be drawn in a rectangle
|
|
|
|
|
// Also, larger numbers seem to cause overflow which causes
|
|
|
|
|
// nothing to be drawn.
|
|
|
|
|
// The following bug should allow us to remove this.
|
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=664884
|
|
|
|
|
this.ctx.fillRect(-1e10, -1e10, 2e10, 2e10); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
@ -2884,8 +3084,20 @@ var CanvasGraphics = (function() {
@@ -2884,8 +3084,20 @@ var CanvasGraphics = (function() {
|
|
|
|
|
error("Invalid image width or height"); |
|
|
|
|
|
|
|
|
|
var ctx = this.ctx; |
|
|
|
|
|
|
|
|
|
// scale the image to the unit square
|
|
|
|
|
ctx.scale(1/w, 1/h); |
|
|
|
|
ctx.scale(1/w, -1/h); |
|
|
|
|
|
|
|
|
|
// If the platform can render the image format directly, the
|
|
|
|
|
// stream has a getImage property which directly returns a
|
|
|
|
|
// suitable DOM Image object.
|
|
|
|
|
if (image.getImage) { |
|
|
|
|
var domImage = image.getImage(); |
|
|
|
|
ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, |
|
|
|
|
0, -h, w, h); |
|
|
|
|
this.restore(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var interpolate = dict.get2("Interpolate", "I"); |
|
|
|
|
if (!IsBool(interpolate)) |
|
|
|
@ -2989,7 +3201,7 @@ var CanvasGraphics = (function() {
@@ -2989,7 +3201,7 @@ var CanvasGraphics = (function() {
|
|
|
|
|
switch (numComps) { |
|
|
|
|
case 1: |
|
|
|
|
for (var i = 0; i < length; i += 4) { |
|
|
|
|
var p = imgArray[imageIdx++]; |
|
|
|
|
var p = imgArray[imgIdx++]; |
|
|
|
|
pixels[i] = p; |
|
|
|
|
pixels[i+1] = p; |
|
|
|
|
pixels[i+2] = p; |
|
|
|
@ -3016,7 +3228,7 @@ var CanvasGraphics = (function() {
@@ -3016,7 +3228,7 @@ var CanvasGraphics = (function() {
|
|
|
|
|
switch (numComps) { |
|
|
|
|
case 1: |
|
|
|
|
for (var i = 0; i < length; i += 4) { |
|
|
|
|
var p = imgArray[imageIdx++]; |
|
|
|
|
var p = imgArray[imgIdx++]; |
|
|
|
|
pixels[i] = p; |
|
|
|
|
pixels[i+1] = p; |
|
|
|
|
pixels[i+2] = p; |
|
|
|
@ -3036,7 +3248,7 @@ var CanvasGraphics = (function() {
@@ -3036,7 +3248,7 @@ var CanvasGraphics = (function() {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
tmpCtx.putImageData(imgData, 0, 0); |
|
|
|
|
ctx.drawImage(tmpCanvas, 0, 0); |
|
|
|
|
ctx.drawImage(tmpCanvas, 0, -h); |
|
|
|
|
this.restore(); |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|