Use promises to track completion of decoding.
This commit is contained in:
parent
7d1cddf371
commit
683f64d54f
@ -219,10 +219,8 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn = 'paintImageXObject';
|
fn = 'paintImageXObject';
|
||||||
var imageObj = new PDFImage(xref, resources, image, inline, handler);
|
|
||||||
|
|
||||||
imageObj.ready((function() {
|
PDFImage.buildImage(function(imageObj) {
|
||||||
return function(data) {
|
|
||||||
var imgData = {
|
var imgData = {
|
||||||
width: w,
|
width: w,
|
||||||
height: h,
|
height: h,
|
||||||
@ -231,8 +229,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
var pixels = imgData.data;
|
var pixels = imgData.data;
|
||||||
imageObj.fillRgbaBuffer(pixels, imageObj.decode);
|
imageObj.fillRgbaBuffer(pixels, imageObj.decode);
|
||||||
handler.send('obj', [objId, 'Image', imgData]);
|
handler.send('obj', [objId, 'Image', imgData]);
|
||||||
};
|
}, handler, xref, resources, image, inline);
|
||||||
})(objId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uniquePrefix = uniquePrefix || '';
|
uniquePrefix = uniquePrefix || '';
|
||||||
|
86
src/image.js
86
src/image.js
@ -4,11 +4,28 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var PDFImage = (function pdfImage() {
|
var PDFImage = (function pdfImage() {
|
||||||
function constructor(xref, res, image, inline, handler) {
|
/**
|
||||||
|
* 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) {
|
||||||
|
if (image instanceof JpegStream && image.isNative) {
|
||||||
|
// 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;
|
||||||
|
handler.send('jpeg_decode', [image.getIR(), numComps], function(message) {
|
||||||
|
var data = message.data;
|
||||||
|
var stream = new Stream(data, 0, data.length, image.dict);
|
||||||
|
promise.resolve(stream);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
promise.resolve(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function constructor(xref, res, image, inline, smask) {
|
||||||
this.image = image;
|
this.image = image;
|
||||||
this.imageReady = true;
|
|
||||||
this.smaskReady = true;
|
|
||||||
this.callbacks = [];
|
|
||||||
|
|
||||||
if (image.getParams) {
|
if (image.getParams) {
|
||||||
// JPX/JPEG2000 streams directly contain bits per component
|
// JPX/JPEG2000 streams directly contain bits per component
|
||||||
@ -55,31 +72,37 @@ var PDFImage = (function pdfImage() {
|
|||||||
this.decode = dict.get('Decode', 'D');
|
this.decode = dict.get('Decode', 'D');
|
||||||
|
|
||||||
var mask = xref.fetchIfRef(dict.get('Mask'));
|
var mask = xref.fetchIfRef(dict.get('Mask'));
|
||||||
var smask = xref.fetchIfRef(dict.get('SMask'));
|
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
TODO('masked images');
|
TODO('masked images');
|
||||||
} else if (smask) {
|
} else if (smask) {
|
||||||
this.smaskReady = false;
|
this.smask = new PDFImage(xref, res, smask, 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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Handles processing of image data and calls the callback with an argument
|
||||||
|
* of a PDFImage when the image is ready to be used.
|
||||||
|
*/
|
||||||
|
constructor.buildImage = function buildImage(callback, handler, xref, res,
|
||||||
|
image, inline) {
|
||||||
|
var promise = new Promise();
|
||||||
|
var smaskPromise = new Promise();
|
||||||
|
var promises = [promise, smaskPromise];
|
||||||
|
// The image data and smask data may not be ready yet, wait till both are
|
||||||
|
// resolved.
|
||||||
|
Promise.all(promises).then(function(results) {
|
||||||
|
var image = new PDFImage(xref, res, results[0], inline, results[1]);
|
||||||
|
callback(image);
|
||||||
|
});
|
||||||
|
|
||||||
|
handleImageData(handler, xref, res, image, promise);
|
||||||
|
|
||||||
|
var smask = xref.fetchIfRef(image.dict.get('SMask'));
|
||||||
|
if (smask)
|
||||||
|
handleImageData(handler, xref, res, smask, smaskPromise);
|
||||||
|
else
|
||||||
|
smaskPromise.resolve(null);
|
||||||
|
};
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
getComponents: function getComponents(buffer, decodeMap) {
|
getComponents: function getComponents(buffer, decodeMap) {
|
||||||
@ -151,8 +174,6 @@ var PDFImage = (function pdfImage() {
|
|||||||
var buf = new Uint8Array(width * height);
|
var buf = new Uint8Array(width * height);
|
||||||
|
|
||||||
if (smask) {
|
if (smask) {
|
||||||
if (!smask.isReady())
|
|
||||||
error('Soft mask is not ready.');
|
|
||||||
var sw = smask.width;
|
var sw = smask.width;
|
||||||
var sh = smask.height;
|
var sh = smask.height;
|
||||||
if (sw != this.width || sh != this.height)
|
if (sw != this.width || sh != this.height)
|
||||||
@ -234,23 +255,8 @@ var PDFImage = (function pdfImage() {
|
|||||||
buffer[i] = comps[i];
|
buffer[i] = comps[i];
|
||||||
},
|
},
|
||||||
getImageBytes: function getImageBytes(length) {
|
getImageBytes: function getImageBytes(length) {
|
||||||
if (!this.isReady())
|
|
||||||
error('Image is not ready to be read.');
|
|
||||||
this.image.reset();
|
this.image.reset();
|
||||||
return this.image.getBytes(length);
|
return this.image.getBytes(length);
|
||||||
},
|
|
||||||
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;
|
return constructor;
|
||||||
|
28
src/util.js
28
src/util.js
@ -217,7 +217,33 @@ var Promise = (function promise() {
|
|||||||
}
|
}
|
||||||
this.callbacks = [];
|
this.callbacks = [];
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Builds a promise that is resolved when all the passed in promises are
|
||||||
|
* resolved.
|
||||||
|
* @param Array promises
|
||||||
|
* @return Promise
|
||||||
|
*/
|
||||||
|
Promise.all = function(promises) {
|
||||||
|
var deferred = new Promise();
|
||||||
|
var unresolved = promises.length;
|
||||||
|
var results = [];
|
||||||
|
if (unresolved === 0) {
|
||||||
|
deferred.resolve(results);
|
||||||
|
return deferred;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < unresolved; ++i) {
|
||||||
|
var promise = promises[i];
|
||||||
|
promise.then((function(i) {
|
||||||
|
return function(value) {
|
||||||
|
results[i] = value;
|
||||||
|
unresolved--;
|
||||||
|
if (unresolved === 0)
|
||||||
|
deferred.resolve(results);
|
||||||
|
};
|
||||||
|
})(i));
|
||||||
|
}
|
||||||
|
return deferred;
|
||||||
|
};
|
||||||
Promise.prototype = {
|
Promise.prototype = {
|
||||||
hasData: false,
|
hasData: false,
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user