Merge branch 'master' of github.com:andreasgal/pdf.js
Conflicts: pdf.js
This commit is contained in:
commit
7077ad5b67
219
pdf.js
219
pdf.js
@ -590,7 +590,7 @@ function IsString(v) {
|
||||
}
|
||||
|
||||
function IsNull(v) {
|
||||
return v == null;
|
||||
return v === null;
|
||||
}
|
||||
|
||||
function IsName(v) {
|
||||
@ -630,14 +630,6 @@ function IsPDFFunction(v) {
|
||||
return fnDict.has("FunctionType");
|
||||
}
|
||||
|
||||
function IsFunctionDict(v) {
|
||||
return IsFunction(v) && IsDict(v);
|
||||
}
|
||||
|
||||
function IsFunctionStream(v) {
|
||||
return IsFunction(v) && IsStream(v);
|
||||
}
|
||||
|
||||
var EOF = {};
|
||||
|
||||
function IsEOF(v) {
|
||||
@ -841,10 +833,12 @@ var Lexer = (function() {
|
||||
ch = stream.getChar();
|
||||
if (ch == '>') {
|
||||
break;
|
||||
} else if (!ch) {
|
||||
}
|
||||
if (!ch) {
|
||||
warn("Unterminated hex string");
|
||||
break;
|
||||
} else if (specialChars[ch.charCodeAt(0)] != 1) {
|
||||
}
|
||||
if (specialChars[ch.charCodeAt(0)] != 1) {
|
||||
var x, x2;
|
||||
if (((x = ToHexDigit(ch)) == -1) ||
|
||||
((x2 = ToHexDigit(stream.getChar())) == -1)) {
|
||||
@ -1373,8 +1367,8 @@ var Page = (function() {
|
||||
}
|
||||
|
||||
constructor.prototype = {
|
||||
get contents() {
|
||||
return shadow(this, "contents", this.pageDict.get("Contents"));
|
||||
get content() {
|
||||
return shadow(this, "content", this.pageDict.get("Contents"));
|
||||
},
|
||||
get resources() {
|
||||
return shadow(this, "resources", this.pageDict.get("Resources"));
|
||||
@ -1385,18 +1379,25 @@ var Page = (function() {
|
||||
? obj
|
||||
: null));
|
||||
},
|
||||
compile: function(gfx, fonts) {
|
||||
if (!this.code) {
|
||||
var xref = this.xref;
|
||||
var content = xref.fetchIfRef(this.content);
|
||||
var resources = xref.fetchIfRef(this.resources);
|
||||
this.code = gfx.compile(content, xref, resources, fonts);
|
||||
}
|
||||
},
|
||||
display: function(gfx) {
|
||||
var xref = this.xref;
|
||||
var contents = xref.fetchIfRef(this.contents);
|
||||
var content = xref.fetchIfRef(this.content);
|
||||
var resources = xref.fetchIfRef(this.resources);
|
||||
var mediaBox = xref.fetchIfRef(this.mediaBox);
|
||||
assertWellFormed(IsStream(contents) && IsDict(resources),
|
||||
"invalid page contents or resources");
|
||||
assertWellFormed(IsStream(content) && IsDict(resources),
|
||||
"invalid page content or resources");
|
||||
gfx.beginDrawing({ x: mediaBox[0], y: mediaBox[1],
|
||||
width: mediaBox[2] - mediaBox[0],
|
||||
height: mediaBox[3] - mediaBox[1] });
|
||||
gfx.interpret(new Parser(new Lexer(contents), false),
|
||||
xref, resources);
|
||||
gfx.execute(this.code, xref, resources);
|
||||
gfx.endDrawing();
|
||||
}
|
||||
};
|
||||
@ -1605,65 +1606,65 @@ var CanvasGraphics = (function() {
|
||||
this.xobjs = null;
|
||||
this.map = {
|
||||
// Graphics state
|
||||
w: this.setLineWidth,
|
||||
J: this.setLineCap,
|
||||
j: this.setLineJoin,
|
||||
d: this.setDash,
|
||||
ri: this.setRenderingIntent,
|
||||
i: this.setFlatness,
|
||||
gs: this.setGState,
|
||||
q: this.save,
|
||||
Q: this.restore,
|
||||
cm: this.transform,
|
||||
w: "setLineWidth",
|
||||
J: "setLineCap",
|
||||
j: "setLineJoin",
|
||||
d: "setDash",
|
||||
ri: "setRenderingIntent",
|
||||
i: "setFlatness",
|
||||
gs: "setGState",
|
||||
q: "save",
|
||||
Q: "restore",
|
||||
cm: "transform",
|
||||
|
||||
// Path
|
||||
m: this.moveTo,
|
||||
l: this.lineTo,
|
||||
c: this.curveTo,
|
||||
h: this.closePath,
|
||||
re: this.rectangle,
|
||||
S: this.stroke,
|
||||
f: this.fill,
|
||||
"f*": this.eoFill,
|
||||
B: this.fillStroke,
|
||||
b: this.closeFillStroke,
|
||||
n: this.endPath,
|
||||
m: "moveTo",
|
||||
l: "lineTo",
|
||||
c: "curveTo",
|
||||
h: "closePath",
|
||||
re: "rectangle",
|
||||
S: "stroke",
|
||||
f: "fill",
|
||||
"f*": "eoFill",
|
||||
B: "fillStroke",
|
||||
b: "closeFillStroke",
|
||||
n: "endPath",
|
||||
|
||||
// Clipping
|
||||
W: this.clip,
|
||||
"W*": this.eoClip,
|
||||
W: "clip",
|
||||
"W*": "eoClip",
|
||||
|
||||
// Text
|
||||
BT: this.beginText,
|
||||
ET: this.endText,
|
||||
TL: this.setLeading,
|
||||
Tf: this.setFont,
|
||||
Td: this.moveText,
|
||||
Tm: this.setTextMatrix,
|
||||
"T*": this.nextLine,
|
||||
Tj: this.showText,
|
||||
TJ: this.showSpacedText,
|
||||
BT: "beginText",
|
||||
ET: "endText",
|
||||
TL: "setLeading",
|
||||
Tf: "setFont",
|
||||
Td: "moveText",
|
||||
Tm: "setTextMatrix",
|
||||
"T*": "nextLine",
|
||||
Tj: "showText",
|
||||
TJ: "showSpacedText",
|
||||
|
||||
// Type3 fonts
|
||||
|
||||
// Color
|
||||
CS: this.setStrokeColorSpace,
|
||||
cs: this.setFillColorSpace,
|
||||
SC: this.setStrokeColor,
|
||||
SCN: this.setStrokeColorN,
|
||||
sc: this.setFillColor,
|
||||
scn: this.setFillColorN,
|
||||
G: this.setStrokeGray,
|
||||
g: this.setFillGray,
|
||||
RG: this.setStrokeRGBColor,
|
||||
rg: this.setFillRGBColor,
|
||||
CS: "setStrokeColorSpace",
|
||||
cs: "setFillColorSpace",
|
||||
SC: "setStrokeColor",
|
||||
SCN: "setStrokeColorN",
|
||||
sc: "setFillColor",
|
||||
scn: "setFillColorN",
|
||||
G: "setStrokeGray",
|
||||
g: "setFillGray",
|
||||
RG: "setStrokeRGBColor",
|
||||
rg: "setFillRGBColor",
|
||||
|
||||
// Shading
|
||||
sh: this.shadingFill,
|
||||
sh: "shadingFill",
|
||||
|
||||
// Images
|
||||
// XObjects
|
||||
Do: this.paintXObject,
|
||||
Do: "paintXObject",
|
||||
|
||||
// Marked content
|
||||
// Compatibility
|
||||
@ -1676,6 +1677,10 @@ var CanvasGraphics = (function() {
|
||||
const EO_CLIP = {};
|
||||
|
||||
constructor.prototype = {
|
||||
translateFont: function(fontDict, xref, resources) {
|
||||
return "translated";
|
||||
},
|
||||
|
||||
beginDrawing: function(mediaBox) {
|
||||
var cw = this.ctx.canvas.width, ch = this.ctx.canvas.height;
|
||||
this.ctx.save();
|
||||
@ -1683,12 +1688,35 @@ var CanvasGraphics = (function() {
|
||||
this.ctx.translate(0, -mediaBox.height);
|
||||
},
|
||||
|
||||
interpret: function(parser, xref, resources) {
|
||||
execute: function(code, xref, resources) {
|
||||
var savedXref = this.xref, savedRes = this.res, savedXobjs = this.xobjs;
|
||||
this.xref = xref;
|
||||
this.res = resources || new Dict();
|
||||
this.xobjs = this.res.get("XObject") || new Dict();
|
||||
this.xobjs = this.xref.fetchIfRef(this.xobjs);
|
||||
this.xobjs = xref.fetchIfRef(this.res.get("XObject")) || new Dict();
|
||||
|
||||
code(this);
|
||||
|
||||
this.xobjs = savedXobjs;
|
||||
this.res = savedRes;
|
||||
this.xref = savedXref;
|
||||
},
|
||||
|
||||
compile: function(stream, xref, resources, fonts) {
|
||||
var xobjs = xref.fetchIfRef(resources.get("XObject")) || new Dict();
|
||||
|
||||
var parser = new Parser(new Lexer(stream), false);
|
||||
var objpool = [];
|
||||
|
||||
function emitArg(arg) {
|
||||
if (typeof arg == "object" || typeof arg == "string") {
|
||||
var index = objpool.length;
|
||||
objpool[index] = arg;
|
||||
return "objpool[" + index + "]";
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
var src = "";
|
||||
|
||||
var args = [];
|
||||
var map = this.map;
|
||||
@ -1699,7 +1727,46 @@ var CanvasGraphics = (function() {
|
||||
var fn = map[cmd];
|
||||
assertWellFormed(fn, "Unknown command '" + cmd + "'");
|
||||
// TODO figure out how to type-check vararg functions
|
||||
fn.apply(this, args);
|
||||
|
||||
if (cmd == "Do" && !args[0].code) { // eagerly compile XForm objects
|
||||
var name = args[0].name;
|
||||
var xobj = xobjs.get(name);
|
||||
if (xobj) {
|
||||
xobj = xref.fetchIfRef(xobj);
|
||||
assertWellFormed(IsStream(xobj), "XObject should be a stream");
|
||||
|
||||
var type = xobj.dict.get("Subtype");
|
||||
assertWellFormed(IsName(type), "XObject should have a Name subtype");
|
||||
|
||||
if ("Form" == type.name) {
|
||||
args[0].code = this.compile(xobj,
|
||||
xref,
|
||||
xobj.dict.get("Resources"),
|
||||
fonts);
|
||||
}
|
||||
}
|
||||
} else if (cmd == "Tf") { // eagerly collect all fonts
|
||||
var fontRes = resources.get("Font");
|
||||
if (fontRes) {
|
||||
fontRes = xref.fetchIfRef(fontRes);
|
||||
var font = xref.fetchIfRef(fontRes.get(args[0].name));
|
||||
assertWellFormed(IsDict(font));
|
||||
if (!font.translated) {
|
||||
font.translated = this.translateFont(font, xref, resources);
|
||||
if (fonts && font.translated) {
|
||||
// keep track of each font we translated so the caller can
|
||||
// load them asynchronously before calling display on a page
|
||||
fonts.push(font.translated);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
src += "this.";
|
||||
src += fn;
|
||||
src += "(";
|
||||
src += args.map(emitArg).join(",");
|
||||
src += ");\n";
|
||||
|
||||
args.length = 0;
|
||||
} else {
|
||||
@ -1708,9 +1775,8 @@ var CanvasGraphics = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
this.xobjs = savedXobjs;
|
||||
this.res = savedRes;
|
||||
this.xref = savedXref;
|
||||
var fn = Function("objpool", src);
|
||||
return function (gfx) { fn.call(gfx, objpool); };
|
||||
},
|
||||
|
||||
endDrawing: function() {
|
||||
@ -2012,9 +2078,9 @@ var CanvasGraphics = (function() {
|
||||
var type = xobj.dict.get("Subtype");
|
||||
assertWellFormed(IsName(type), "XObject should have a Name subtype");
|
||||
if ("Image" == type.name) {
|
||||
this.paintImageXObject(xobj, false);
|
||||
this.paintImageXObject(obj, xobj, false);
|
||||
} else if ("Form" == type.name) {
|
||||
this.paintFormXObject(xobj);
|
||||
this.paintFormXObject(obj, xobj);
|
||||
} else if ("PS" == type.name) {
|
||||
warn("(deprecated) PostScript XObjects are not supported");
|
||||
} else {
|
||||
@ -2022,27 +2088,26 @@ var CanvasGraphics = (function() {
|
||||
}
|
||||
},
|
||||
|
||||
paintFormXObject: function(form) {
|
||||
paintFormXObject: function(ref, stream) {
|
||||
this.save();
|
||||
|
||||
var matrix = form.dict.get("Matrix");
|
||||
var matrix = stream.dict.get("Matrix");
|
||||
if (matrix && IsArray(matrix) && 6 == matrix.length)
|
||||
this.transform.apply(this, matrix);
|
||||
|
||||
var bbox = form.dict.get("BBox");
|
||||
var bbox = stream.dict.get("BBox");
|
||||
if (bbox && IsArray(bbox) && 4 == bbox.length) {
|
||||
this.rectangle.apply(this, bbox);
|
||||
this.clip();
|
||||
this.endPath();
|
||||
}
|
||||
|
||||
this.interpret(new Parser(new Lexer(form), false),
|
||||
this.xref, form.dict.get("Resources"));
|
||||
this.execute(ref.code, this.xref, stream.dict.get("Resources"));
|
||||
|
||||
this.restore();
|
||||
},
|
||||
|
||||
paintImageXObject: function(image, inline) {
|
||||
paintImageXObject: function(ref, image, inline) {
|
||||
this.save();
|
||||
if (image.getParams) {
|
||||
// JPX/JPEG2000 streams directly contain bits per component
|
||||
|
13
test.html
13
test.html
@ -95,11 +95,20 @@ function displayPage(num) {
|
||||
ctx.restore();
|
||||
|
||||
var gfx = new CanvasGraphics(ctx);
|
||||
page.display(gfx);
|
||||
|
||||
// page.compile will collect all fonts for us, once we have loaded them
|
||||
// we can trigger the actual page rendering with page.display
|
||||
var fonts = [];
|
||||
page.compile(gfx, fonts);
|
||||
|
||||
var t2 = Date.now();
|
||||
|
||||
infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms";
|
||||
// This should be called when font loading is complete
|
||||
page.display(gfx);
|
||||
|
||||
var t3 = Date.now();
|
||||
|
||||
infoDisplay.innerHTML = "Time to load/compile/render: "+ (t1 - t0) + "/" + (t2 - t1) + "/" + (t3 - t2) + " ms";
|
||||
}
|
||||
|
||||
function nextPage() {
|
||||
|
Loading…
Reference in New Issue
Block a user