You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
6.2 KiB
201 lines
6.2 KiB
<html> |
|
<head> |
|
<title>Simple pdf.js page viewer worker</title> |
|
<script> |
|
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) { |
|
// console.log(text, currentX, y, this.measureText(text).width); |
|
|
|
this.translate(currentX, -1 * y); |
|
this.fillText(text, 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] == "$") { |
|
// console.log("set property", opp[1], opp[2]); |
|
if (opp[1] == "font") { |
|
ctx[opp[1]] = opp[2]; |
|
// ctx.font = "10px 'Verdana Bold Italic'"; |
|
// console.log("font", opp[2]); |
|
} else { |
|
ctx[opp[1]] = opp[2]; |
|
} |
|
|
|
} else if (opp[0] in special) { |
|
// console.log("sepcial", opp[0], opp[1]) |
|
special[opp[0]].apply(ctx, opp[1]); |
|
} else { |
|
// console.log("execute", opp[0], opp[1]); |
|
ctx[opp[0]].apply(ctx, opp[1]); |
|
} |
|
} |
|
} |
|
|
|
const WAIT = 0; |
|
const CANVAS_PROXY_STACK = 1; |
|
const LOG = 2; |
|
const FONT = 3; |
|
|
|
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 "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 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); |
|
|
|
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", 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); |
|
}); |
|
renderProxyCanvas(stack); |
|
}, 100); |
|
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"); |
|
ctx.save(); |
|
ctx.fillStyle = "rgb(255, 255, 255)"; |
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
ctx.restore(); |
|
// 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> |
|
|
|
|