2012-09-01 07:48:21 +09:00
|
|
|
/* Copyright 2012 Mozilla Foundation
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2011-10-26 10:18:22 +09:00
|
|
|
|
2017-09-02 03:27:13 +09:00
|
|
|
import { assert, FormatError, ImageKind, info, warn } from '../shared/util';
|
2017-04-02 23:14:30 +09:00
|
|
|
import { isStream, Name } from './primitives';
|
|
|
|
import { ColorSpace } from './colorspace';
|
2017-10-26 20:00:09 +09:00
|
|
|
import { DecodeStream } from './stream';
|
|
|
|
import { JpegStream } from './jpeg_stream';
|
2017-04-02 23:14:30 +09:00
|
|
|
import { JpxImage } from './jpx';
|
2015-11-22 01:32:47 +09:00
|
|
|
|
2011-12-09 07:18:43 +09:00
|
|
|
var PDFImage = (function PDFImageClosure() {
|
2011-12-12 09:56:45 +09:00
|
|
|
/**
|
2016-04-01 21:36:16 +09:00
|
|
|
* Decodes the image using native decoder if possible. Resolves the promise
|
2011-12-12 09:56:45 +09:00
|
|
|
* when the image data is ready.
|
|
|
|
*/
|
2016-04-01 21:36:16 +09:00
|
|
|
function handleImageData(image, nativeDecoder) {
|
|
|
|
if (nativeDecoder && nativeDecoder.canDecode(image)) {
|
2018-02-01 23:32:09 +09:00
|
|
|
return nativeDecoder.decode(image).catch((reason) => {
|
|
|
|
warn('Native image decoding failed -- trying to recover: ' +
|
|
|
|
(reason && reason.message));
|
|
|
|
return image;
|
|
|
|
});
|
2011-12-12 09:56:45 +09:00
|
|
|
}
|
2016-12-16 21:05:33 +09:00
|
|
|
return Promise.resolve(image);
|
2011-12-12 09:56:45 +09:00
|
|
|
}
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2011-12-14 06:53:22 +09:00
|
|
|
/**
|
2011-12-14 07:35:46 +09:00
|
|
|
* Decode and clamp a value. The formula is different from the spec because we
|
|
|
|
* don't decode to float range [0,1], we decode it in the [0,max] range.
|
2011-12-14 06:53:22 +09:00
|
|
|
*/
|
2011-12-14 07:35:46 +09:00
|
|
|
function decodeAndClamp(value, addend, coefficient, max) {
|
2011-12-14 06:53:22 +09:00
|
|
|
value = addend + value * coefficient;
|
|
|
|
// Clamp the value to the range
|
2014-03-21 04:28:22 +09:00
|
|
|
return (value < 0 ? 0 : (value > max ? max : value));
|
2011-12-14 06:53:22 +09:00
|
|
|
}
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2016-04-17 03:07:35 +09:00
|
|
|
/**
|
|
|
|
* Resizes an image mask with 1 component.
|
|
|
|
* @param {TypedArray} src - The source buffer.
|
|
|
|
* @param {Number} bpc - Number of bits per component.
|
|
|
|
* @param {Number} w1 - Original width.
|
|
|
|
* @param {Number} h1 - Original height.
|
|
|
|
* @param {Number} w2 - New width.
|
|
|
|
* @param {Number} h2 - New height.
|
|
|
|
* @returns {TypedArray} The resized image mask buffer.
|
|
|
|
*/
|
|
|
|
function resizeImageMask(src, bpc, w1, h1, w2, h2) {
|
|
|
|
var length = w2 * h2;
|
|
|
|
var dest = (bpc <= 8 ? new Uint8Array(length) :
|
|
|
|
(bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
|
|
|
|
var xRatio = w1 / w2;
|
|
|
|
var yRatio = h1 / h2;
|
|
|
|
var i, j, py, newIndex = 0, oldIndex;
|
|
|
|
var xScaled = new Uint16Array(w2);
|
|
|
|
var w1Scanline = w1;
|
|
|
|
|
|
|
|
for (i = 0; i < w2; i++) {
|
|
|
|
xScaled[i] = Math.floor(i * xRatio);
|
|
|
|
}
|
|
|
|
for (i = 0; i < h2; i++) {
|
|
|
|
py = Math.floor(i * yRatio) * w1Scanline;
|
|
|
|
for (j = 0; j < w2; j++) {
|
|
|
|
oldIndex = py + xScaled[j];
|
|
|
|
dest[newIndex++] = src[oldIndex];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dest;
|
|
|
|
}
|
|
|
|
|
Attempt to actually resolve ColourSpace names in accordance with the specification (issue 9285)
Please refer to the PDF specification, in particular http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3801570
> A colour space shall be specified in one of two ways:
> - Within a content stream, the CS or cs operator establishes the current colour space parameter in the graphics state. The operand shall always be name object, which either identifies one of the colour spaces that need no additional parameters (DeviceGray, DeviceRGB, DeviceCMYK, or some cases of Pattern) or shall be used as a key in the ColorSpace subdictionary of the current resource dictionary (see 7.8.3, "Resource Dictionaries"). In the latter case, the value of the dictionary entry in turn shall be a colour space array or name. A colour space array shall never be inline within a content stream.
>
> - Outside a content stream, certain objects, such as image XObjects, shall specify a colour space as an explicit parameter, often associated with the key ColorSpace. In this case, the colour space array or name shall always be defined directly as a PDF object, not by an entry in the ColorSpace resource subdictionary. This convention also applies when colour spaces are defined in terms of other colour spaces.
2017-12-20 23:35:04 +09:00
|
|
|
function PDFImage({ xref, res, image, isInline = false, smask = null,
|
|
|
|
mask = null, isMask = false, pdfFunctionFactory, }) {
|
2011-10-25 08:55:23 +09:00
|
|
|
this.image = image;
|
2014-04-06 00:27:18 +09:00
|
|
|
var dict = image.dict;
|
2014-04-06 19:08:04 +09:00
|
|
|
if (dict.has('Filter')) {
|
|
|
|
var filter = dict.get('Filter').name;
|
|
|
|
if (filter === 'JPXDecode') {
|
|
|
|
var jpxImage = new JpxImage();
|
|
|
|
jpxImage.parseImageProperties(image.stream);
|
|
|
|
image.stream.reset();
|
|
|
|
image.bitsPerComponent = jpxImage.bitsPerComponent;
|
|
|
|
image.numComps = jpxImage.componentsCount;
|
|
|
|
} else if (filter === 'JBIG2Decode') {
|
|
|
|
image.bitsPerComponent = 1;
|
|
|
|
image.numComps = 1;
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
// TODO cache rendered images?
|
|
|
|
|
|
|
|
this.width = dict.get('Width', 'W');
|
|
|
|
this.height = dict.get('Height', 'H');
|
|
|
|
|
2014-03-05 17:42:16 +09:00
|
|
|
if (this.width < 1 || this.height < 1) {
|
2017-06-29 05:51:31 +09:00
|
|
|
throw new FormatError(`Invalid image width: ${this.width} or ` +
|
|
|
|
`height: ${this.height}`);
|
2014-03-05 17:42:16 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
|
|
|
|
this.interpolate = dict.get('Interpolate', 'I') || false;
|
|
|
|
this.imageMask = dict.get('ImageMask', 'IM') || false;
|
2013-07-03 04:27:06 +09:00
|
|
|
this.matte = dict.get('Matte') || false;
|
2011-10-25 08:55:23 +09:00
|
|
|
|
|
|
|
var bitsPerComponent = image.bitsPerComponent;
|
|
|
|
if (!bitsPerComponent) {
|
|
|
|
bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
|
|
|
|
if (!bitsPerComponent) {
|
2014-03-05 17:42:16 +09:00
|
|
|
if (this.imageMask) {
|
2011-10-25 08:55:23 +09:00
|
|
|
bitsPerComponent = 1;
|
2014-03-05 17:42:16 +09:00
|
|
|
} else {
|
2017-06-29 05:51:31 +09:00
|
|
|
throw new FormatError(
|
|
|
|
`Bits per component missing in image: ${this.imageMask}`);
|
2014-03-05 17:42:16 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
this.bpc = bitsPerComponent;
|
|
|
|
|
|
|
|
if (!this.imageMask) {
|
|
|
|
var colorSpace = dict.get('ColorSpace', 'CS');
|
|
|
|
if (!colorSpace) {
|
2014-04-06 00:27:18 +09:00
|
|
|
info('JPX images (which do not require color spaces)');
|
|
|
|
switch (image.numComps) {
|
|
|
|
case 1:
|
|
|
|
colorSpace = Name.get('DeviceGray');
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
colorSpace = Name.get('DeviceRGB');
|
|
|
|
break;
|
2014-04-20 02:34:42 +09:00
|
|
|
case 4:
|
|
|
|
colorSpace = Name.get('DeviceCMYK');
|
|
|
|
break;
|
2014-04-06 00:27:18 +09:00
|
|
|
default:
|
2017-06-29 05:51:31 +09:00
|
|
|
throw new Error(`JPX images with ${this.numComps} ` +
|
|
|
|
'color components not supported.');
|
2014-04-06 00:27:18 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
Attempt to actually resolve ColourSpace names in accordance with the specification (issue 9285)
Please refer to the PDF specification, in particular http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3801570
> A colour space shall be specified in one of two ways:
> - Within a content stream, the CS or cs operator establishes the current colour space parameter in the graphics state. The operand shall always be name object, which either identifies one of the colour spaces that need no additional parameters (DeviceGray, DeviceRGB, DeviceCMYK, or some cases of Pattern) or shall be used as a key in the ColorSpace subdictionary of the current resource dictionary (see 7.8.3, "Resource Dictionaries"). In the latter case, the value of the dictionary entry in turn shall be a colour space array or name. A colour space array shall never be inline within a content stream.
>
> - Outside a content stream, certain objects, such as image XObjects, shall specify a colour space as an explicit parameter, often associated with the key ColorSpace. In this case, the colour space array or name shall always be defined directly as a PDF object, not by an entry in the ColorSpace resource subdictionary. This convention also applies when colour spaces are defined in terms of other colour spaces.
2017-12-20 23:35:04 +09:00
|
|
|
let resources = isInline ? res : null;
|
|
|
|
this.colorSpace = ColorSpace.parse(colorSpace, xref, resources,
|
2017-09-19 20:49:30 +09:00
|
|
|
pdfFunctionFactory);
|
2011-10-25 08:55:23 +09:00
|
|
|
this.numComps = this.colorSpace.numComps;
|
|
|
|
}
|
|
|
|
|
2016-05-06 02:16:35 +09:00
|
|
|
this.decode = dict.getArray('Decode', 'D');
|
2011-12-14 07:35:46 +09:00
|
|
|
this.needsDecode = false;
|
2013-03-15 06:06:44 +09:00
|
|
|
if (this.decode &&
|
|
|
|
((this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode)) ||
|
|
|
|
(isMask && !ColorSpace.isDefaultDecode(this.decode, 1)))) {
|
2011-12-14 07:35:46 +09:00
|
|
|
this.needsDecode = true;
|
2011-12-14 06:53:22 +09:00
|
|
|
// Do some preprocessing to avoid more math.
|
|
|
|
var max = (1 << bitsPerComponent) - 1;
|
|
|
|
this.decodeCoefficients = [];
|
|
|
|
this.decodeAddends = [];
|
|
|
|
for (var i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
|
|
|
|
var dmin = this.decode[i];
|
|
|
|
var dmax = this.decode[i + 1];
|
|
|
|
this.decodeCoefficients[j] = dmax - dmin;
|
|
|
|
this.decodeAddends[j] = max * dmin;
|
|
|
|
}
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
|
2012-06-09 14:42:56 +09:00
|
|
|
if (smask) {
|
2017-09-21 19:14:05 +09:00
|
|
|
this.smask = new PDFImage({
|
|
|
|
xref,
|
|
|
|
res,
|
|
|
|
image: smask,
|
Attempt to actually resolve ColourSpace names in accordance with the specification (issue 9285)
Please refer to the PDF specification, in particular http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3801570
> A colour space shall be specified in one of two ways:
> - Within a content stream, the CS or cs operator establishes the current colour space parameter in the graphics state. The operand shall always be name object, which either identifies one of the colour spaces that need no additional parameters (DeviceGray, DeviceRGB, DeviceCMYK, or some cases of Pattern) or shall be used as a key in the ColorSpace subdictionary of the current resource dictionary (see 7.8.3, "Resource Dictionaries"). In the latter case, the value of the dictionary entry in turn shall be a colour space array or name. A colour space array shall never be inline within a content stream.
>
> - Outside a content stream, certain objects, such as image XObjects, shall specify a colour space as an explicit parameter, often associated with the key ColorSpace. In this case, the colour space array or name shall always be defined directly as a PDF object, not by an entry in the ColorSpace resource subdictionary. This convention also applies when colour spaces are defined in terms of other colour spaces.
2017-12-20 23:35:04 +09:00
|
|
|
isInline,
|
2017-09-19 20:49:30 +09:00
|
|
|
pdfFunctionFactory,
|
2017-09-21 19:14:05 +09:00
|
|
|
});
|
2012-06-09 14:42:56 +09:00
|
|
|
} else if (mask) {
|
2012-08-29 09:19:31 +09:00
|
|
|
if (isStream(mask)) {
|
2015-11-13 05:41:16 +09:00
|
|
|
var maskDict = mask.dict, imageMask = maskDict.get('ImageMask', 'IM');
|
|
|
|
if (!imageMask) {
|
|
|
|
warn('Ignoring /Mask in image without /ImageMask.');
|
|
|
|
} else {
|
2017-09-21 19:14:05 +09:00
|
|
|
this.mask = new PDFImage({
|
|
|
|
xref,
|
|
|
|
res,
|
|
|
|
image: mask,
|
Attempt to actually resolve ColourSpace names in accordance with the specification (issue 9285)
Please refer to the PDF specification, in particular http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3801570
> A colour space shall be specified in one of two ways:
> - Within a content stream, the CS or cs operator establishes the current colour space parameter in the graphics state. The operand shall always be name object, which either identifies one of the colour spaces that need no additional parameters (DeviceGray, DeviceRGB, DeviceCMYK, or some cases of Pattern) or shall be used as a key in the ColorSpace subdictionary of the current resource dictionary (see 7.8.3, "Resource Dictionaries"). In the latter case, the value of the dictionary entry in turn shall be a colour space array or name. A colour space array shall never be inline within a content stream.
>
> - Outside a content stream, certain objects, such as image XObjects, shall specify a colour space as an explicit parameter, often associated with the key ColorSpace. In this case, the colour space array or name shall always be defined directly as a PDF object, not by an entry in the ColorSpace resource subdictionary. This convention also applies when colour spaces are defined in terms of other colour spaces.
2017-12-20 23:35:04 +09:00
|
|
|
isInline,
|
2017-09-21 19:14:05 +09:00
|
|
|
isMask: true,
|
2017-09-19 20:49:30 +09:00
|
|
|
pdfFunctionFactory,
|
2017-09-21 19:14:05 +09:00
|
|
|
});
|
2015-11-13 05:41:16 +09:00
|
|
|
}
|
2012-08-29 09:19:31 +09:00
|
|
|
} else {
|
|
|
|
// Color key mask (just an array).
|
|
|
|
this.mask = mask;
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
}
|
2011-12-12 09:56:45 +09:00
|
|
|
/**
|
2014-04-15 05:22:35 +09:00
|
|
|
* Handles processing of image data and returns the Promise that is resolved
|
|
|
|
* with a PDFImage when the image is ready to be used.
|
2011-12-12 09:56:45 +09:00
|
|
|
*/
|
Attempt to actually resolve ColourSpace names in accordance with the specification (issue 9285)
Please refer to the PDF specification, in particular http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3801570
> A colour space shall be specified in one of two ways:
> - Within a content stream, the CS or cs operator establishes the current colour space parameter in the graphics state. The operand shall always be name object, which either identifies one of the colour spaces that need no additional parameters (DeviceGray, DeviceRGB, DeviceCMYK, or some cases of Pattern) or shall be used as a key in the ColorSpace subdictionary of the current resource dictionary (see 7.8.3, "Resource Dictionaries"). In the latter case, the value of the dictionary entry in turn shall be a colour space array or name. A colour space array shall never be inline within a content stream.
>
> - Outside a content stream, certain objects, such as image XObjects, shall specify a colour space as an explicit parameter, often associated with the key ColorSpace. In this case, the colour space array or name shall always be defined directly as a PDF object, not by an entry in the ColorSpace resource subdictionary. This convention also applies when colour spaces are defined in terms of other colour spaces.
2017-12-20 23:35:04 +09:00
|
|
|
PDFImage.buildImage = function({ handler, xref, res, image, isInline = false,
|
2017-09-19 20:49:30 +09:00
|
|
|
nativeDecoder = null,
|
|
|
|
pdfFunctionFactory, }) {
|
2016-04-01 21:36:16 +09:00
|
|
|
var imagePromise = handleImageData(image, nativeDecoder);
|
2014-04-15 05:22:35 +09:00
|
|
|
var smaskPromise;
|
|
|
|
var maskPromise;
|
2011-12-12 09:56:45 +09:00
|
|
|
|
2012-04-05 03:43:04 +09:00
|
|
|
var smask = image.dict.get('SMask');
|
2012-06-09 14:42:56 +09:00
|
|
|
var mask = image.dict.get('Mask');
|
|
|
|
|
|
|
|
if (smask) {
|
2016-04-01 21:36:16 +09:00
|
|
|
smaskPromise = handleImageData(smask, nativeDecoder);
|
2014-04-15 05:22:35 +09:00
|
|
|
maskPromise = Promise.resolve(null);
|
2012-06-09 14:42:56 +09:00
|
|
|
} else {
|
2014-04-15 05:22:35 +09:00
|
|
|
smaskPromise = Promise.resolve(null);
|
2012-08-29 09:19:31 +09:00
|
|
|
if (mask) {
|
|
|
|
if (isStream(mask)) {
|
2016-04-01 21:36:16 +09:00
|
|
|
maskPromise = handleImageData(mask, nativeDecoder);
|
2017-09-02 03:27:13 +09:00
|
|
|
} else if (Array.isArray(mask)) {
|
2014-04-15 05:22:35 +09:00
|
|
|
maskPromise = Promise.resolve(mask);
|
2012-08-29 09:19:31 +09:00
|
|
|
} else {
|
|
|
|
warn('Unsupported mask format.');
|
2014-04-15 05:22:35 +09:00
|
|
|
maskPromise = Promise.resolve(null);
|
2012-08-29 09:19:31 +09:00
|
|
|
}
|
2012-06-09 14:42:56 +09:00
|
|
|
} else {
|
2014-04-15 05:22:35 +09:00
|
|
|
maskPromise = Promise.resolve(null);
|
2012-06-09 14:42:56 +09:00
|
|
|
}
|
|
|
|
}
|
2014-04-15 05:22:35 +09:00
|
|
|
return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
|
2017-09-21 19:14:05 +09:00
|
|
|
function([imageData, smaskData, maskData]) {
|
|
|
|
return new PDFImage({
|
|
|
|
xref,
|
|
|
|
res,
|
|
|
|
image: imageData,
|
Attempt to actually resolve ColourSpace names in accordance with the specification (issue 9285)
Please refer to the PDF specification, in particular http://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf#G7.3801570
> A colour space shall be specified in one of two ways:
> - Within a content stream, the CS or cs operator establishes the current colour space parameter in the graphics state. The operand shall always be name object, which either identifies one of the colour spaces that need no additional parameters (DeviceGray, DeviceRGB, DeviceCMYK, or some cases of Pattern) or shall be used as a key in the ColorSpace subdictionary of the current resource dictionary (see 7.8.3, "Resource Dictionaries"). In the latter case, the value of the dictionary entry in turn shall be a colour space array or name. A colour space array shall never be inline within a content stream.
>
> - Outside a content stream, certain objects, such as image XObjects, shall specify a colour space as an explicit parameter, often associated with the key ColorSpace. In this case, the colour space array or name shall always be defined directly as a PDF object, not by an entry in the ColorSpace resource subdictionary. This convention also applies when colour spaces are defined in terms of other colour spaces.
2017-12-20 23:35:04 +09:00
|
|
|
isInline,
|
2017-09-21 19:14:05 +09:00
|
|
|
smask: smaskData,
|
|
|
|
mask: maskData,
|
2017-09-19 20:49:30 +09:00
|
|
|
pdfFunctionFactory,
|
2017-09-21 19:14:05 +09:00
|
|
|
});
|
2014-04-15 05:22:35 +09:00
|
|
|
});
|
2011-12-12 09:56:45 +09:00
|
|
|
};
|
2011-10-25 08:55:23 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
PDFImage.createMask = function({ imgArray, width, height,
|
|
|
|
imageIsFromDecodeStream, inverseDecode, }) {
|
2014-06-13 09:37:41 +09:00
|
|
|
// |imgArray| might not contain full data for every pixel of the mask, so
|
|
|
|
// we need to distinguish between |computedLength| and |actualLength|.
|
|
|
|
// In particular, if inverseDecode is true, then the array we return must
|
|
|
|
// have a length of |computedLength|.
|
|
|
|
|
|
|
|
var computedLength = ((width + 7) >> 3) * height;
|
2014-03-07 14:09:07 +09:00
|
|
|
var actualLength = imgArray.byteLength;
|
2014-08-02 05:40:47 +09:00
|
|
|
var haveFullData = computedLength === actualLength;
|
2014-06-13 09:37:41 +09:00
|
|
|
var data, i;
|
|
|
|
|
|
|
|
if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {
|
|
|
|
// imgArray came from a DecodeStream and its data is in an appropriate
|
|
|
|
// form, so we can just transfer it.
|
2014-03-07 14:27:32 +09:00
|
|
|
data = imgArray;
|
2014-06-13 09:37:41 +09:00
|
|
|
} else if (!inverseDecode) {
|
2014-03-07 14:27:32 +09:00
|
|
|
data = new Uint8Array(actualLength);
|
|
|
|
data.set(imgArray);
|
2014-06-13 09:37:41 +09:00
|
|
|
} else {
|
|
|
|
data = new Uint8Array(computedLength);
|
|
|
|
data.set(imgArray);
|
|
|
|
for (i = actualLength; i < computedLength; i++) {
|
|
|
|
data[i] = 0xff;
|
|
|
|
}
|
2014-03-07 14:27:32 +09:00
|
|
|
}
|
2014-06-13 09:37:41 +09:00
|
|
|
|
|
|
|
// If necessary, invert the original mask data (but not any extra we might
|
|
|
|
// have added above). It's safe to modify the array -- whether it's the
|
2014-03-07 14:27:32 +09:00
|
|
|
// original or a copy, we're about to transfer it anyway, so nothing else
|
|
|
|
// in this thread can be relying on its contents.
|
|
|
|
if (inverseDecode) {
|
2014-06-13 09:37:41 +09:00
|
|
|
for (i = 0; i < actualLength; i++) {
|
2017-08-16 20:21:33 +09:00
|
|
|
data[i] ^= 0xFF;
|
2013-05-31 09:42:26 +09:00
|
|
|
}
|
|
|
|
}
|
2014-01-14 11:08:39 +09:00
|
|
|
|
2017-04-27 19:58:44 +09:00
|
|
|
return { data, width, height, };
|
2013-05-31 09:42:26 +09:00
|
|
|
};
|
|
|
|
|
2011-12-09 07:18:43 +09:00
|
|
|
PDFImage.prototype = {
|
2011-12-20 09:31:47 +09:00
|
|
|
get drawWidth() {
|
2014-02-06 03:58:14 +09:00
|
|
|
return Math.max(this.width,
|
|
|
|
this.smask && this.smask.width || 0,
|
|
|
|
this.mask && this.mask.width || 0);
|
2011-12-19 10:18:36 +09:00
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2011-12-20 09:31:47 +09:00
|
|
|
get drawHeight() {
|
2014-02-06 03:58:14 +09:00
|
|
|
return Math.max(this.height,
|
|
|
|
this.smask && this.smask.height || 0,
|
|
|
|
this.mask && this.mask.height || 0);
|
2011-12-19 10:18:36 +09:00
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
decodeBuffer(buffer) {
|
2011-10-25 08:55:23 +09:00
|
|
|
var bpc = this.bpc;
|
2013-03-15 06:06:44 +09:00
|
|
|
var numComps = this.numComps;
|
|
|
|
|
|
|
|
var decodeAddends = this.decodeAddends;
|
|
|
|
var decodeCoefficients = this.decodeCoefficients;
|
|
|
|
var max = (1 << bpc) - 1;
|
2014-04-08 06:42:54 +09:00
|
|
|
var i, ii;
|
2013-03-15 06:06:44 +09:00
|
|
|
|
|
|
|
if (bpc === 1) {
|
|
|
|
// If the buffer needed decode that means it just needs to be inverted.
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0, ii = buffer.length; i < ii; i++) {
|
2013-03-15 06:06:44 +09:00
|
|
|
buffer[i] = +!(buffer[i]);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var index = 0;
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0, ii = this.width * this.height; i < ii; i++) {
|
2013-03-15 06:06:44 +09:00
|
|
|
for (var j = 0; j < numComps; j++) {
|
|
|
|
buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
|
2014-03-21 04:28:22 +09:00
|
|
|
decodeCoefficients[j], max);
|
2013-03-15 06:06:44 +09:00
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
getComponents(buffer) {
|
2013-03-15 06:06:44 +09:00
|
|
|
var bpc = this.bpc;
|
2011-12-14 07:35:46 +09:00
|
|
|
|
|
|
|
// This image doesn't require any extra work.
|
2014-01-23 09:47:51 +09:00
|
|
|
if (bpc === 8) {
|
2011-12-14 06:53:22 +09:00
|
|
|
return buffer;
|
2014-01-23 09:47:51 +09:00
|
|
|
}
|
2011-12-14 07:35:46 +09:00
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
var width = this.width;
|
|
|
|
var height = this.height;
|
|
|
|
var numComps = this.numComps;
|
|
|
|
|
2011-12-14 06:53:22 +09:00
|
|
|
var length = width * height * numComps;
|
2011-10-25 08:55:23 +09:00
|
|
|
var bufferPos = 0;
|
2014-03-21 04:28:22 +09:00
|
|
|
var output = (bpc <= 8 ? new Uint8Array(length) :
|
|
|
|
(bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
|
2011-10-25 08:55:23 +09:00
|
|
|
var rowComps = width * numComps;
|
2013-03-15 06:06:44 +09:00
|
|
|
|
2011-12-14 06:53:22 +09:00
|
|
|
var max = (1 << bpc) - 1;
|
2014-04-08 06:42:54 +09:00
|
|
|
var i = 0, ii, buf;
|
2011-10-25 08:55:23 +09:00
|
|
|
|
2013-03-15 06:06:44 +09:00
|
|
|
if (bpc === 1) {
|
2011-12-14 06:53:22 +09:00
|
|
|
// Optimization for reading 1 bpc images.
|
2014-04-08 06:42:54 +09:00
|
|
|
var mask, loop1End, loop2End;
|
2014-03-05 17:42:16 +09:00
|
|
|
for (var j = 0; j < height; j++) {
|
|
|
|
loop1End = i + (rowComps & ~7);
|
|
|
|
loop2End = i + rowComps;
|
2011-10-25 08:55:23 +09:00
|
|
|
|
2014-03-05 17:42:16 +09:00
|
|
|
// unroll loop for all full bytes
|
|
|
|
while (i < loop1End) {
|
|
|
|
buf = buffer[bufferPos++];
|
|
|
|
output[i] = (buf >> 7) & 1;
|
|
|
|
output[i + 1] = (buf >> 6) & 1;
|
|
|
|
output[i + 2] = (buf >> 5) & 1;
|
|
|
|
output[i + 3] = (buf >> 4) & 1;
|
|
|
|
output[i + 4] = (buf >> 3) & 1;
|
|
|
|
output[i + 5] = (buf >> 2) & 1;
|
|
|
|
output[i + 6] = (buf >> 1) & 1;
|
|
|
|
output[i + 7] = buf & 1;
|
|
|
|
i += 8;
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
|
2016-07-17 21:33:41 +09:00
|
|
|
// handle remaining bits
|
2014-03-05 17:42:16 +09:00
|
|
|
if (i < loop2End) {
|
2011-10-25 08:55:23 +09:00
|
|
|
buf = buffer[bufferPos++];
|
|
|
|
mask = 128;
|
2014-03-05 17:42:16 +09:00
|
|
|
while (i < loop2End) {
|
|
|
|
output[i++] = +!!(buf & mask);
|
|
|
|
mask >>= 1;
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2011-12-14 06:53:22 +09:00
|
|
|
// The general case that handles all other bpc values.
|
2014-04-08 06:42:54 +09:00
|
|
|
var bits = 0;
|
|
|
|
buf = 0;
|
|
|
|
for (i = 0, ii = length; i < ii; ++i) {
|
2013-02-01 08:32:13 +09:00
|
|
|
if (i % rowComps === 0) {
|
2011-10-25 08:55:23 +09:00
|
|
|
buf = 0;
|
|
|
|
bits = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (bits < bpc) {
|
|
|
|
buf = (buf << 8) | buffer[bufferPos++];
|
|
|
|
bits += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
var remainingBits = bits - bpc;
|
2011-12-14 06:53:22 +09:00
|
|
|
var value = buf >> remainingBits;
|
2014-03-21 04:28:22 +09:00
|
|
|
output[i] = (value < 0 ? 0 : (value > max ? max : value));
|
2011-10-25 08:55:23 +09:00
|
|
|
buf = buf & ((1 << remainingBits) - 1);
|
|
|
|
bits = remainingBits;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return output;
|
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
fillOpacity(rgbaBuf, width, height, actualHeight, image) {
|
2011-10-25 08:55:23 +09:00
|
|
|
var smask = this.smask;
|
2012-06-09 14:42:56 +09:00
|
|
|
var mask = this.mask;
|
2014-04-08 06:42:54 +09:00
|
|
|
var alphaBuf, sw, sh, i, ii, j;
|
2011-10-25 08:55:23 +09:00
|
|
|
|
|
|
|
if (smask) {
|
2014-04-08 06:42:54 +09:00
|
|
|
sw = smask.width;
|
|
|
|
sh = smask.height;
|
2014-01-17 10:55:42 +09:00
|
|
|
alphaBuf = new Uint8Array(sw * sh);
|
|
|
|
smask.fillGrayBuffer(alphaBuf);
|
2014-08-02 05:40:47 +09:00
|
|
|
if (sw !== width || sh !== height) {
|
2016-04-17 03:07:35 +09:00
|
|
|
alphaBuf = resizeImageMask(alphaBuf, smask.bpc, sw, sh,
|
|
|
|
width, height);
|
2014-03-05 17:42:16 +09:00
|
|
|
}
|
2012-06-09 14:42:56 +09:00
|
|
|
} else if (mask) {
|
2012-08-29 09:19:31 +09:00
|
|
|
if (mask instanceof PDFImage) {
|
2014-04-08 06:42:54 +09:00
|
|
|
sw = mask.width;
|
|
|
|
sh = mask.height;
|
2014-01-17 10:55:42 +09:00
|
|
|
alphaBuf = new Uint8Array(sw * sh);
|
2012-08-29 09:19:31 +09:00
|
|
|
mask.numComps = 1;
|
2014-01-17 10:55:42 +09:00
|
|
|
mask.fillGrayBuffer(alphaBuf);
|
2012-06-09 14:42:56 +09:00
|
|
|
|
2014-01-17 10:55:42 +09:00
|
|
|
// Need to invert values in rgbaBuf
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0, ii = sw * sh; i < ii; ++i) {
|
2014-01-17 10:55:42 +09:00
|
|
|
alphaBuf[i] = 255 - alphaBuf[i];
|
2014-03-05 17:42:16 +09:00
|
|
|
}
|
2012-06-09 14:42:56 +09:00
|
|
|
|
2014-08-02 05:40:47 +09:00
|
|
|
if (sw !== width || sh !== height) {
|
2016-04-17 03:07:35 +09:00
|
|
|
alphaBuf = resizeImageMask(alphaBuf, mask.bpc, sw, sh,
|
|
|
|
width, height);
|
2014-03-05 17:42:16 +09:00
|
|
|
}
|
2017-09-02 03:27:13 +09:00
|
|
|
} else if (Array.isArray(mask)) {
|
2016-07-17 21:33:41 +09:00
|
|
|
// Color key mask: if any of the components are outside the range
|
2012-08-29 09:19:31 +09:00
|
|
|
// then they should be painted.
|
2014-01-17 10:55:42 +09:00
|
|
|
alphaBuf = new Uint8Array(width * height);
|
2012-08-30 01:36:12 +09:00
|
|
|
var numComps = this.numComps;
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0, ii = width * height; i < ii; ++i) {
|
2012-08-29 09:19:31 +09:00
|
|
|
var opacity = 0;
|
2012-08-30 01:36:12 +09:00
|
|
|
var imageOffset = i * numComps;
|
2014-04-08 06:42:54 +09:00
|
|
|
for (j = 0; j < numComps; ++j) {
|
2012-08-30 01:36:12 +09:00
|
|
|
var color = image[imageOffset + j];
|
|
|
|
var maskOffset = j * 2;
|
|
|
|
if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
|
2012-08-29 09:19:31 +09:00
|
|
|
opacity = 255;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-01-17 10:55:42 +09:00
|
|
|
alphaBuf[i] = opacity;
|
2012-08-29 09:19:31 +09:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-29 05:51:31 +09:00
|
|
|
throw new FormatError('Unknown mask format.');
|
2012-08-29 09:19:31 +09:00
|
|
|
}
|
2014-01-17 10:55:42 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
if (alphaBuf) {
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
|
2014-01-17 10:55:42 +09:00
|
|
|
rgbaBuf[j] = alphaBuf[i];
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
} else {
|
2014-03-04 13:46:42 +09:00
|
|
|
// No mask.
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
|
2014-01-17 10:55:42 +09:00
|
|
|
rgbaBuf[j] = 255;
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
}
|
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
undoPreblend(buffer, width, height) {
|
2013-07-03 04:27:06 +09:00
|
|
|
var matte = this.smask && this.smask.matte;
|
|
|
|
if (!matte) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var matteRgb = this.colorSpace.getRgb(matte, 0);
|
2014-04-29 00:21:56 +09:00
|
|
|
var matteR = matteRgb[0];
|
|
|
|
var matteG = matteRgb[1];
|
|
|
|
var matteB = matteRgb[2];
|
2013-07-03 04:27:06 +09:00
|
|
|
var length = width * height * 4;
|
2014-04-29 00:21:56 +09:00
|
|
|
var r, g, b;
|
2013-07-03 04:27:06 +09:00
|
|
|
for (var i = 0; i < length; i += 4) {
|
|
|
|
var alpha = buffer[i + 3];
|
|
|
|
if (alpha === 0) {
|
|
|
|
// according formula we have to get Infinity in all components
|
2014-04-29 00:21:56 +09:00
|
|
|
// making it white (typical paper color) should be okay
|
2013-07-03 04:27:06 +09:00
|
|
|
buffer[i] = 255;
|
|
|
|
buffer[i + 1] = 255;
|
|
|
|
buffer[i + 2] = 255;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
var k = 255 / alpha;
|
2014-04-29 00:21:56 +09:00
|
|
|
r = (buffer[i] - matteR) * k + matteR;
|
|
|
|
g = (buffer[i + 1] - matteG) * k + matteG;
|
|
|
|
b = (buffer[i + 2] - matteB) * k + matteB;
|
|
|
|
buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;
|
|
|
|
buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;
|
|
|
|
buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;
|
2013-07-03 04:27:06 +09:00
|
|
|
}
|
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
createImageData(forceRGBA = false) {
|
2014-01-23 09:47:51 +09:00
|
|
|
var drawWidth = this.drawWidth;
|
|
|
|
var drawHeight = this.drawHeight;
|
2014-03-21 04:28:22 +09:00
|
|
|
var imgData = { // other fields are filled in below
|
2014-01-23 09:47:51 +09:00
|
|
|
width: drawWidth,
|
Fix inconsistent spacing and trailing commas in objects in `src/core/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
*Unfortunately this patch is fairly big, even though it only covers the `src/core` folder, but splitting it even further seemed difficult.*
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint --fix command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/core/evaluator.js b/src/core/evaluator.js
index abab9027..dcd3594b 100644
--- a/src/core/evaluator.js
+++ b/src/core/evaluator.js
@@ -2785,7 +2785,8 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
t['Tz'] = { id: OPS.setHScale, numArgs: 1, variableArgs: false, };
t['TL'] = { id: OPS.setLeading, numArgs: 1, variableArgs: false, };
t['Tf'] = { id: OPS.setFont, numArgs: 2, variableArgs: false, };
- t['Tr'] = { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false, };
+ t['Tr'] = { id: OPS.setTextRenderingMode, numArgs: 1,
+ variableArgs: false, };
t['Ts'] = { id: OPS.setTextRise, numArgs: 1, variableArgs: false, };
t['Td'] = { id: OPS.moveText, numArgs: 2, variableArgs: false, };
t['TD'] = { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false, };
diff --git a/src/core/jbig2.js b/src/core/jbig2.js
index 5a17d482..71671541 100644
--- a/src/core/jbig2.js
+++ b/src/core/jbig2.js
@@ -123,19 +123,22 @@ var Jbig2Image = (function Jbig2ImageClosure() {
{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, }, { x: -2, y: 0, },
{ x: -1, y: 0, }],
[{ x: -3, y: -1, }, { x: -2, y: -1, }, { x: -1, y: -1, }, { x: 0, y: -1, },
- { x: 1, y: -1, }, { x: -4, y: 0, }, { x: -3, y: 0, }, { x: -2, y: 0, }, { x: -1, y: 0, }]
+ { x: 1, y: -1, }, { x: -4, y: 0, }, { x: -3, y: 0, }, { x: -2, y: 0, },
+ { x: -1, y: 0, }]
];
var RefinementTemplates = [
{
coding: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }],
- reference: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, },
- { x: 1, y: 0, }, { x: -1, y: 1, }, { x: 0, y: 1, }, { x: 1, y: 1, }],
+ reference: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, },
+ { x: 0, y: 0, }, { x: 1, y: 0, }, { x: -1, y: 1, },
+ { x: 0, y: 1, }, { x: 1, y: 1, }],
},
{
- coding: [{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }],
- reference: [{ x: 0, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, }, { x: 1, y: 0, },
- { x: 0, y: 1, }, { x: 1, y: 1, }],
+ coding: [{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, },
+ { x: -1, y: 0, }],
+ reference: [{ x: 0, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, },
+ { x: 1, y: 0, }, { x: 0, y: 1, }, { x: 1, y: 1, }],
}
];
```
2017-06-02 18:16:24 +09:00
|
|
|
height: drawHeight,
|
2014-01-23 09:47:51 +09:00
|
|
|
};
|
|
|
|
|
2011-10-25 08:55:23 +09:00
|
|
|
var numComps = this.numComps;
|
2011-12-19 10:18:36 +09:00
|
|
|
var originalWidth = this.width;
|
|
|
|
var originalHeight = this.height;
|
2011-10-25 08:55:23 +09:00
|
|
|
var bpc = this.bpc;
|
|
|
|
|
2014-02-25 12:37:19 +09:00
|
|
|
// Rows start at byte boundary.
|
2011-12-19 10:18:36 +09:00
|
|
|
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
|
2014-03-28 01:08:32 +09:00
|
|
|
var imgArray;
|
2011-10-25 08:55:23 +09:00
|
|
|
|
2014-02-25 12:37:19 +09:00
|
|
|
if (!forceRGBA) {
|
|
|
|
// If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image
|
|
|
|
// without any complications, we pass a same-sized copy to the main
|
|
|
|
// thread rather than expanding by 32x to RGBA form. This saves *lots*
|
|
|
|
// of memory for many scanned documents. It's also much faster.
|
|
|
|
//
|
|
|
|
// Similarly, if it is a 24-bit-per pixel RGB image without any
|
|
|
|
// complications, we avoid expanding by 1.333x to RGBA form.
|
|
|
|
var kind;
|
|
|
|
if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
|
2014-02-26 08:11:15 +09:00
|
|
|
kind = ImageKind.GRAYSCALE_1BPP;
|
2014-08-18 10:53:50 +09:00
|
|
|
} else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&
|
|
|
|
!this.needsDecode) {
|
2014-02-26 08:11:15 +09:00
|
|
|
kind = ImageKind.RGB_24BPP;
|
2014-02-25 12:37:19 +09:00
|
|
|
}
|
2014-08-18 10:53:50 +09:00
|
|
|
if (kind && !this.smask && !this.mask &&
|
2014-02-25 12:37:19 +09:00
|
|
|
drawWidth === originalWidth && drawHeight === originalHeight) {
|
|
|
|
imgData.kind = kind;
|
|
|
|
|
2014-03-28 01:08:32 +09:00
|
|
|
imgArray = this.getImageBytes(originalHeight * rowBytes);
|
2014-03-04 09:34:17 +09:00
|
|
|
// If imgArray came from a DecodeStream, we're safe to transfer it
|
2016-01-29 07:52:07 +09:00
|
|
|
// (and thus detach its underlying buffer) because it will constitute
|
|
|
|
// the entire DecodeStream's data. But if it came from a Stream, we
|
|
|
|
// need to copy it because it'll only be a portion of the Stream's
|
|
|
|
// data, and the rest will be read later on.
|
2014-03-04 09:34:17 +09:00
|
|
|
if (this.image instanceof DecodeStream) {
|
|
|
|
imgData.data = imgArray;
|
|
|
|
} else {
|
|
|
|
var newArray = new Uint8Array(imgArray.length);
|
|
|
|
newArray.set(imgArray);
|
|
|
|
imgData.data = newArray;
|
|
|
|
}
|
2014-08-18 10:53:50 +09:00
|
|
|
if (this.needsDecode) {
|
|
|
|
// Invert the buffer (which must be grayscale if we reached here).
|
|
|
|
assert(kind === ImageKind.GRAYSCALE_1BPP);
|
|
|
|
var buffer = imgData.data;
|
|
|
|
for (var i = 0, ii = buffer.length; i < ii; i++) {
|
|
|
|
buffer[i] ^= 0xff;
|
|
|
|
}
|
|
|
|
}
|
2014-02-25 12:37:19 +09:00
|
|
|
return imgData;
|
|
|
|
}
|
2017-12-30 01:15:08 +09:00
|
|
|
if (this.image instanceof JpegStream && !this.smask && !this.mask) {
|
|
|
|
let imageLength = originalHeight * rowBytes;
|
|
|
|
switch (this.colorSpace.name) {
|
|
|
|
case 'DeviceGray':
|
|
|
|
// Avoid truncating the image, since `JpegImage.getData`
|
|
|
|
// will expand the image data when `forceRGB === true`.
|
|
|
|
imageLength *= 3;
|
|
|
|
/* falls through */
|
|
|
|
case 'DeviceRGB':
|
|
|
|
case 'DeviceCMYK':
|
|
|
|
imgData.kind = ImageKind.RGB_24BPP;
|
|
|
|
imgData.data = this.getImageBytes(imageLength,
|
|
|
|
drawWidth, drawHeight, /* forceRGB = */ true);
|
|
|
|
return imgData;
|
|
|
|
}
|
2014-06-05 05:53:46 +09:00
|
|
|
}
|
2014-03-28 01:08:32 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
imgArray = this.getImageBytes(originalHeight * rowBytes);
|
2014-02-25 12:37:19 +09:00
|
|
|
// imgArray can be incomplete (e.g. after CCITT fax encoding).
|
2012-08-21 05:57:21 +09:00
|
|
|
var actualHeight = 0 | (imgArray.length / rowBytes *
|
2014-01-23 09:47:51 +09:00
|
|
|
drawHeight / originalHeight);
|
|
|
|
|
2013-03-15 06:06:44 +09:00
|
|
|
var comps = this.getComponents(imgArray);
|
2014-01-17 10:55:42 +09:00
|
|
|
|
2014-03-04 13:46:42 +09:00
|
|
|
// If opacity data is present, use RGBA_32BPP form. Otherwise, use the
|
|
|
|
// more compact RGB_24BPP form if allowable.
|
|
|
|
var alpha01, maybeUndoPreblend;
|
|
|
|
if (!forceRGBA && !this.smask && !this.mask) {
|
|
|
|
imgData.kind = ImageKind.RGB_24BPP;
|
|
|
|
imgData.data = new Uint8Array(drawWidth * drawHeight * 3);
|
|
|
|
alpha01 = 0;
|
|
|
|
maybeUndoPreblend = false;
|
|
|
|
} else {
|
|
|
|
imgData.kind = ImageKind.RGBA_32BPP;
|
|
|
|
imgData.data = new Uint8Array(drawWidth * drawHeight * 4);
|
|
|
|
alpha01 = 1;
|
|
|
|
maybeUndoPreblend = true;
|
|
|
|
|
|
|
|
// Color key masking (opacity) must be performed before decoding.
|
|
|
|
this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,
|
|
|
|
comps);
|
|
|
|
}
|
2012-08-21 05:57:21 +09:00
|
|
|
|
2013-03-15 06:06:44 +09:00
|
|
|
if (this.needsDecode) {
|
|
|
|
this.decodeBuffer(comps);
|
|
|
|
}
|
2014-03-04 13:46:42 +09:00
|
|
|
this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
|
|
|
|
drawWidth, drawHeight, actualHeight, bpc, comps,
|
|
|
|
alpha01);
|
|
|
|
if (maybeUndoPreblend) {
|
|
|
|
this.undoPreblend(imgData.data, drawWidth, actualHeight);
|
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
|
2014-01-23 09:47:51 +09:00
|
|
|
return imgData;
|
2011-10-25 08:55:23 +09:00
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
fillGrayBuffer(buffer) {
|
2011-10-25 08:55:23 +09:00
|
|
|
var numComps = this.numComps;
|
2014-08-02 05:40:47 +09:00
|
|
|
if (numComps !== 1) {
|
2017-06-29 05:51:31 +09:00
|
|
|
throw new FormatError(
|
|
|
|
`Reading gray scale from a color image: ${numComps}`);
|
2014-03-21 04:28:22 +09:00
|
|
|
}
|
2011-10-25 08:55:23 +09:00
|
|
|
|
|
|
|
var width = this.width;
|
|
|
|
var height = this.height;
|
|
|
|
var bpc = this.bpc;
|
|
|
|
|
2014-03-21 04:28:22 +09:00
|
|
|
// rows start at byte boundary
|
2011-10-25 08:55:23 +09:00
|
|
|
var rowBytes = (width * numComps * bpc + 7) >> 3;
|
2011-12-09 14:18:04 +09:00
|
|
|
var imgArray = this.getImageBytes(height * rowBytes);
|
2011-10-25 08:55:23 +09:00
|
|
|
|
|
|
|
var comps = this.getComponents(imgArray);
|
2014-04-08 06:42:54 +09:00
|
|
|
var i, length;
|
2014-03-05 17:42:16 +09:00
|
|
|
|
|
|
|
if (bpc === 1) {
|
|
|
|
// inline decoding (= inversion) for 1 bpc images
|
2014-04-08 06:42:54 +09:00
|
|
|
length = width * height;
|
2014-03-05 17:42:16 +09:00
|
|
|
if (this.needsDecode) {
|
2014-04-23 23:56:22 +09:00
|
|
|
// invert and scale to {0, 255}
|
2014-03-28 01:08:32 +09:00
|
|
|
for (i = 0; i < length; ++i) {
|
2014-03-05 17:42:16 +09:00
|
|
|
buffer[i] = (comps[i] - 1) & 255;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// scale to {0, 255}
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0; i < length; ++i) {
|
2014-03-05 17:42:16 +09:00
|
|
|
buffer[i] = (-comps[i]) & 255;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-15 06:06:44 +09:00
|
|
|
if (this.needsDecode) {
|
|
|
|
this.decodeBuffer(comps);
|
|
|
|
}
|
2014-04-08 06:42:54 +09:00
|
|
|
length = width * height;
|
2011-12-19 10:18:36 +09:00
|
|
|
// we aren't using a colorspace so we need to scale the value
|
|
|
|
var scale = 255 / ((1 << bpc) - 1);
|
2014-04-08 06:42:54 +09:00
|
|
|
for (i = 0; i < length; ++i) {
|
2011-12-19 10:18:36 +09:00
|
|
|
buffer[i] = (scale * comps[i]) | 0;
|
2014-03-05 17:42:16 +09:00
|
|
|
}
|
2011-12-09 05:50:34 +09:00
|
|
|
},
|
2014-03-27 19:11:28 +09:00
|
|
|
|
2017-09-21 19:14:05 +09:00
|
|
|
getImageBytes(length, drawWidth, drawHeight, forceRGB = false) {
|
2011-12-09 14:18:04 +09:00
|
|
|
this.image.reset();
|
2014-06-05 05:53:46 +09:00
|
|
|
this.image.drawWidth = drawWidth || this.width;
|
|
|
|
this.image.drawHeight = drawHeight || this.height;
|
|
|
|
this.image.forceRGB = !!forceRGB;
|
2011-12-09 14:18:04 +09:00
|
|
|
return this.image.getBytes(length);
|
Fix inconsistent spacing and trailing commas in objects in `src/core/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
*Unfortunately this patch is fairly big, even though it only covers the `src/core` folder, but splitting it even further seemed difficult.*
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint --fix command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/core/evaluator.js b/src/core/evaluator.js
index abab9027..dcd3594b 100644
--- a/src/core/evaluator.js
+++ b/src/core/evaluator.js
@@ -2785,7 +2785,8 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
t['Tz'] = { id: OPS.setHScale, numArgs: 1, variableArgs: false, };
t['TL'] = { id: OPS.setLeading, numArgs: 1, variableArgs: false, };
t['Tf'] = { id: OPS.setFont, numArgs: 2, variableArgs: false, };
- t['Tr'] = { id: OPS.setTextRenderingMode, numArgs: 1, variableArgs: false, };
+ t['Tr'] = { id: OPS.setTextRenderingMode, numArgs: 1,
+ variableArgs: false, };
t['Ts'] = { id: OPS.setTextRise, numArgs: 1, variableArgs: false, };
t['Td'] = { id: OPS.moveText, numArgs: 2, variableArgs: false, };
t['TD'] = { id: OPS.setLeadingMoveText, numArgs: 2, variableArgs: false, };
diff --git a/src/core/jbig2.js b/src/core/jbig2.js
index 5a17d482..71671541 100644
--- a/src/core/jbig2.js
+++ b/src/core/jbig2.js
@@ -123,19 +123,22 @@ var Jbig2Image = (function Jbig2ImageClosure() {
{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, }, { x: -2, y: 0, },
{ x: -1, y: 0, }],
[{ x: -3, y: -1, }, { x: -2, y: -1, }, { x: -1, y: -1, }, { x: 0, y: -1, },
- { x: 1, y: -1, }, { x: -4, y: 0, }, { x: -3, y: 0, }, { x: -2, y: 0, }, { x: -1, y: 0, }]
+ { x: 1, y: -1, }, { x: -4, y: 0, }, { x: -3, y: 0, }, { x: -2, y: 0, },
+ { x: -1, y: 0, }]
];
var RefinementTemplates = [
{
coding: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }],
- reference: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, },
- { x: 1, y: 0, }, { x: -1, y: 1, }, { x: 0, y: 1, }, { x: 1, y: 1, }],
+ reference: [{ x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, },
+ { x: 0, y: 0, }, { x: 1, y: 0, }, { x: -1, y: 1, },
+ { x: 0, y: 1, }, { x: 1, y: 1, }],
},
{
- coding: [{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, }, { x: -1, y: 0, }],
- reference: [{ x: 0, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, }, { x: 1, y: 0, },
- { x: 0, y: 1, }, { x: 1, y: 1, }],
+ coding: [{ x: -1, y: -1, }, { x: 0, y: -1, }, { x: 1, y: -1, },
+ { x: -1, y: 0, }],
+ reference: [{ x: 0, y: -1, }, { x: -1, y: 0, }, { x: 0, y: 0, },
+ { x: 1, y: 0, }, { x: 0, y: 1, }, { x: 1, y: 1, }],
}
];
```
2017-06-02 18:16:24 +09:00
|
|
|
},
|
2011-10-25 08:55:23 +09:00
|
|
|
};
|
2011-12-09 07:18:43 +09:00
|
|
|
return PDFImage;
|
2011-10-25 08:55:23 +09:00
|
|
|
})();
|
2015-11-22 01:32:47 +09:00
|
|
|
|
2017-04-02 23:14:30 +09:00
|
|
|
export {
|
|
|
|
PDFImage,
|
|
|
|
};
|