From 146cd8c8617d254a533fe6967a1cbaa303c38a5a Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 8 Dec 2011 12:50:34 -0800 Subject: [PATCH] Second stage, smasks now working. Still needs optimization. --- src/canvas.js | 43 ++++-------------------------- src/core.js | 27 +++++++++++++------ src/evaluator.js | 69 ++++++++++++++++++++---------------------------- src/image.js | 50 +++++++++++++++++++++++++---------- 4 files changed, 88 insertions(+), 101 deletions(-) diff --git a/src/canvas.js b/src/canvas.js index 06c3e6557..128f4fbc9 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -1036,28 +1036,6 @@ var CanvasGraphics = (function canvasGraphics() { this.restore(); }, - paintJpegXObject: function canvasGraphicsPaintJpegXObject(objId, w, h) { - var image = this.objs.get(objId); - debugger; - if (!image) { - error('Dependent image isn\'t ready yet'); - } - - - this.paintNormalImageXObject(image); - /* - this.save(); - - var ctx = this.ctx; - // scale the image to the unit square - ctx.scale(1 / w, -1 / h); - - ctx.drawImage(image.data, 0, 0, image.width, image.height, - 0, -h, w, h); - - this.restore(); */ - }, - paintImageMaskXObject: function canvasGraphicsPaintImageMaskXObject( imgArray, inverseDecode, width, height) { function applyStencilMask(buffer, inverseDecode) { @@ -1107,7 +1085,11 @@ var CanvasGraphics = (function canvasGraphics() { this.restore(); }, - paintNormalImageXObject: function canvasGraphicsPaintImageXObject(imgData) { + paintImageXObject: function canvasGraphicsPaintImageXObject(objId) { + var imgData = this.objs.get(objId); + if (!imgData) { + error('Dependent image isn\'t ready yet'); + } this.save(); var ctx = this.ctx; var w = imgData.width; @@ -1137,21 +1119,6 @@ var CanvasGraphics = (function canvasGraphics() { this.restore(); }, - paintImageXObject: function canvasGraphicsPaintImageXObject(type, data) { - debugger; - switch(type) { - case 'jpeg': - this.paintJpegXObject.apply(this, data); - break; - case 'imageMask': - this.paintImageMaskXObject.apply(this, data); - break; - default: - this.paintNormalImageXObject.apply(this, data); - break; - } - }, - // Marked content markPoint: function canvasGraphicsMarkPoint(tag) { diff --git a/src/core.js b/src/core.js index ea9589505..8063841f2 100644 --- a/src/core.js +++ b/src/core.js @@ -560,7 +560,7 @@ var PDFDoc = (function pdfDoc() { var type = data[1]; switch (type) { - case 'Jpeg': + case 'Image': var imageData = data[2]; this.objs.resolve(id, imageData); break; @@ -610,21 +610,32 @@ var PDFDoc = (function pdfDoc() { messageHandler.on('jpeg_decode', function(message) { var imageData = message.data[0]; + var components = message.data[1]; + if (components != 3 && components != 1) + error('Only 3 component or 1 component can be returned'); + var img = new Image(); img.onload = (function jpegImageLoaderOnload() { var width = img.width; var height = img.height; - var length = width * height * 4; - var buf = new Uint8Array(length); + var size = width * height; + var rgbaLength = size * 4; + var buf = new Uint8Array(size * components); var tempCanvas = new ScratchCanvas(width, height); var tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(img, 0, 0); var data = tempCtx.getImageData(0, 0, width, height).data; - for (var i = 0; i < length; i += 4) { - buf[i] = data[i]; - buf[i + 1] = data[i + 1]; - buf[i + 2] = data[i + 2]; - buf[i + 3] = data[i + 3]; + + if (components == 3) { + for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) { + buf[j] = data[i]; + buf[j + 1] = data[i + 1]; + buf[j + 2] = data[i + 2]; + } + } else if(components == 1) { + for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) { + buf[j] = data[i]; + } } message.resolve({ data: buf, width: width, height: height}); }).bind(this); diff --git a/src/evaluator.js b/src/evaluator.js index 224d823a4..a53d15c50 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -183,38 +183,42 @@ var PartialEvaluator = (function partialEvaluator() { var dict = image.dict; var w = dict.get('Width', 'W'); var h = dict.get('Height', 'H'); - fn = 'paintImageXObject'; - if (image instanceof JpegStream && image.isNative) { - var objId = 'img_' + uniquePrefix + (++self.objIdCounter); - debugger; - handler.send('jpeg_decode', [image.getIR()], function(data) { - handler.send('obj', [objId, 'Jpeg', data]); - }); + var imageMask = dict.get('ImageMask', 'IM') || false; + if (imageMask) { + // 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. - // Add the dependency on the image object. - insertDependency([objId]); - - // The normal fn. - args = ['jpeg', [objId, w, h]]; + 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 = !!decode && decode[0] > 0; + fn = 'paintImageMaskXObject'; + args = [imgArray, inverseDecode, width, height]; return; } - // Needs to be rendered ourself. - - // Figure out if the image has an imageMask. - var imageMask = dict.get('ImageMask', 'IM') || false; - // If there is no imageMask, create the PDFImage and a lot // of image processing can be done here. - if (!imageMask) { - var imageObj = new PDFImage(xref, resources, image, inline); + var objId = 'img_' + uniquePrefix + (++self.objIdCounter); + insertDependency([objId]); + fn = 'paintImageXObject'; + args = [objId, w, h]; + var resolve = (function(objId) { + return function resolve(data) { + handler.send('obj', [objId, 'Image', data]); + }; + })(objId); - if (imageObj.imageMask) { - throw 'Can\'t handle this in the web worker :/'; - } + var imageObj = new PDFImage(xref, resources, image, inline, handler); + imageObj.ready(function() { var imgData = { width: w, height: h, @@ -222,25 +226,8 @@ var PartialEvaluator = (function partialEvaluator() { }; var pixels = imgData.data; imageObj.fillRgbaBuffer(pixels, imageObj.decode); - - args = ['normal', [imgData]]; - return; - } - - // 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. - - 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 = !!decode && decode[0] > 0; - - args = ['imageMask', [imgArray, inverseDecode, width, height]]; + resolve(imgData); + }); } uniquePrefix = uniquePrefix || ''; diff --git a/src/image.js b/src/image.js index dbb62c99f..adae24292 100644 --- a/src/image.js +++ b/src/image.js @@ -4,8 +4,12 @@ 'use strict'; var PDFImage = (function pdfImage() { - function constructor(xref, res, image, inline) { + function constructor(xref, res, image, inline, handler) { this.image = image; + this.imageReady = true; + this.smaskReady = true; + this.callbacks = []; + if (image.getParams) { // JPX/JPEG2000 streams directly contain bits per component // and color space mode information. @@ -56,7 +60,24 @@ var PDFImage = (function pdfImage() { if (mask) { TODO('masked images'); } else if (smask) { - this.smask = new PDFImage(xref, res, smask); + this.smaskReady = false; + this.smask = new PDFImage(xref, res, smask, false, handler); + this.smask.ready(function() { + this.smaskReady = true; + if (this.isReady()) + this.fireReady(); + }.bind(this)); + } + + if (image instanceof JpegStream && image.isNative) { + this.imageReady = false; + handler.send('jpeg_decode', [image.getIR(), this.numComps], function(message) { + var data = message.data; + this.image = new Stream(data, 0, data.length); + this.imageReady = true; + if (this.isReady()) + this.fireReady(); + }.bind(this)); } } @@ -130,18 +151,6 @@ var PDFImage = (function pdfImage() { var buf = new Uint8Array(width * height); if (smask) { - if (smask.image.getImage) { - // smask is a DOM image - var tempCanvas = new ScratchCanvas(width, height); - var tempCtx = tempCanvas.getContext('2d'); - var domImage = smask.image.getImage(); - tempCtx.drawImage(domImage, 0, 0, domImage.width, domImage.height, - 0, 0, width, height); - var data = tempCtx.getImageData(0, 0, width, height).data; - for (var i = 0, j = 0, ii = width * height; i < ii; ++i, j += 4) - buf[i] = data[j]; // getting first component value - return buf; - } var sw = smask.width; var sh = smask.height; if (sw != this.width || sh != this.height) @@ -224,6 +233,19 @@ var PDFImage = (function pdfImage() { for (var i = 0; i < length; ++i) buffer[i] = comps[i]; + }, + isReady: function isReady() { + return this.imageReady && this.smaskReady; + }, + fireReady: function fireReady() { + for (var i = 0; i < this.callbacks.length; ++i) { + this.callbacks[i](); + this.callbacks = []; + }, + ready: function ready(callback) { + this.callbacks.push(callback); + if (this.isReady()) + this.fireReady(); } }; return constructor;