Fix where image component decoding takes place.
This commit is contained in:
parent
f627281626
commit
93b99e7352
93
src/image.js
93
src/image.js
@ -49,7 +49,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
// Clamp the value to the range
|
||||
return value < 0 ? 0 : value > max ? max : value;
|
||||
}
|
||||
function PDFImage(xref, res, image, inline, smask, mask) {
|
||||
function PDFImage(xref, res, image, inline, smask, mask, isMask) {
|
||||
this.image = image;
|
||||
if (image.getParams) {
|
||||
// JPX/JPEG2000 streams directly contain bits per component
|
||||
@ -95,8 +95,9 @@ var PDFImage = (function PDFImageClosure() {
|
||||
|
||||
this.decode = dict.get('Decode', 'D');
|
||||
this.needsDecode = false;
|
||||
if (this.decode && this.colorSpace &&
|
||||
!this.colorSpace.isDefaultDecode(this.decode)) {
|
||||
if (this.decode &&
|
||||
((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||
|
||||
(isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {
|
||||
this.needsDecode = true;
|
||||
// Do some preprocessing to avoid more math.
|
||||
var max = (1 << bitsPerComponent) - 1;
|
||||
@ -114,7 +115,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
this.smask = new PDFImage(xref, res, smask, false);
|
||||
} else if (mask) {
|
||||
if (isStream(mask)) {
|
||||
this.mask = new PDFImage(xref, res, mask, false);
|
||||
this.mask = new PDFImage(xref, res, mask, false, null, null, true);
|
||||
} else {
|
||||
// Color key mask (just an array).
|
||||
this.mask = mask;
|
||||
@ -216,13 +217,37 @@ var PDFImage = (function PDFImageClosure() {
|
||||
return this.height;
|
||||
return Math.max(this.height, this.smask.height);
|
||||
},
|
||||
decodeBuffer: function PDFImage_decodeBuffer(buffer) {
|
||||
var bpc = this.bpc;
|
||||
var decodeMap = this.decode;
|
||||
var numComps = this.numComps;
|
||||
|
||||
var decodeAddends, decodeCoefficients;
|
||||
var decodeAddends = this.decodeAddends;
|
||||
var decodeCoefficients = this.decodeCoefficients;
|
||||
var max = (1 << bpc) - 1;
|
||||
|
||||
if (bpc === 1) {
|
||||
// If the buffer needed decode that means it just needs to be inverted.
|
||||
for (var i = 0, ii = buffer.length; i < ii; i++) {
|
||||
buffer[i] = +!(buffer[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var index = 0;
|
||||
for (var i = 0, ii = this.width * this.height; i < ii; i++) {
|
||||
for (var j = 0; j < numComps; j++) {
|
||||
buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
|
||||
decodeCoefficients[j], max);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
},
|
||||
getComponents: function PDFImage_getComponents(buffer) {
|
||||
var bpc = this.bpc;
|
||||
var needsDecode = this.needsDecode;
|
||||
var decodeMap = this.decode;
|
||||
|
||||
// This image doesn't require any extra work.
|
||||
if (bpc == 8 && !needsDecode)
|
||||
if (bpc === 8)
|
||||
return buffer;
|
||||
|
||||
var bufferLength = buffer.length;
|
||||
@ -235,29 +260,11 @@ var PDFImage = (function PDFImageClosure() {
|
||||
var output = bpc <= 8 ? new Uint8Array(length) :
|
||||
bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
|
||||
var rowComps = width * numComps;
|
||||
var decodeAddends, decodeCoefficients;
|
||||
if (needsDecode) {
|
||||
decodeAddends = this.decodeAddends;
|
||||
decodeCoefficients = this.decodeCoefficients;
|
||||
}
|
||||
|
||||
var max = (1 << bpc) - 1;
|
||||
|
||||
if (bpc == 8) {
|
||||
// Optimization for reading 8 bpc images that have a decode.
|
||||
for (var i = 0, ii = length; i < ii; ++i) {
|
||||
var compIndex = i % numComps;
|
||||
var value = buffer[i];
|
||||
value = decodeAndClamp(value, decodeAddends[compIndex],
|
||||
decodeCoefficients[compIndex], max);
|
||||
output[i] = value;
|
||||
}
|
||||
} else if (bpc == 1) {
|
||||
if (bpc === 1) {
|
||||
// Optimization for reading 1 bpc images.
|
||||
var valueZero = 0, valueOne = 1;
|
||||
if (decodeMap) {
|
||||
valueZero = decodeMap[0] ? 1 : 0;
|
||||
valueOne = decodeMap[1] ? 1 : 0;
|
||||
}
|
||||
var mask = 0;
|
||||
var buf = 0;
|
||||
|
||||
@ -274,7 +281,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
mask = 128;
|
||||
}
|
||||
|
||||
output[i] = !(buf & mask) ? valueZero : valueOne;
|
||||
output[i] = +!!(buf & mask);
|
||||
}
|
||||
} else {
|
||||
// The general case that handles all other bpc values.
|
||||
@ -292,12 +299,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
|
||||
var remainingBits = bits - bpc;
|
||||
var value = buf >> remainingBits;
|
||||
if (needsDecode) {
|
||||
var compIndex = i % numComps;
|
||||
value = decodeAndClamp(value, decodeAddends[compIndex],
|
||||
decodeCoefficients[compIndex], max);
|
||||
}
|
||||
output[i] = value;
|
||||
output[i] = value < 0 ? 0 : value > max ? max : value;
|
||||
buf = buf & ((1 << remainingBits) - 1);
|
||||
bits = remainingBits;
|
||||
}
|
||||
@ -397,21 +399,27 @@ var PDFImage = (function PDFImageClosure() {
|
||||
// imgArray can be incomplete (e.g. after CCITT fax encoding)
|
||||
var actualHeight = 0 | (imgArray.length / rowBytes *
|
||||
height / originalHeight);
|
||||
var comps = this.getComponents(imgArray);
|
||||
// Build opacity here since color key masking needs to be perormed on
|
||||
// undecoded values.
|
||||
var opacity = this.getOpacity(width, height, comps);
|
||||
|
||||
var comps = this.colorSpace.createRgbBuffer(this.getComponents(imgArray),
|
||||
0, originalWidth * originalHeight, bpc);
|
||||
if (this.needsDecode) {
|
||||
this.decodeBuffer(comps);
|
||||
}
|
||||
var rgbBuf = this.colorSpace.createRgbBuffer(comps, 0,
|
||||
originalWidth * originalHeight, bpc);
|
||||
if (originalWidth != width || originalHeight != height)
|
||||
comps = PDFImage.resize(comps, this.bpc, 3, originalWidth,
|
||||
rgbBuf = PDFImage.resize(rgbBuf, this.bpc, 3, originalWidth,
|
||||
originalHeight, width, height);
|
||||
var compsPos = 0;
|
||||
var opacity = this.getOpacity(width, height, imgArray);
|
||||
var opacityPos = 0;
|
||||
var length = width * actualHeight * 4;
|
||||
|
||||
for (var i = 0; i < length; i += 4) {
|
||||
buffer[i] = comps[compsPos++];
|
||||
buffer[i + 1] = comps[compsPos++];
|
||||
buffer[i + 2] = comps[compsPos++];
|
||||
buffer[i] = rgbBuf[compsPos++];
|
||||
buffer[i + 1] = rgbBuf[compsPos++];
|
||||
buffer[i + 2] = rgbBuf[compsPos++];
|
||||
buffer[i + 3] = opacity[opacityPos++];
|
||||
}
|
||||
},
|
||||
@ -429,6 +437,9 @@ var PDFImage = (function PDFImageClosure() {
|
||||
var imgArray = this.getImageBytes(height * rowBytes);
|
||||
|
||||
var comps = this.getComponents(imgArray);
|
||||
if (this.needsDecode) {
|
||||
this.decodeBuffer(comps);
|
||||
}
|
||||
var length = width * height;
|
||||
// we aren't using a colorspace so we need to scale the value
|
||||
var scale = 255 / ((1 << bpc) - 1);
|
||||
|
1
test/pdfs/issue2770.pdf.link
Normal file
1
test/pdfs/issue2770.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
https://bugzilla.mozilla.org/attachment.cgi?id=718826
|
@ -971,6 +971,14 @@
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue2770",
|
||||
"file": "pdfs/issue2770.pdf",
|
||||
"md5": "36070d756d06eaa35c2227efb069fb1b",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq",
|
||||
"about": "Has a 4 bit per component image with mask and decode."
|
||||
},
|
||||
{ "id": "p020121130574743273239",
|
||||
"file": "pdfs/P020121130574743273239.pdf",
|
||||
"md5": "271b65885d42d174cbc597ca89becb1a",
|
||||
|
Loading…
Reference in New Issue
Block a user