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:
commit
d409c42068
@ -58,7 +58,11 @@ var jpegImage = new pdfjsImageDecoders.JpegImage();
|
|||||||
jpegImage.parse(typedArrayImage);
|
jpegImage.parse(typedArrayImage);
|
||||||
|
|
||||||
var width = jpegImage.width, height = jpegImage.height;
|
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>.
|
// Render the JPEG image on a <canvas>.
|
||||||
//
|
//
|
||||||
|
@ -97,8 +97,12 @@ let JpegStream = (function JpegStreamClosure() {
|
|||||||
const jpegImage = new JpegImage(jpegOptions);
|
const jpegImage = new JpegImage(jpegOptions);
|
||||||
|
|
||||||
jpegImage.parse(this.bytes);
|
jpegImage.parse(this.bytes);
|
||||||
let data = jpegImage.getData(this.drawWidth, this.drawHeight,
|
let data = jpegImage.getData({
|
||||||
this.forceRGB);
|
width: this.drawWidth,
|
||||||
|
height: this.drawHeight,
|
||||||
|
forceRGB: this.forceRGB,
|
||||||
|
isSourcePDF: true,
|
||||||
|
});
|
||||||
this.buffer = data;
|
this.buffer = data;
|
||||||
this.bufferLength = data.length;
|
this.bufferLength = data.length;
|
||||||
this.eof = true;
|
this.eof = true;
|
||||||
|
@ -975,7 +975,7 @@ var JpegImage = (function JpegImageClosure() {
|
|||||||
this.numComponents = this.components.length;
|
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 scaleX = this.width / width, scaleY = this.height / height;
|
||||||
|
|
||||||
var component, componentScaleX, componentScaleY, blocksPerScanline;
|
var component, componentScaleX, componentScaleY, blocksPerScanline;
|
||||||
@ -1013,7 +1013,24 @@ var JpegImage = (function JpegImageClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decodeTransform contains pairs of multiplier (-256..256) and additive
|
// 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) {
|
if (transform) {
|
||||||
for (i = 0; i < dataLength;) {
|
for (i = 0; i < dataLength;) {
|
||||||
for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
|
for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
|
||||||
@ -1024,7 +1041,7 @@ var JpegImage = (function JpegImageClosure() {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|
||||||
_isColorConversionNeeded() {
|
get _isColorConversionNeeded() {
|
||||||
if (this.adobe) {
|
if (this.adobe) {
|
||||||
// The adobe transform marker overrides any previous setting.
|
// The adobe transform marker overrides any previous setting.
|
||||||
return !!this.adobe.transformCode;
|
return !!this.adobe.transformCode;
|
||||||
@ -1162,14 +1179,14 @@ var JpegImage = (function JpegImageClosure() {
|
|||||||
return data.subarray(0, offset);
|
return data.subarray(0, offset);
|
||||||
},
|
},
|
||||||
|
|
||||||
getData: function getData(width, height, forceRGBoutput) {
|
getData({ width, height, forceRGB = false, isSourcePDF = false, }) {
|
||||||
if (this.numComponents > 4) {
|
if (this.numComponents > 4) {
|
||||||
throw new JpegError('Unsupported color mode');
|
throw new JpegError('Unsupported color mode');
|
||||||
}
|
}
|
||||||
// type of data: Uint8Array(width * height * numComponents)
|
// Type of data: Uint8ClampedArray(width * height * numComponents)
|
||||||
var data = this._getLinearizedBlockData(width, height);
|
var data = this._getLinearizedBlockData(width, height, isSourcePDF);
|
||||||
|
|
||||||
if (this.numComponents === 1 && forceRGBoutput) {
|
if (this.numComponents === 1 && forceRGB) {
|
||||||
var dataLength = data.length;
|
var dataLength = data.length;
|
||||||
var rgbData = new Uint8ClampedArray(dataLength * 3);
|
var rgbData = new Uint8ClampedArray(dataLength * 3);
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
@ -1180,15 +1197,15 @@ var JpegImage = (function JpegImageClosure() {
|
|||||||
rgbData[offset++] = grayColor;
|
rgbData[offset++] = grayColor;
|
||||||
}
|
}
|
||||||
return rgbData;
|
return rgbData;
|
||||||
} else if (this.numComponents === 3 && this._isColorConversionNeeded()) {
|
} else if (this.numComponents === 3 && this._isColorConversionNeeded) {
|
||||||
return this._convertYccToRgb(data);
|
return this._convertYccToRgb(data);
|
||||||
} else if (this.numComponents === 4) {
|
} else if (this.numComponents === 4) {
|
||||||
if (this._isColorConversionNeeded()) {
|
if (this._isColorConversionNeeded) {
|
||||||
if (forceRGBoutput) {
|
if (forceRGB) {
|
||||||
return this._convertYcckToRgb(data);
|
return this._convertYcckToRgb(data);
|
||||||
}
|
}
|
||||||
return this._convertYcckToCmyk(data);
|
return this._convertYcckToCmyk(data);
|
||||||
} else if (forceRGBoutput) {
|
} else if (forceRGB) {
|
||||||
return this._convertCmykToRgb(data);
|
return this._convertCmykToRgb(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user