4 changed files with 343 additions and 2 deletions
@ -0,0 +1,109 @@ |
|||||||
|
function CanvasProxy(width, height) { |
||||||
|
var stack = this.$stack = []; |
||||||
|
|
||||||
|
// Expose only the minimum of the canvas object - there is no dom to do
|
||||||
|
// more here.
|
||||||
|
this.canvas = { |
||||||
|
width: width, |
||||||
|
height: height |
||||||
|
} |
||||||
|
|
||||||
|
var ctxFunc = [ |
||||||
|
"createRadialGradient", |
||||||
|
"arcTo", |
||||||
|
"arc", |
||||||
|
"fillText", |
||||||
|
"strokeText", |
||||||
|
"drawImage", |
||||||
|
"getImageData", |
||||||
|
"putImageData", |
||||||
|
"createImageData", |
||||||
|
"drawWindow", |
||||||
|
"save", |
||||||
|
"restore", |
||||||
|
"scale", |
||||||
|
"rotate", |
||||||
|
"translate", |
||||||
|
"transform", |
||||||
|
"setTransform", |
||||||
|
"createLinearGradient", |
||||||
|
"createPattern", |
||||||
|
"clearRect", |
||||||
|
"fillRect", |
||||||
|
"strokeRect", |
||||||
|
"beginPath", |
||||||
|
"closePath", |
||||||
|
"moveTo", |
||||||
|
"lineTo", |
||||||
|
"quadraticCurveTo", |
||||||
|
"bezierCurveTo", |
||||||
|
"rect", |
||||||
|
"fill", |
||||||
|
"stroke", |
||||||
|
"clip", |
||||||
|
"measureText", |
||||||
|
"isPointInPath" |
||||||
|
]; |
||||||
|
function buildFuncCall(name) { |
||||||
|
return function() { |
||||||
|
console.log("funcCall", name) |
||||||
|
stack.push([name, Array.prototype.slice.call(arguments)]); |
||||||
|
} |
||||||
|
} |
||||||
|
var name; |
||||||
|
for (var i = 0; i < ctxFunc.length; i++) { |
||||||
|
name = ctxFunc[i]; |
||||||
|
this[name] = buildFuncCall(name); |
||||||
|
} |
||||||
|
|
||||||
|
var ctxProp = { |
||||||
|
// "canvas"
|
||||||
|
"globalAlpha": "1", |
||||||
|
"globalCompositeOperation": "source-over", |
||||||
|
"strokeStyle": "#000000", |
||||||
|
"fillStyle": "#000000", |
||||||
|
"lineWidth": "1", |
||||||
|
"lineCap": "butt", |
||||||
|
"lineJoin": "miter", |
||||||
|
"miterLimit": "10", |
||||||
|
"shadowOffsetX": "0", |
||||||
|
"shadowOffsetY": "0", |
||||||
|
"shadowBlur": "0", |
||||||
|
"shadowColor": "rgba(0, 0, 0, 0)", |
||||||
|
"font": "10px sans-serif", |
||||||
|
"textAlign": "start", |
||||||
|
"textBaseline": "alphabetic", |
||||||
|
"mozTextStyle": "10px sans-serif", |
||||||
|
"mozImageSmoothingEnabled": "true", |
||||||
|
"DRAWWINDOW_DRAW_CARET": "1", |
||||||
|
"DRAWWINDOW_DO_NOT_FLUSH": "2", |
||||||
|
"DRAWWINDOW_DRAW_VIEW": "4", |
||||||
|
"DRAWWINDOW_USE_WIDGET_LAYERS": "8", |
||||||
|
"DRAWWINDOW_ASYNC_DECODE_IMAGES": "16", |
||||||
|
} |
||||||
|
|
||||||
|
function buildGetter(name) { |
||||||
|
return function() { |
||||||
|
return this["$" + name]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function buildSetter(name) { |
||||||
|
return function(value) { |
||||||
|
stack.push(["$", name, value]); |
||||||
|
return this["$" + name] = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (var name in ctxProp) { |
||||||
|
this["$" + name] = ctxProp[name]; |
||||||
|
this.__defineGetter__(name, buildGetter(name)); |
||||||
|
this.__defineSetter__(name, buildSetter(name)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
CanvasProxy.prototype.flush = function() { |
||||||
|
postMessage("canvas_proxy_stack"); |
||||||
|
postMessage(JSON.stringify(this.$stack)); |
||||||
|
this.$stack.length = 0; |
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
<html> |
||||||
|
<head> |
||||||
|
<title>Simple pdf.js page viewer worker</title> |
||||||
|
<script> |
||||||
|
var myWorker = new Worker('worker.js'); |
||||||
|
|
||||||
|
// var array = new Uint8Array(2); |
||||||
|
// array[0] = 1; |
||||||
|
// array[1] = 300; |
||||||
|
// |
||||||
|
const WAIT = 0; |
||||||
|
const CANVAS_PROXY_STACK = 1; |
||||||
|
const LOG = 2; |
||||||
|
|
||||||
|
var onMessageState = WAIT; |
||||||
|
myWorker.onmessage = function(event) { |
||||||
|
var data = event.data; |
||||||
|
console.log("onMessageRaw", data); |
||||||
|
switch (onMessageState) { |
||||||
|
case WAIT: |
||||||
|
if (typeof data != "string") { |
||||||
|
throw "expecting to get an string"; |
||||||
|
} |
||||||
|
switch (data) { |
||||||
|
case "log": |
||||||
|
onMessageState = LOG; |
||||||
|
return; |
||||||
|
case "canvas_proxy_stack": |
||||||
|
onMessageState = CANVAS_PROXY_STACK; |
||||||
|
return; |
||||||
|
default: |
||||||
|
throw "unkown state: " + data |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case LOG: |
||||||
|
console.log.apply(console, JSON.parse(data)); |
||||||
|
onMessageState = WAIT; |
||||||
|
break; |
||||||
|
|
||||||
|
case CANVAS_PROXY_STACK: |
||||||
|
var stack = JSON.parse(data); |
||||||
|
for (var i = 0; i < stack.length; i++) { |
||||||
|
var opp = stack[i]; |
||||||
|
if (opp[0] == "$") { |
||||||
|
console.log("set property", opp[1], opp[2]); |
||||||
|
ctx[opp[1]] = opp[2]; |
||||||
|
} else { |
||||||
|
console.log("execute", opp[0], opp[1]); |
||||||
|
ctx[opp[0]].apply(ctx, opp[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
onMessageState = WAIT; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
// |
||||||
|
// myWorker.postMessage(array); |
||||||
|
|
||||||
|
function open(url) { |
||||||
|
document.title = url; |
||||||
|
var req = new XMLHttpRequest(); |
||||||
|
req.open("GET", url); |
||||||
|
req.mozResponseType = req.responseType = "arraybuffer"; |
||||||
|
req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200; |
||||||
|
req.onreadystatechange = function() { |
||||||
|
if (req.readyState == 4 && req.status == req.expected) { |
||||||
|
var data = req.mozResponseArrayBuffer || req.mozResponse || |
||||||
|
req.responseArrayBuffer || req.response; |
||||||
|
myWorker.postMessage(data); |
||||||
|
} |
||||||
|
}; |
||||||
|
req.send(null); |
||||||
|
} |
||||||
|
|
||||||
|
window.onload = function() { |
||||||
|
var ctx = window.ctx = document.getElementById("canvas").getContext("2d"); |
||||||
|
// for (var name in ctx) { |
||||||
|
// if (!(ctx[name] instanceof Function)) { |
||||||
|
// console.log('"' + name + '": "' + ctx[name] + '",'); |
||||||
|
// } |
||||||
|
// } |
||||||
|
open("compressed.tracemonkey-pldi-09.pdf"); |
||||||
|
} |
||||||
|
</script> |
||||||
|
<link rel="stylesheet" href="viewer.css"></link> |
||||||
|
</head> |
||||||
|
|
||||||
|
<body> |
||||||
|
<div id="controls"> |
||||||
|
<input type="file" style="float: right; margin: auto 32px;" onChange="load(this.value.toString());"></input> |
||||||
|
<!-- This only opens supported PDFs from the source path... |
||||||
|
-- Can we use JSONP to overcome the same-origin restrictions? --> |
||||||
|
<button onclick="prevPage();">Previous</button> |
||||||
|
<button onclick="nextPage();">Next</button> |
||||||
|
<input type="text" id="pageNumber" onchange="gotoPage(this.value);" |
||||||
|
value="1" size="4"></input> |
||||||
|
<span id="numPages">--</span> |
||||||
|
<span id="info"></span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div id="viewer"> |
||||||
|
<!-- Canvas dimensions must be specified in CSS pixels. CSS pixels |
||||||
|
are always 96 dpi. 816x1056 is 8.5x11in at 96dpi. --> |
||||||
|
<!-- We're rendering here at 1.5x scale. --> |
||||||
|
<canvas id="canvas" width="1224" height="1584"></canvas> |
||||||
|
</div> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
|
@ -0,0 +1,113 @@ |
|||||||
|
"use strict"; |
||||||
|
|
||||||
|
function log() { |
||||||
|
var args = Array.prototype.slice.call(arguments); |
||||||
|
postMessage("log"); |
||||||
|
postMessage(JSON.stringify(args)) |
||||||
|
} |
||||||
|
|
||||||
|
var console = { |
||||||
|
log: log |
||||||
|
} |
||||||
|
|
||||||
|
importScripts("canvas_proxy.js"); |
||||||
|
importScripts("pdf.js"); |
||||||
|
importScripts("fonts.js"); |
||||||
|
importScripts("glyphlist.js") |
||||||
|
|
||||||
|
// var array = new Uint8Array(2);
|
||||||
|
// array[0] = 1;
|
||||||
|
// array[1] = 300;
|
||||||
|
// postMessage(array);
|
||||||
|
|
||||||
|
var timer = null; |
||||||
|
function tic() { |
||||||
|
timer = Date.now(); |
||||||
|
} |
||||||
|
|
||||||
|
function toc(msg) { |
||||||
|
log("Took ", (Date.now() - timer)); |
||||||
|
timer = null; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var canvas = new CanvasProxy(1224, 1584); |
||||||
|
// canvas.moveTo(0, 10);
|
||||||
|
// canvas.lineTo(0, 20);
|
||||||
|
// canvas.lineTo(500, 500);
|
||||||
|
// canvas.flush();
|
||||||
|
// canvas.stroke();
|
||||||
|
// canvas.flush();
|
||||||
|
log("test"); |
||||||
|
|
||||||
|
onmessage = function(event) { |
||||||
|
var data = event.data; |
||||||
|
var pdfDocument = new PDFDoc(new Stream(data)); |
||||||
|
var numPages = pdfDocument.numPages; |
||||||
|
|
||||||
|
tic(); |
||||||
|
// Let's try to render the first page...
|
||||||
|
var page = pdfDocument.getPage(1); |
||||||
|
|
||||||
|
// 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 = []; |
||||||
|
|
||||||
|
var gfx = new CanvasGraphics(canvas); |
||||||
|
page.compile(gfx, fonts); |
||||||
|
toc("compiled page"); |
||||||
|
|
||||||
|
//
|
||||||
|
var fontsReady = true; |
||||||
|
// Inspect fonts and translate the missing one
|
||||||
|
var count = fonts.length; |
||||||
|
for (var i = 0; i < count; i++) { |
||||||
|
var font = fonts[i]; |
||||||
|
if (Fonts[font.name]) { |
||||||
|
fontsReady = fontsReady && !Fonts[font.name].loading; |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
new Font(font.name, font.file, font.properties); |
||||||
|
fontsReady = false; |
||||||
|
} |
||||||
|
|
||||||
|
function delayLoadFont() { |
||||||
|
for (var i = 0; i < count; i++) { |
||||||
|
if (Fonts[font.name].loading) |
||||||
|
return; |
||||||
|
} |
||||||
|
clearInterval(pageInterval); |
||||||
|
page.display(gfx); |
||||||
|
|
||||||
|
canvas.flush(); |
||||||
|
}; |
||||||
|
|
||||||
|
if (fontsReady) { |
||||||
|
delayLoadFont(); |
||||||
|
} else { |
||||||
|
pageInterval = setInterval(delayLoadFont, 10); |
||||||
|
} |
||||||
|
postMessage(page.code.src); |
||||||
|
} |
||||||
|
|
||||||
|
// function open(url) {
|
||||||
|
// var req = new XMLHttpRequest();
|
||||||
|
// req.open("GET", url);
|
||||||
|
// // req.responseType = "arraybuffer";
|
||||||
|
// req.expected = 0;//(document.URL.indexOf("file:") == 0) ? 0 : 200;
|
||||||
|
// req.onreadystatechange = function() {
|
||||||
|
// postMessage("loaded");
|
||||||
|
// if (req.readyState == 4 && req.status == req.expected) {
|
||||||
|
// var data = req.mozResponseArrayBuffer || req.mozResponse ||
|
||||||
|
// req.responseArrayBuffer || req.response;
|
||||||
|
// pdfDocument = new PDFDoc(new Stream(data));
|
||||||
|
// numPages = pdfDocument.numPages;
|
||||||
|
// // document.getElementById("numPages").innerHTML = numPages.toString();
|
||||||
|
// // goToPage(pageNum);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// req.send(null);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// open("compressed.tracemonkey-pldi-09.pdf")
|
Loading…
Reference in new issue