diff --git a/src/colorspace.js b/src/colorspace.js index 8088ab7df..827fd2e19 100644 --- a/src/colorspace.js +++ b/src/colorspace.js @@ -225,7 +225,7 @@ var AlternateCS = (function AlternateCSClosure() { return base.getRgbBuffer(baseBuf, 8); }, isDefaultDecode: function altcs_isDefaultDecode(decodeMap) { - ColorSpace.isDefaultDecode(decodeMap, this.numComps); + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } }; @@ -327,7 +327,7 @@ var DeviceGrayCS = (function DeviceGrayCSClosure() { return rgbBuf; }, isDefaultDecode: function graycs_isDefaultDecode(decodeMap) { - ColorSpace.isDefaultDecode(decodeMap, this.numComps); + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } }; return DeviceGrayCS; @@ -354,7 +354,7 @@ var DeviceRgbCS = (function DeviceRgbCSClosure() { return rgbBuf; }, isDefaultDecode: function rgbcs_isDefaultDecode(decodeMap) { - ColorSpace.isDefaultDecode(decodeMap, this.numComps); + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } }; return DeviceRgbCS; @@ -441,7 +441,7 @@ var DeviceCmykCS = (function DeviceCmykCSClosure() { return rgbBuf; }, isDefaultDecode: function cmykcs_isDefaultDecode(decodeMap) { - ColorSpace.isDefaultDecode(decodeMap, this.numComps); + return ColorSpace.isDefaultDecode(decodeMap, this.numComps); } }; diff --git a/src/evaluator.js b/src/evaluator.js index 213fe2178..bc0d83e11 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -221,13 +221,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { fn = 'paintImageXObject'; PDFImage.buildImage(function(imageObj) { + var drawWidth = imageObj.drawWidth; + var drawHeight = imageObj.drawHeight; var imgData = { - width: w, - height: h, - data: new Uint8Array(w * h * 4) + width: drawWidth, + height: drawHeight, + data: new Uint8Array(drawWidth * drawHeight * 4) }; var pixels = imgData.data; - imageObj.fillRgbaBuffer(pixels); + imageObj.fillRgbaBuffer(pixels, drawWidth, drawHeight); handler.send('obj', [objId, 'Image', imgData]); }, handler, xref, resources, image, inline); } diff --git a/src/image.js b/src/image.js index 22a9f9eb4..29bad4d8a 100644 --- a/src/image.js +++ b/src/image.js @@ -127,7 +127,56 @@ var PDFImage = (function PDFImageClosure() { smaskPromise.resolve(null); }; + /** + * Resize an image using the nearest neighbor algorithm. Currently only + * supports one and three component images. + * @param {TypedArray} pixels The original image with one component. + * @param {Number} bpc Number of bits per component. + * @param {Number} components Number of color components, 1 or 3 is supported. + * @param {Number} w1 Original width. + * @param {Number} h1 Original height. + * @param {Number} w2 New width. + * @param {Number} h2 New height. + * @return {TypedArray} Resized image data. + */ + PDFImage.resize = function resize(pixels, bpc, components, w1, h1, w2, h2) { + var length = w2 * h2 * components; + var temp = bpc <= 8 ? new Uint8Array(length) : + bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length); + var xRatio = w1 / w2; + var yRatio = h1 / h2; + var px, py, newIndex, oldIndex; + for (var i = 0; i < h2; i++) { + for (var j = 0; j < w2; j++) { + px = Math.floor(j * xRatio); + py = Math.floor(i * yRatio); + newIndex = (i * w2) + j; + oldIndex = ((py * w1) + px); + if (components === 1) { + temp[newIndex] = pixels[oldIndex]; + } else if (components === 3) { + newIndex *= 3; + oldIndex *= 3; + temp[newIndex] = pixels[oldIndex]; + temp[newIndex + 1] = pixels[oldIndex + 1]; + temp[newIndex + 2] = pixels[oldIndex + 2]; + } + } + } + return temp; + }; + PDFImage.prototype = { + get drawWidth() { + if (!this.smask) + return this.width; + return Math.max(this.width, this.smask.width); + }, + get drawHeight() { + if (!this.smask) + return this.height; + return Math.max(this.height, this.smask.height); + }, getComponents: function getComponents(buffer) { var bpc = this.bpc; var needsDecode = this.needsDecode; @@ -216,22 +265,21 @@ var PDFImage = (function PDFImageClosure() { } return output; }, - getOpacity: function getOpacity() { + getOpacity: function getOpacity(width, height) { var smask = this.smask; - var width = this.width; - var height = this.height; - var buf = new Uint8Array(width * height); + var originalWidth = this.width; + var originalHeight = this.height; + var buf; if (smask) { var sw = smask.width; var sh = smask.height; - if (sw != this.width || sh != this.height) - error('smask dimensions do not match image dimensions: ' + sw + - ' != ' + this.width + ', ' + sh + ' != ' + this.height); - + buf = new Uint8Array(sw * sh); smask.fillGrayBuffer(buf); - return buf; + if (sw != width || sh != height) + buf = PDFImage.resize(buf, smask.bps, 1, sw, sh, width, height); } else { + buf = new Uint8Array(width * height); for (var i = 0, ii = width * height; i < ii; ++i) buf[i] = 255; } @@ -260,20 +308,23 @@ var PDFImage = (function PDFImageClosure() { } } }, - fillRgbaBuffer: function fillRgbaBuffer(buffer) { + fillRgbaBuffer: function fillRgbaBuffer(buffer, width, height) { var numComps = this.numComps; - var width = this.width; - var height = this.height; + var originalWidth = this.width; + var originalHeight = this.height; var bpc = this.bpc; // rows start at byte boundary; - var rowBytes = (width * numComps * bpc + 7) >> 3; - var imgArray = this.getImageBytes(height * rowBytes); + var rowBytes = (originalWidth * numComps * bpc + 7) >> 3; + var imgArray = this.getImageBytes(originalHeight * rowBytes); var comps = this.colorSpace.getRgbBuffer( this.getComponents(imgArray), bpc); + if (originalWidth != width || originalHeight != height) + comps = PDFImage.resize(comps, this.bpc, 3, originalWidth, + originalHeight, width, height); var compsPos = 0; - var opacity = this.getOpacity(); + var opacity = this.getOpacity(width, height); var opacityPos = 0; var length = width * height * 4; @@ -299,9 +350,10 @@ var PDFImage = (function PDFImageClosure() { var comps = this.getComponents(imgArray); var length = width * height; - + // we aren't using a colorspace so we need to scale the value + var scale = 255 / ((1 << bpc) - 1); for (var i = 0; i < length; ++i) - buffer[i] = comps[i]; + buffer[i] = (scale * comps[i]) | 0; }, getImageBytes: function getImageBytes(length) { this.image.reset(); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 23ba6340e..fd541a06d 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -20,3 +20,4 @@ !scan-bad.pdf !freeculture.pdf !issue918.pdf +!smaskdim.pdf diff --git a/test/pdfs/smaskdim.pdf b/test/pdfs/smaskdim.pdf new file mode 100755 index 000000000..1ca92c3ac Binary files /dev/null and b/test/pdfs/smaskdim.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index 7469db678..5b88b3136 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -361,5 +361,11 @@ "rounds": 1, "link": true, "type": "eq" + }, + { "id": "smaskdim", + "file": "pdfs/smaskdim.pdf", + "md5": "de80aeca7cbf79940189fd34d59671ee", + "rounds": 1, + "type": "eq" } ]