Merge pull request #10031 from Snuffleupagus/JPEG-CMYK-invert

Add a new parameter to `JpegImage.getData` to indicate the source of the image data (issue 9513)
This commit is contained in:
Tim van der Meij 2018-09-02 15:15:26 +02:00 committed by GitHub
commit d409c42068
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 14 deletions

View File

@ -58,7 +58,11 @@ var jpegImage = new pdfjsImageDecoders.JpegImage();
jpegImage.parse(typedArrayImage);
var width = jpegImage.width, height = jpegImage.height;
var jpegData = jpegImage.getData(width, height, /* forceRGB = */ true);
var jpegData = jpegImage.getData({
width,
height,
forceRGB: true,
});
// Render the JPEG image on a <canvas>.
//

View File

@ -97,8 +97,12 @@ let JpegStream = (function JpegStreamClosure() {
const jpegImage = new JpegImage(jpegOptions);
jpegImage.parse(this.bytes);
let data = jpegImage.getData(this.drawWidth, this.drawHeight,
this.forceRGB);
let data = jpegImage.getData({
width: this.drawWidth,
height: this.drawHeight,
forceRGB: this.forceRGB,
isSourcePDF: true,
});
this.buffer = data;
this.bufferLength = data.length;
this.eof = true;

View File

@ -975,7 +975,7 @@ var JpegImage = (function JpegImageClosure() {
this.numComponents = this.components.length;
},
_getLinearizedBlockData: function getLinearizedBlockData(width, height) {
_getLinearizedBlockData(width, height, isSourcePDF = false) {
var scaleX = this.width / width, scaleY = this.height / height;
var component, componentScaleX, componentScaleY, blocksPerScanline;
@ -1013,7 +1013,24 @@ var JpegImage = (function JpegImageClosure() {
}
// decodeTransform contains pairs of multiplier (-256..256) and additive
const transform = this._decodeTransform;
let transform = this._decodeTransform;
// In PDF files, JPEG images with CMYK colour spaces are usually inverted
// (this can be observed by extracting the raw image data).
// Since the conversion algorithms (see below) were written primarily for
// the PDF use-cases, attempting to use `JpegImage` to parse standalone
// JPEG (CMYK) images may thus result in inverted images (see issue 9513).
//
// Unfortunately it's not (always) possible to tell, from the image data
// alone, if it needs to be inverted. Thus in an attempt to provide better
// out-of-box behaviour when `JpegImage` is used standalone, default to
// inverting JPEG (CMYK) images if and only if the image data does *not*
// come from a PDF file and no `decodeTransform` was passed by the user.
if (!transform && numComponents === 4 && !isSourcePDF) {
transform = new Int32Array([
-256, 255, -256, 255, -256, 255, -256, 255]);
}
if (transform) {
for (i = 0; i < dataLength;) {
for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
@ -1024,7 +1041,7 @@ var JpegImage = (function JpegImageClosure() {
return data;
},
_isColorConversionNeeded() {
get _isColorConversionNeeded() {
if (this.adobe) {
// The adobe transform marker overrides any previous setting.
return !!this.adobe.transformCode;
@ -1162,14 +1179,14 @@ var JpegImage = (function JpegImageClosure() {
return data.subarray(0, offset);
},
getData: function getData(width, height, forceRGBoutput) {
getData({ width, height, forceRGB = false, isSourcePDF = false, }) {
if (this.numComponents > 4) {
throw new JpegError('Unsupported color mode');
}
// type of data: Uint8Array(width * height * numComponents)
var data = this._getLinearizedBlockData(width, height);
// Type of data: Uint8ClampedArray(width * height * numComponents)
var data = this._getLinearizedBlockData(width, height, isSourcePDF);
if (this.numComponents === 1 && forceRGBoutput) {
if (this.numComponents === 1 && forceRGB) {
var dataLength = data.length;
var rgbData = new Uint8ClampedArray(dataLength * 3);
var offset = 0;
@ -1180,15 +1197,15 @@ var JpegImage = (function JpegImageClosure() {
rgbData[offset++] = grayColor;
}
return rgbData;
} else if (this.numComponents === 3 && this._isColorConversionNeeded()) {
} else if (this.numComponents === 3 && this._isColorConversionNeeded) {
return this._convertYccToRgb(data);
} else if (this.numComponents === 4) {
if (this._isColorConversionNeeded()) {
if (forceRGBoutput) {
if (this._isColorConversionNeeded) {
if (forceRGB) {
return this._convertYcckToRgb(data);
}
return this._convertYcckToCmyk(data);
} else if (forceRGBoutput) {
} else if (forceRGB) {
return this._convertCmykToRgb(data);
}
}