From 2a632d4ab257d1c0eeed8384a7d8c6af2d14dcc9 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 7 Dec 2011 15:36:27 -0800 Subject: [PATCH] First stage of trying to support smasks on native jpegs. --- src/canvas.js | 26 +++++++++++++++++++++---- src/core.js | 35 ++++++++++++++++++++++++++++----- src/evaluator.js | 17 ++++++++-------- src/image.js | 27 -------------------------- src/stream.js | 2 ++ src/worker.js | 50 ++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 109 insertions(+), 48 deletions(-) diff --git a/src/canvas.js b/src/canvas.js index 6007d0031..06c3e6557 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -1038,21 +1038,24 @@ var CanvasGraphics = (function canvasGraphics() { 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); - var domImage = image.getImage(); - ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height, + ctx.drawImage(image.data, 0, 0, image.width, image.height, 0, -h, w, h); - this.restore(); + this.restore(); */ }, paintImageMaskXObject: function canvasGraphicsPaintImageMaskXObject( @@ -1104,7 +1107,7 @@ var CanvasGraphics = (function canvasGraphics() { this.restore(); }, - paintImageXObject: function canvasGraphicsPaintImageXObject(imgData) { + paintNormalImageXObject: function canvasGraphicsPaintImageXObject(imgData) { this.save(); var ctx = this.ctx; var w = imgData.width; @@ -1134,6 +1137,21 @@ 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 284b3cb40..ea9589505 100644 --- a/src/core.js +++ b/src/core.js @@ -6,7 +6,7 @@ var globalScope = (typeof window === 'undefined') ? this : window; var ERRORS = 0, WARNINGS = 1, TODOS = 5; -var verbosity = WARNINGS; +var verbosity = TODOS; // The global PDFJS object exposes the API // In production, it will be declared outside a global wrapper @@ -14,7 +14,7 @@ var verbosity = WARNINGS; if (!globalScope.PDFJS) { globalScope.PDFJS = {}; } - +PDFJS.disableWorker = true; // getPdf() // Convenience function to perform binary Ajax GET // Usage: getPdf('http://...', callback) @@ -440,6 +440,7 @@ var PDFDocModel = (function pdfDoc() { this.startXRef, this.mainXRefEntriesOffset); this.catalog = new Catalog(this.xref); + this.objs = new PDFObjects(); }, get numPages() { var linearization = this.linearization; @@ -559,9 +560,9 @@ var PDFDoc = (function pdfDoc() { var type = data[1]; switch (type) { - case 'JpegStream': - var IR = data[2]; - new JpegImageLoader(id, IR, this.objs); + case 'Jpeg': + var imageData = data[2]; + this.objs.resolve(id, imageData); break; case 'Font': var name = data[2]; @@ -607,6 +608,30 @@ var PDFDoc = (function pdfDoc() { throw data.error; }, this); + messageHandler.on('jpeg_decode', function(message) { + var imageData = message.data[0]; + 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 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]; + } + message.resolve({ data: buf, width: width, height: height}); + }).bind(this); + var src = 'data:image/jpeg;base64,' + window.btoa(imageData); + img.src = src; + }); + setTimeout(function pdfDocFontReadySetTimeout() { messageHandler.send('doc', this.data); this.workerReadyPromise.resolve(true); diff --git a/src/evaluator.js b/src/evaluator.js index 954c3bec3..224d823a4 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -179,21 +179,24 @@ var PartialEvaluator = (function partialEvaluator() { return loadedName; } - function buildPaintImageXObject(image, inline) { + function buildPaintImageXObject(image, inline) { 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); - handler.send('obj', [objId, 'JpegStream', image.getIR()]); + debugger; + handler.send('jpeg_decode', [image.getIR()], function(data) { + handler.send('obj', [objId, 'Jpeg', data]); + }); // Add the dependency on the image object. insertDependency([objId]); // The normal fn. - fn = 'paintJpegXObject'; - args = [objId, w, h]; + args = ['jpeg', [objId, w, h]]; return; } @@ -220,8 +223,7 @@ var PartialEvaluator = (function partialEvaluator() { var pixels = imgData.data; imageObj.fillRgbaBuffer(pixels, imageObj.decode); - fn = 'paintImageXObject'; - args = [imgData]; + args = ['normal', [imgData]]; return; } @@ -230,7 +232,6 @@ var PartialEvaluator = (function partialEvaluator() { // data can't be done here. Instead of creating a // complete PDFImage, only read the information needed // for later. - fn = 'paintImageMaskXObject'; var width = dict.get('Width', 'W'); var height = dict.get('Height', 'H'); @@ -239,7 +240,7 @@ var PartialEvaluator = (function partialEvaluator() { var decode = dict.get('Decode', 'D'); var inverseDecode = !!decode && decode[0] > 0; - args = [imgArray, inverseDecode, width, height]; + args = ['imageMask', [imgArray, inverseDecode, width, height]]; } uniquePrefix = uniquePrefix || ''; diff --git a/src/image.js b/src/image.js index 17ef7b06d..dbb62c99f 100644 --- a/src/image.js +++ b/src/image.js @@ -228,30 +228,3 @@ var PDFImage = (function pdfImage() { }; return constructor; })(); - -var JpegImageLoader = (function jpegImage() { - function JpegImageLoader(objId, imageData, objs) { - var src = 'data:image/jpeg;base64,' + window.btoa(imageData); - - var img = new Image(); - img.onload = (function jpegImageLoaderOnload() { - this.loaded = true; - - objs.resolve(objId, this); - - if (this.onLoad) - this.onLoad(); - }).bind(this); - img.src = src; - this.domImage = img; - } - - JpegImageLoader.prototype = { - getImage: function jpegImageLoaderGetImage() { - return this.domImage; - } - }; - - return JpegImageLoader; -})(); - diff --git a/src/stream.js b/src/stream.js index 559fb2ca2..e4732d87a 100644 --- a/src/stream.js +++ b/src/stream.js @@ -804,6 +804,8 @@ var JpegStream = (function jpegStream() { this.colorTransform = -1; + this.bytes = bytes; + if (isAdobeImage(bytes)) { // when bug 674619 land, let's check if browser can do // normal cmyk and then we won't have to the following diff --git a/src/worker.js b/src/worker.js index 8e4c14fbc..ea314744f 100644 --- a/src/worker.js +++ b/src/worker.js @@ -6,6 +6,8 @@ function MessageHandler(name, comObj) { this.name = name; this.comObj = comObj; + this.callbackIndex = 1; + this.callbacks = {}; var ah = this.actionHandler = {}; ah['console_log'] = [function ahConsoleLog(data) { @@ -14,11 +16,38 @@ function MessageHandler(name, comObj) { ah['console_error'] = [function ahConsoleError(data) { console.error.apply(console, data); }]; + ah['__resolve__'] = [ function(data) { + var callbackId = data.callbackId; + if (data.callbackId in this.callbacks) { + var callback = this.callbacks[callbackId]; + delete this.callbacks[callbackId]; + callback(data.data); + } else { + throw 'Cannot resolve callback ' + callbackId; + } + }, this]; + comObj.onmessage = function messageHandlerComObjOnMessage(event) { var data = event.data; if (data.action in ah) { var action = ah[data.action]; - action[0].call(action[1], data.data); + if (data.callbackId) { + action[0].call(action[1], { + data: data.data, + resolve: (function(callbackId) { + return function(resolvedData) { + comObj.postMessage({ + action: '__resolve__', + data: { + data: resolvedData, + callbackId: data.callbackId + } + }); + }})(data.callbackId) + }); + } else { + action[0].call(action[1], data.data); + } } else { throw 'Unkown action from worker: ' + data.action; } @@ -34,11 +63,17 @@ MessageHandler.prototype = { ah[actionName] = [handler, scope]; }, - send: function messageHandlerSend(actionName, data) { - this.comObj.postMessage({ + send: function messageHandlerSend(actionName, data, callback) { + var message = { action: actionName, data: data - }); + }; + if (callback) { + var callbackId = this.callbackIndex++; + this.callbacks[callbackId] = callback; + message.callbackId = callbackId; + } + this.comObj.postMessage(message); } }; @@ -160,6 +195,13 @@ var WorkerMessageHandler = { handler.send('font_ready', [objId, obj]); }); + + handler.on('jpeg_decoded', function jpegDecoded(data) { + var objId = data[0]; + var imageData = data[1]; + console.log('worker recieved decoded jpeg'); + debugger; + }, this); } };