Implement paintReadyJpegXObject + add infrastructure to handle JpegStreams

This commit is contained in:
Julian Viereck 2011-09-07 14:45:38 -07:00
parent 5bfa9e4f3b
commit d887d2bd29
3 changed files with 100 additions and 42 deletions

106
pdf.js
View File

@ -859,6 +859,31 @@ var PredictorStream = (function() {
return constructor;
})();
var JpegStreamIR = (function() {
function JpegStreamIR(objId, IR) {
var src = IR;
// create DOM image
var img = new Image();
img.onload = (function() {
this.loaded = true;
Objects[objId] = this;
if (this.onLoad)
this.onLoad();
}).bind(this);
img.src = src;
this.domImage = img;
}
JpegStreamIR.prototype = {
getImage: function() {
return this.domImage;
}
}
return JpegStreamIR;
})()
// A JpegStream can't be read directly. We use the platform to render
// the underlying JPEG data for us.
var JpegStream = (function() {
@ -891,30 +916,23 @@ var JpegStream = (function() {
newBytes.set(embedMarker, 2);
return newBytes;
}
function constructor(bytes, dict) {
// TODO: per poppler, some images may have "junk" before that
// need to be removed
this.dict = dict;
if (isYcckImage(bytes))
bytes = fixYcckImage(bytes);
// create DOM image
var img = new Image();
img.onload = (function() {
this.loaded = true;
if (this.onLoad)
this.onLoad();
}).bind(this);
img.src = 'data:image/jpeg;base64,' + window.btoa(bytesToString(bytes));
this.domImage = img;
this.src = 'data:image/jpeg;base64,' + window.btoa(bytesToString(bytes));
}
constructor.prototype = {
getImage: function() {
return this.domImage;
getIR: function() {
return this.src;
},
getChar: function() {
error('internal error: getChar is not valid on JpegStream');
}
@ -4100,6 +4118,8 @@ var EvalState = (function() {
var FontsMap = {};
var FontLoadedCounter = 0;
var objIdCounter = 0;
var PartialEvaluator = (function() {
function constructor() {
this.state = new EvalState();
@ -4273,25 +4293,27 @@ var PartialEvaluator = (function() {
fonts, images, uniquePrefix);
var matrix = xobj.dict.get('Matrix');
var bbox = xobj.dict.get('BBox');
args = [raw, matrix, bbox];
args = [ raw, matrix, bbox ];
fn = "paintReadyFormXObject";
}
if (xobj instanceof JpegStream) {
images.bind(xobj); // monitoring image load
// console.log("got xobj that is a JpegStream");
}
if (xobj.dict.get('Subtype').name == "Image") {
// Check if we have an image that is not rendered by the platform.
// Needs to be rendered ourself.
if (!(xobj instanceof JpegStream)) {
var image = xobj;
var dict = image.dict;
var w = dict.get('Width', 'W');
var h = dict.get('Height', 'H');
} else if ('Image' == type.name) {
var image = xobj;
var dict = image.dict;
var w = dict.get('Width', 'W');
var h = dict.get('Height', 'H');
if (image instanceof JpegStream) {
var objId = ++objIdCounter;
images.push({
id: objId,
IR: image.getIR()
});
// TODO: Place dependency note in IR queue.
fn = 'paintReadyJpegXObject';
args = [ objId, w, h ];
} else {
// Needs to be rendered ourself.
var inline = false;
var imageObj = new PDFImage(xref, resources, image, inline);
if (imageObj.imageMask) {
@ -4308,12 +4330,10 @@ var PartialEvaluator = (function() {
fn = "paintReadyImageXObject";
args = [ imgData ];
// console.log("xobj subtype image", w, h, imageObj.imageMask);
}
} else {
error('Unhandled XObject subtype ' + type.name);
}
// console.log("xobj subtype", xobj.dict.get('Subtype').name);
}
} else if (cmd == 'Tf') { // eagerly collect all fonts
var fontName = args[0].name;
@ -5533,6 +5553,24 @@ var CanvasGraphics = (function() {
this.restore();
},
paintReadyJpegXObject: function(objId, w, h) {
var image = Objects[objId];
if (!image) {
error("Dependent image isn't ready yet");
}
this.save();
var ctx = this.ctx;
ctx.scale(1 / w, -1 / h);
var domImage = image.getImage();
ctx.drawImage(domImage, 0, 0, domImage.width, domImage.height,
0, -h, w, h);
this.restore();
},
paintImageXObject: function(ref, image, inline) {
this.save();

View File

@ -50,6 +50,9 @@ var WorkerPage = (function() {
return constructor;
})();
// This holds a list of objects the IR queue depends on.
var Objects = {};
var WorkerPDFDoc = (function() {
function constructor(data) {
this.data = data;
@ -60,7 +63,7 @@ var WorkerPDFDoc = (function() {
this.pageCache = [];
var useWorker = true;
var useWorker = false;
if (useWorker) {
var worker = new Worker("../worker/boot.js");
@ -90,9 +93,27 @@ var WorkerPDFDoc = (function() {
font.file.end - font.file.start, fontFileDict);
font.file = new FlateStream(fontFile);
}
console.log("startRenderingFromPreCompilation:", "numberOfFonts", fonts.length);
page.startRenderingFromPreCompilation(data.preCompilation, data.fonts, data.images);
var imageLoadingDone = function() {
console.log("startRenderingFromPreCompilation:", "numberOfFonts", fonts.length);
page.startRenderingFromPreCompilation(data.preCompilation, data.fonts, data.images);
}
var images = data.images;
if (images.length != 0) {
// Generate JpegStreams based on IR information and start rendering
// once the compilation is done.
var loader = new ImagesLoader();
loader.onLoad = imageLoadingDone;
for (var i = 0; i < images.length; i++) {
var image = images[i];
var stream = new JpegStreamIR(image.id, image.IR);
loader.bind(stream);
}
} else {
imageLoadingDone();
}
}, this);
if (!useWorker) {

View File

@ -22,8 +22,7 @@ var WorkerHandler = {
// but stops at one point and sends the result back to the main thread.
var gfx = new CanvasGraphics(null);
var fonts = [];
// TODO: Figure out how image loading is handled inside the worker.
var images = new ImagesLoader();
var images = [];
// Pre compile the pdf page and fetch the fonts/images.
var preCompilation = page.preCompile(gfx, fonts, images);
@ -76,9 +75,9 @@ var WorkerHandler = {
handler.send("page", {
pageNum: pageNum,
fonts: fontsMin,
images: [],
images: images,
preCompilation: preCompilation,
});
}, this);
}
}
}