diff --git a/pdf.js b/pdf.js index 805122f9e..73a7e2e88 100644 --- a/pdf.js +++ b/pdf.js @@ -4313,23 +4313,47 @@ var PartialEvaluator = (function() { args = [ objId, w, h ]; } else { // Needs to be rendered ourself. - var inline = false; - var imageObj = new PDFImage(xref, resources, image, inline); + + // Figure out if the image has an imageMask. + var imageMask = dict.get('ImageMask', 'IM') || false; - if (imageObj.imageMask) { - throw "Can't handle this in the web worker :/"; + // If there is no imageMask, create the PDFImage and a lot + // of image processing can be done here. + if (!imageMask) { + var inline = false; + var imageObj = new PDFImage(xref, resources, image, inline); + + if (imageObj.imageMask) { + throw "Can't handle this in the web worker :/"; + } + + var imgData = { + width: w, + height: h, + data: new Uint8Array(w * h * 4) + }; + var pixels = imgData.data; + imageObj.fillRgbaBuffer(pixels, imageObj.decode); + + fn = "paintReadyImageXObject"; + args = [ imgData ]; + } else /* imageMask == true */ { + // This depends on a tmpCanvas beeing filled with the + // current fillStyle, such that processing the pixel + // data can't be done here. Instead of creating a + // complete PDFImage, only read the information needed + // for later. + fn = "paintReadyImageMaskXObject"; + + var width = dict.get('Width', 'W'); + var height = dict.get('Height', 'H'); + var bitStrideLength = (width + 7) >> 3; + var imgArray = image.getBytes(bitStrideLength * height); + var decode = dict.get('Decode', 'D'); + var inverseDecode = !!imageObj.decode && imageObj.decode[0] > 0; + + args = [ imgArray, inverseDecode, width, height ]; } - - var imgData = { - width: w, - height: h, - data: new Uint8Array(w * h * 4) - }; - var pixels = imgData.data; - imageObj.fillRgbaBuffer(pixels, imageObj.decode); - - fn = "paintReadyImageXObject"; - args = [ imgData ]; } } else { error('Unhandled XObject subtype ' + type.name); @@ -5616,6 +5640,54 @@ var CanvasGraphics = (function() { this.restore(); }, + paintReadyImageMaskXObject: function(imgArray, inverseDecode, width, height) { + function applyStencilMask(buffer, inverseDecode) { + var imgArrayPos = 0; + var i, j, mask, buf; + // removing making non-masked pixels transparent + var bufferPos = 3; // alpha component offset + for (i = 0; i < height; i++) { + mask = 0; + for (j = 0; j < width; j++) { + if (!mask) { + buf = imgArray[imgArrayPos++]; + mask = 128; + } + if (!(buf & mask) == inverseDecode) { + buffer[bufferPos] = 0; + } + bufferPos += 4; + mask >>= 1; + } + } + } + + this.save(); + + var ctx = this.ctx; + var w = width, h = height; + + // scale the image to the unit square + ctx.scale(1 / w, -1 / h); + + var tmpCanvas = new this.ScratchCanvas(w, h); + var tmpCtx = tmpCanvas.getContext('2d'); + var fillColor = this.current.fillColor; + + tmpCtx.fillStyle = (fillColor && fillColor.type === 'Pattern') ? + fillColor.getPattern(tmpCtx) : fillColor; + tmpCtx.fillRect(0, 0, w, h); + + var imgData = tmpCtx.getImageData(0, 0, w, h); + var pixels = imgData.data; + + applyStencilMask(pixels, inverseDecode); + + tmpCtx.putImageData(imgData, 0, 0); + ctx.drawImage(tmpCanvas, 0, -h); + this.restore(); + }, + paintReadyImageXObject: function(imgData) { this.save(); @@ -5633,6 +5705,9 @@ var CanvasGraphics = (function() { // Copy over the imageData. var tmpImgDataPixels = tmpImgData.data; var len = tmpImgDataPixels.length; + + // TODO: There got to be a better way to copy an ImageData array + // then coping over all the bytes one by one :/ while (len--) tmpImgDataPixels[len] = imgData.data[len]; @@ -6786,29 +6861,6 @@ var PDFImage = (function() { } return buf; }, - applyStencilMask: function applyStencilMask(buffer, inverseDecode) { - var width = this.width, height = this.height; - var bitStrideLength = (width + 7) >> 3; - var imgArray = this.image.getBytes(bitStrideLength * height); - var imgArrayPos = 0; - var i, j, mask, buf; - // removing making non-masked pixels transparent - var bufferPos = 3; // alpha component offset - for (i = 0; i < height; i++) { - mask = 0; - for (j = 0; j < width; j++) { - if (!mask) { - buf = imgArray[imgArrayPos++]; - mask = 128; - } - if (!(buf & mask) == inverseDecode) { - buffer[bufferPos] = 0; - } - bufferPos += 4; - mask >>= 1; - } - } - }, fillRgbaBuffer: function fillRgbaBuffer(buffer, decodeMap) { var numComps = this.numComps; var width = this.width;