pdf.js/viewer_worker.html

232 lines
6.7 KiB
HTML

<html>
<head>
<title>Simple pdf.js page viewer worker</title>
<script>
var timer = null
function tic() {
timer = Date.now();
}
function toc(msg) {
console.log(msg + ": " + (Date.now() - timer) + "ms");
}
var myWorker = new Worker('worker.js');
var currentX = 0;
var currentXStack = [];
var special = {
"$setCurrentX": function(value) {
currentX = value;
},
"$addCurrentX": function(value) {
currentX += value;
},
"$saveCurrentX": function() {
currentXStack.push(currentX);
},
"$restoreCurrentX": function() {
currentX = currentXStack.pop();
},
"$showText": function(y, text, uniText) {
this.translate(currentX, -1 * y);
this.fillText(uniText, 0, 0);
currentX += this.measureText(text).width;
},
"$drawCanvas": function(data, x, y, width, height) {
// Ugly: getImageData is called here only to get an object of the right
// shape - we are not interessted in the data, as we set it the line
// afterwards to something custome.
// Can we do better here?
var imgData = ctx.getImageData(0, 0, width, height);
imgData.data = data;
ctx.putImageData(imgData, x, y);
}
}
var gStack;
function renderProxyCanvas(stack) {
for (var i = 0; i < stack.length; i++) {
// for (var i = 0; i < 1000; i++) {
var opp = stack[i];
if (opp[0] == "$") {
ctx[opp[1]] = opp[2];
} else if (opp[0] in special) {
special[opp[0]].apply(ctx, opp[1]);
} else {
ctx[opp[0]].apply(ctx, opp[1]);
}
}
}
const WAIT = 0;
const CANVAS_PROXY_STACK = 1;
const LOG = 2;
const FONT = 3;
const PDF_NUM_PAGE = 4;
var onMessageState = WAIT;
var fontStr = null;
var first = true;
var intervals = [];
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 "pdf_num_page":
onMessageState = PDF_NUM_PAGE;
return;
case "log":
onMessageState = LOG;
return;
case "canvas_proxy_stack":
onMessageState = CANVAS_PROXY_STACK;
return;
case "font":
onMessageState = FONT;
return;
default:
throw "unkown state: " + data
}
break;
case PDF_NUM_PAGE:
console.log(data);
maxPages = parseInt(data);
document.getElementById("numPages").innerHTML = "/" + data;
onMessageState = WAIT;
break;
case FONT:
data = JSON.parse(data);
var base64 = window.btoa(data.str);
// Add the @font-face rule to the document
var url = "url(data:" + data.mimetype + ";base64," + base64 + ");";
var rule = "@font-face { font-family:'" + data.fontName + "';src:" + url + "}";
var styleSheet = document.styleSheets[0];
styleSheet.insertRule(rule, styleSheet.length);
// *HACK*: this makes the font get loaded on the page. WTF? We
// really have to set the fonts a few time...
var interval = setInterval(function() {
ctx.font = "bold italic 20px " + data.fontName + ", Symbol, Arial";
}, 10);
intervals.push(interval);
console.log("setup font", data.fontName);
onMessageState = WAIT;
break;
case LOG:
console.log.apply(console, JSON.parse(data));
onMessageState = WAIT;
break;
case CANVAS_PROXY_STACK:
var stack = JSON.parse(data);
gStack = stack;
console.log("canvas stack size", stack.length)
// Shedule a timeout. Hoping the fonts are loaded after 100ms.
setTimeout(function() {
// Remove all setIntervals to make the font load.
intervals.forEach(function(inter) {
clearInterval(inter);
});
tic();
renderProxyCanvas(stack);
toc("canvas rendering")
}, 100);
onMessageState = WAIT;
break;
}
}
//
// myWorker.postMessage(array);
var currentPage = 1;
var maxPages = 1;
function showPage(num) {
ctx.save();
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
console.log("worker: page=" + num)
document.getElementById('pageNumber').value = num;
currentPage = parseInt(num);
myWorker.postMessage(num);
}
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);
showPage("1");
}
};
req.send(null);
}
function nextPage() {
if (currentPage == maxPages) return;
currentPage++;
showPage(currentPage);
}
function prevPage() {
if (currentPage == 0) return;
currentPage--;
showPage(currentPage);
}
window.onload = function() {
window.canvas = document.getElementById("canvas");
window.ctx = canvas.getContext("2d");
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="showPage(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>