From a00f8548489d1db72118f387e0fc23a53beff452 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 14 Apr 2014 15:22:35 -0500 Subject: [PATCH] Refactors buildImage to use Promise; don't draw bad images --- src/core/evaluator.js | 10 +++++--- src/core/image.js | 56 +++++++++++++++++++++---------------------- src/display/api.js | 2 +- src/display/canvas.js | 9 ++++--- 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/core/evaluator.js b/src/core/evaluator.js index e189a6ab4..6d8452c34 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -206,11 +206,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { return; } - PDFImage.buildImage(function(imageObj) { + PDFImage.buildImage(self.handler, self.xref, resources, image, inline). + then(function(imageObj) { var imgData = imageObj.createImageData(/* forceRGBA = */ false); self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData], - null, [imgData.data.buffer]); - }, self.handler, self.xref, resources, image, inline); + null, [imgData.data.buffer]); + }).then(null, function (reason) { + warn('Unable to decode image: ' + reason); + self.handler.send('obj', [objId, self.pageIndex, 'Image', null]); + }); operatorList.addOp(OPS.paintImageXObject, args); if (cacheKey) { diff --git a/src/core/image.js b/src/core/image.js index 19d867a43..14f93f352 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -15,7 +15,7 @@ * limitations under the License. */ /* globals ColorSpace, DecodeStream, error, info, isArray, ImageKind, isStream, - JpegStream, JpxImage, Name, Promise, Stream, warn, LegacyPromise */ + JpegStream, JpxImage, Name, Promise, Stream, warn */ 'use strict'; @@ -24,20 +24,24 @@ var PDFImage = (function PDFImageClosure() { * Decode the image in the main thread if it supported. Resovles the promise * when the image data is ready. */ - function handleImageData(handler, xref, res, image, promise) { + function handleImageData(handler, xref, res, image) { if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) { // For natively supported jpegs send them to the main thread for decoding. var dict = image.dict; var colorSpace = dict.get('ColorSpace', 'CS'); colorSpace = ColorSpace.parse(colorSpace, xref, res); var numComps = colorSpace.numComps; + var resolvePromise; handler.send('JpegDecode', [image.getIR(), numComps], function(message) { var data = message.data; var stream = new Stream(data, 0, data.length, image.dict); - promise.resolve(stream); + resolvePromise(stream); + }); + return new Promise(function (resolve) { + resolvePromise = resolve; }); } else { - promise.resolve(image); + return Promise.resolve(image); } } /** @@ -144,47 +148,43 @@ var PDFImage = (function PDFImageClosure() { } } /** - * Handles processing of image data and calls the callback with an argument - * of a PDFImage when the image is ready to be used. + * Handles processing of image data and returns the Promise that is resolved + * with a PDFImage when the image is ready to be used. */ - PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref, + PDFImage.buildImage = function PDFImage_buildImage(handler, xref, res, image, inline) { - var imageDataPromise = new LegacyPromise(); - var smaskPromise = new LegacyPromise(); - var maskPromise = new LegacyPromise(); - // The image data and smask data may not be ready yet, wait until both are - // resolved. - Promise.all([imageDataPromise, smaskPromise, maskPromise]).then( - function(results) { - var imageData = results[0], smaskData = results[1], maskData = results[2]; - var image = new PDFImage(xref, res, imageData, inline, smaskData, - maskData); - callback(image); - }); - - handleImageData(handler, xref, res, image, imageDataPromise); + var imagePromise = handleImageData(handler, xref, res, image); + var smaskPromise; + var maskPromise; var smask = image.dict.get('SMask'); var mask = image.dict.get('Mask'); if (smask) { - handleImageData(handler, xref, res, smask, smaskPromise); - maskPromise.resolve(null); + smaskPromise = handleImageData(handler, xref, res, smask); + maskPromise = Promise.resolve(null); } else { - smaskPromise.resolve(null); + smaskPromise = Promise.resolve(null); if (mask) { if (isStream(mask)) { - handleImageData(handler, xref, res, mask, maskPromise); + maskPromise = handleImageData(handler, xref, res, mask); } else if (isArray(mask)) { - maskPromise.resolve(mask); + maskPromise = Promise.resolve(mask); } else { warn('Unsupported mask format.'); - maskPromise.resolve(null); + maskPromise = Promise.resolve(null); } } else { - maskPromise.resolve(null); + maskPromise = Promise.resolve(null); } } + return Promise.all([imagePromise, smaskPromise, maskPromise]).then( + function(results) { + var imageData = results[0]; + var smaskData = results[1]; + var maskData = results[2]; + return new PDFImage(xref, res, imageData, inline, smaskData, maskData); + }); }; /** diff --git a/src/display/api.js b/src/display/api.js index e849d53bc..fb82f5c8b 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -912,7 +912,7 @@ var WorkerTransport = (function WorkerTransportClosure() { // heuristics that will allow not to store large data var MAX_IMAGE_SIZE_TO_STORE = 8000000; - if ('data' in imageData && + if (imageData && 'data' in imageData && imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) { pageProxy.cleanupAfterRender = true; } diff --git a/src/display/canvas.js b/src/display/canvas.js index 9e6414f4a..9e77e2255 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -1824,7 +1824,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) { var domImage = this.objs.get(objId); if (!domImage) { - error('Dependent image isn\'t ready yet'); + warn('Dependent image isn\'t ready yet'); + return; } this.save(); @@ -1958,7 +1959,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { paintImageXObject: function CanvasGraphics_paintImageXObject(objId) { var imgData = this.objs.get(objId); if (!imgData) { - error('Dependent image isn\'t ready yet'); + warn('Dependent image isn\'t ready yet'); + return; } this.paintInlineImageXObject(imgData); @@ -1969,7 +1971,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { positions) { var imgData = this.objs.get(objId); if (!imgData) { - error('Dependent image isn\'t ready yet'); + warn('Dependent image isn\'t ready yet'); + return; } var width = imgData.width;