Implement paintReadyJpegXObject + add infrastructure to handle JpegStreams
This commit is contained in:
parent
5bfa9e4f3b
commit
d887d2bd29
106
pdf.js
106
pdf.js
@ -859,6 +859,31 @@ var PredictorStream = (function() {
|
|||||||
return constructor;
|
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
|
// A JpegStream can't be read directly. We use the platform to render
|
||||||
// the underlying JPEG data for us.
|
// the underlying JPEG data for us.
|
||||||
var JpegStream = (function() {
|
var JpegStream = (function() {
|
||||||
@ -891,30 +916,23 @@ var JpegStream = (function() {
|
|||||||
newBytes.set(embedMarker, 2);
|
newBytes.set(embedMarker, 2);
|
||||||
return newBytes;
|
return newBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructor(bytes, dict) {
|
function constructor(bytes, dict) {
|
||||||
// TODO: per poppler, some images may have "junk" before that
|
// TODO: per poppler, some images may have "junk" before that
|
||||||
// need to be removed
|
// need to be removed
|
||||||
this.dict = dict;
|
this.dict = dict;
|
||||||
|
|
||||||
if (isYcckImage(bytes))
|
if (isYcckImage(bytes))
|
||||||
bytes = fixYcckImage(bytes);
|
bytes = fixYcckImage(bytes);
|
||||||
|
|
||||||
// create DOM image
|
this.src = 'data:image/jpeg;base64,' + window.btoa(bytesToString(bytes));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
getImage: function() {
|
getIR: function() {
|
||||||
return this.domImage;
|
return this.src;
|
||||||
},
|
},
|
||||||
|
|
||||||
getChar: function() {
|
getChar: function() {
|
||||||
error('internal error: getChar is not valid on JpegStream');
|
error('internal error: getChar is not valid on JpegStream');
|
||||||
}
|
}
|
||||||
@ -4100,6 +4118,8 @@ var EvalState = (function() {
|
|||||||
var FontsMap = {};
|
var FontsMap = {};
|
||||||
var FontLoadedCounter = 0;
|
var FontLoadedCounter = 0;
|
||||||
|
|
||||||
|
var objIdCounter = 0;
|
||||||
|
|
||||||
var PartialEvaluator = (function() {
|
var PartialEvaluator = (function() {
|
||||||
function constructor() {
|
function constructor() {
|
||||||
this.state = new EvalState();
|
this.state = new EvalState();
|
||||||
@ -4273,25 +4293,27 @@ var PartialEvaluator = (function() {
|
|||||||
fonts, images, uniquePrefix);
|
fonts, images, uniquePrefix);
|
||||||
var matrix = xobj.dict.get('Matrix');
|
var matrix = xobj.dict.get('Matrix');
|
||||||
var bbox = xobj.dict.get('BBox');
|
var bbox = xobj.dict.get('BBox');
|
||||||
args = [raw, matrix, bbox];
|
args = [ raw, matrix, bbox ];
|
||||||
fn = "paintReadyFormXObject";
|
fn = "paintReadyFormXObject";
|
||||||
}
|
} else if ('Image' == type.name) {
|
||||||
if (xobj instanceof JpegStream) {
|
var image = xobj;
|
||||||
images.bind(xobj); // monitoring image load
|
var dict = image.dict;
|
||||||
// console.log("got xobj that is a JpegStream");
|
var w = dict.get('Width', 'W');
|
||||||
}
|
var h = dict.get('Height', 'H');
|
||||||
|
|
||||||
if (xobj.dict.get('Subtype').name == "Image") {
|
if (image instanceof JpegStream) {
|
||||||
// Check if we have an image that is not rendered by the platform.
|
var objId = ++objIdCounter;
|
||||||
// Needs to be rendered ourself.
|
images.push({
|
||||||
if (!(xobj instanceof JpegStream)) {
|
id: objId,
|
||||||
var image = xobj;
|
IR: image.getIR()
|
||||||
var dict = image.dict;
|
});
|
||||||
var w = dict.get('Width', 'W');
|
|
||||||
var h = dict.get('Height', 'H');
|
// TODO: Place dependency note in IR queue.
|
||||||
|
fn = 'paintReadyJpegXObject';
|
||||||
|
args = [ objId, w, h ];
|
||||||
|
} else {
|
||||||
|
// Needs to be rendered ourself.
|
||||||
var inline = false;
|
var inline = false;
|
||||||
|
|
||||||
var imageObj = new PDFImage(xref, resources, image, inline);
|
var imageObj = new PDFImage(xref, resources, image, inline);
|
||||||
|
|
||||||
if (imageObj.imageMask) {
|
if (imageObj.imageMask) {
|
||||||
@ -4308,12 +4330,10 @@ var PartialEvaluator = (function() {
|
|||||||
|
|
||||||
fn = "paintReadyImageXObject";
|
fn = "paintReadyImageXObject";
|
||||||
args = [ imgData ];
|
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
|
} else if (cmd == 'Tf') { // eagerly collect all fonts
|
||||||
var fontName = args[0].name;
|
var fontName = args[0].name;
|
||||||
@ -5533,6 +5553,24 @@ var CanvasGraphics = (function() {
|
|||||||
this.restore();
|
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) {
|
paintImageXObject: function(ref, image, inline) {
|
||||||
this.save();
|
this.save();
|
||||||
|
|
||||||
|
29
worker.js
29
worker.js
@ -50,6 +50,9 @@ var WorkerPage = (function() {
|
|||||||
return constructor;
|
return constructor;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// This holds a list of objects the IR queue depends on.
|
||||||
|
var Objects = {};
|
||||||
|
|
||||||
var WorkerPDFDoc = (function() {
|
var WorkerPDFDoc = (function() {
|
||||||
function constructor(data) {
|
function constructor(data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
@ -60,7 +63,7 @@ var WorkerPDFDoc = (function() {
|
|||||||
|
|
||||||
this.pageCache = [];
|
this.pageCache = [];
|
||||||
|
|
||||||
var useWorker = true;
|
var useWorker = false;
|
||||||
|
|
||||||
if (useWorker) {
|
if (useWorker) {
|
||||||
var worker = new Worker("../worker/boot.js");
|
var worker = new Worker("../worker/boot.js");
|
||||||
@ -90,9 +93,27 @@ var WorkerPDFDoc = (function() {
|
|||||||
font.file.end - font.file.start, fontFileDict);
|
font.file.end - font.file.start, fontFileDict);
|
||||||
font.file = new FlateStream(fontFile);
|
font.file = new FlateStream(fontFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("startRenderingFromPreCompilation:", "numberOfFonts", fonts.length);
|
var imageLoadingDone = function() {
|
||||||
page.startRenderingFromPreCompilation(data.preCompilation, data.fonts, data.images);
|
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);
|
}, this);
|
||||||
|
|
||||||
if (!useWorker) {
|
if (!useWorker) {
|
||||||
|
@ -22,8 +22,7 @@ var WorkerHandler = {
|
|||||||
// but stops at one point and sends the result back to the main thread.
|
// but stops at one point and sends the result back to the main thread.
|
||||||
var gfx = new CanvasGraphics(null);
|
var gfx = new CanvasGraphics(null);
|
||||||
var fonts = [];
|
var fonts = [];
|
||||||
// TODO: Figure out how image loading is handled inside the worker.
|
var images = [];
|
||||||
var images = new ImagesLoader();
|
|
||||||
|
|
||||||
// Pre compile the pdf page and fetch the fonts/images.
|
// Pre compile the pdf page and fetch the fonts/images.
|
||||||
var preCompilation = page.preCompile(gfx, fonts, images);
|
var preCompilation = page.preCompile(gfx, fonts, images);
|
||||||
@ -76,9 +75,9 @@ var WorkerHandler = {
|
|||||||
handler.send("page", {
|
handler.send("page", {
|
||||||
pageNum: pageNum,
|
pageNum: pageNum,
|
||||||
fonts: fontsMin,
|
fonts: fontsMin,
|
||||||
images: [],
|
images: images,
|
||||||
preCompilation: preCompilation,
|
preCompilation: preCompilation,
|
||||||
});
|
});
|
||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user