Rotating and Caching in canvas bug - javascript

I am making a game and in it I would like to have the ability to use cached canvas's instead of rotating the image every frame. I think I made a function for adding images that makes sense to me, but I am getting an error every frame that tells me that the canvas object is no longer available.
INVALID_STATE_ERR: DOM Exception 11: An attempt was made to use an
object that is not, or is no longer, usable.
You might also need to know that I am using object.set(); to go ahead and add that image to a renderArray. That may be affecting whether the canvas object is still avaliable?
Here is the function that returns a cached canvas, (I took it from a post on this website :D)
rotateAndCache = function(image, angle){
var offscreenCanvas = document.createElement('canvas');
var offscreenCtx = offscreenCanvas.getContext('2d');
var size = Math.max(image.width, image.height);
offscreenCanvas.width = size;
offscreenCanvas.height = size;
offscreenCtx.translate(size/2, size/2);
offscreenCtx.rotate(angle + Math.PI/2);
offscreenCtx.drawImage(image, -(image.width/2), -(image.height/2));
return offscreenCanvas;
}
And here is some more marked up code:
var game = {
render:function(){
//gets called every frame
context.clearRect(0, 0, canvas.width, canvas.height);
for(i = 0; i < game.renderArray.length; i++){
switch(game.renderArray[i].type){
case "image":
context.save();
context.translate(game.renderArray[i].x, game.renderArray[i].y);
context.rotate(Math.PI*game.renderArray[i].rotation/180);
context.translate(-game.renderArray[i].x, -game.renderArray[i].y);
context.drawImage(game.renderArray[i].image, game.renderArray[i].x, game.renderArray[i].y);
context.restore();
break;
}
if(game.renderArray[i].remove == true){
game.renderArray.splice(i,1);
if(i > 1){
i--;
}else{
break;
}
}
}
},
size:function(width, height){
canvas.height = height;
canvas.width = width;
return height + "," + width;
},
renderArray:new Array(),
//initialize the renderArray
image:function(src, angle){
if(angle != undefined){
//if the argument 'angle' was given
this.tmp = new Image();
this.tmp.src = src;
//sets 'this.image' (peach.image) to the canvas. It then should get rendered in the next frame, but apparently it doesn't work...
this.image = rotateAndCache(this.tmp, angle);
}else{
this.image = new Image();
this.image.src = src;
}
this.x = 0;
this.y = 0;
this.rotation = 0;
this.destroy = function(){
this.remove = true;
return "destroyed";
};
this.remove = false;
this.type = "image";
this.set = function(){
game.renderArray.push(this);
}
}
};
var canvas, context, peach;
$(document).ready(function(){
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
//make the variable peach a new game.image with src of meme.jpg and an angle of 20.
peach = new game.image('meme.jpg', 20);
peach.set();
game.size(700,500);
animLoop();
});
If you want, here is this project hosted on my site:
http://keirp.com/zap

There are no errors on your page, at least not anymore or not that I can see.
It's quite possible that the problem is an image that is not done loading. For instance that error will happen if you try to make a canvas pattern out of a not-yet-finished-loading image. Use something like pxloader or your own image loading function to make sure all the images are complete before you start drawing.
Anyway, it's nigh impossible to figure out what was or is happening since your code isn't actually giving any errors (anymore).

Related

Can't seem to get an old image off the canvas

I'm importing an image (that has to come in portrait) onto a canvas object, rotating it (because it's actually landscape) and running some OCR on the base64 from the canvas. That all works fine. However when I put a new image onto the canvas, the old one is retained and never replaced. I've tried clearRect, even gone to the extent of creating a new dom element each time and destroying it when I have everything I need (which is still in the code below) but I just cannot get the first image to clear.
Here's the relevant bit of the code
function onSuccess(imageURI) {
//CREATE NEW CANVAS ELEMENT
g = document.createElement('canvas');
g.setAttribute("id", "thePic");
g.style.overflow = "visible";
document.body.appendChild(g);
const canvas = document.getElementById('thePic'),
context = canvas.getContext('2d');
make_base();
function make_base()
{
base_image = new Image();
base_image.src = imageURI;
base_image.onload = function(){
const uriheight = base_image.naturalHeight;
const uriwidth = base_image.naturalWidth;
console.log(uriwidth + " " + uriheight);
context.canvas.width = uriheight;
context.canvas.height = uriheight;
context.drawImage(base_image, 0, 0);
//ROTATE THE IMAGE 90
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.translate(canvas.width/2,canvas.height/2);
context.rotate(90*Math.PI/180);
context.drawImage(base_image,-base_image.width/1.2,-base_image.width/1.2);
context.restore();
var theCanvas = document.getElementById('thePic');
var rotImg = theCanvas.toDataURL();
var rotImg = rotImg.substring(21);
textocr.recText(4, rotImg, onSuccess, onFail);
function onSuccess(recognizedText) {
var recdata = recognizedText.lines.linetext;
var blockData = recognizedText.blocks.blocktext;
context.clearRect(0, 0, 10000,10000);
base_image = "";
rotImg = "";
document.getElementById('thePic').outerHTML = "";
document.getElementById('cgh').innerHTML = "";
}
}
}
Any advice much appreciated.
So it turned out to not be the canvas at all, it was image caching in a previous function that give the image to the canvas.
Thanks to everyone who took the time to have a squiz.

Making masks with Canvas globalCompositeOperation for jigsaw puzzle game backend

I'm trying to make a backend for publishing simple jigsaw-puzzle games. The game uses 12 premade shapes as masks for making the 12 puzzle pieces. I found the excellent Canvas global CompositeOperation tutorial, and tested it.
The application I'm making is using ajax to send each finished piece to the serverside .php-script. The user loads an image (600x400) using SSE and the app moves the original image inside tempCanvas according to the values of the arrays arr_x and arr_y It's supposed to happen in a for-loop:
function drawPieces(){
var canvas = document.getElementById("myCanvas");
var context =canvas.getContext("2d");
var tempCanvas = document.getElementById("tempCanvas");
var tempContext = tempCanvas.getContext("2d");
var img_mask = new Image();
var w;
var h;
var cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11;
var arr_data = [cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11];
var arr_x = [0,-136,-289,-414,0,-115,-270,-415,0,-118,-288,-415];
var arr_y = [0,0,0,0,-113,-111,-111,-124,-244,-256,-243,-241];
var img_bg = new Image(600, 400);
for (var i = 0; i<arr_x.length; i++) {
img_bg = original;
// get the mask
img_mask.src = "img/mask"+i+".png";
w = img_mask.width;
h = img_mask.height;
console.log("w = ", img_mask.width, " h = ", img_mask.height);
tempCanvas.width = w;
tempCanvas.height = h;
// Her lages maska
tempContext.drawImage(img_mask,0,0);
tempContext.globalCompositeOperation = 'source-in';
tempContext.drawImage(img_bg,arr_x[i],arr_y[i]);
myCanvas.width = w;
myCanvas.height = h;
// Draws tempCanvas on to myCanvas
console.log("tempCanvas: ", tempCanvas, " img_mask.src = ", img_mask.src);
context.drawImage(tempCanvas, 0, 0);
arr_data[i] = myCanvas;
sendData(arr_data[i], [i]);
};
}
Sending the image data to the server:
function sendData(cvd, index){
var imageData = cvd.toDataURL("image/png");
var ajax = new XMLHttpRequest();
ajax.open("POST", "testsave.php", false);
// ajax.onreadystatechange=function(){
// console.log("index = ", index)
// };
ajax.setRequestHeader('Content-Type', 'application/upload');
ajax.send(imageData+"<split>"+index);
};
I got a button to start drawPieces. But I get a number of issues. Firefox throws an error:
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable: context.drawImage(tempCanvas, 0, 0);
But if I click the button again the loop is run and I get 12 pieces in my folder. (Using xammp for now). But the pieces are cut wrong! The app doesn't seem to load the correct mask each time the loop runs.
So I tested it without using a loop by having 12 different functions where each function is calling the next one. It worked with one function, but started messing up the masks when I added more:
function drawPiece0(){
img_bg = original;
img_mask.src = "img/mask0.png";
tempCanvas.width = 185;
tempCanvas.height = 145;
// Her lages maska
tempContext.drawImage(img_mask,0,0);
tempContext.globalCompositeOperation = 'source-in';
tempContext.drawImage(img_bg,0,0);
myCanvas.width = 185;
myCanvas.height = 145;
// Tegner tempCanvas over på myCanvas
context.drawImage(tempCanvas, 0, 0);
cvd0 = myCanvas;
sendData(cvd0, 0);
// drawPiece1();
};
Something is absolutely wrong in my setup, but I can't figure out what it is. Someone help me please!
By the way, here is my .php-script too:
<?php
if (isset($GLOBALS["HTTP_RAW_POST_DATA"]))
{
// Get the data
$imageData=$GLOBALS['HTTP_RAW_POST_DATA'];
$parts = explode("<split>", $imageData);
$imageData = $parts[0];
$index= $parts[1];
// Remove the headers (data:,) part.
// A real application should use them according to needs such as to check image type
$filteredData=substr($imageData, strpos($imageData, ",")+1);
// Need to decode before saving since the data we received is already base64 encoded
$unencodedData=base64_decode($filteredData);
// Save file.
$fp = fopen( "pieces/".$index.".png", "wb" );
fwrite( $fp, $unencodedData);
fclose( $fp );
}
?>
Problem
The problem is that image loading is asynchronous which means they load in the background while your code is continuing.
That means the images won't be ready (loaded and decoded) when you try to use them with drawImage resulting in the error. The error is indirect here though as w and h do not get valid values for the canvas which means canvas will be 0 width and 0 height which will trigger the actual error when attempted drawn.
The reason why it "works" the second time is because an image exists in the browser's cache and may be able to provide the image before it's used.
Another problem is that in your loop you are overwriting the image variable so only the last image will be used when loaded.
Solution
The solution is to make or use an image loader before you start the loop. It's easy to make one but for simplicity I will use the YAIL loader in this example (disclaimer: author ibid) but any kind of loader will do as long as you use a callback for the images:
function drawPieces(){
var canvas = document.getElementById("myCanvas");
var context =canvas.getContext("2d");
var tempCanvas = document.getElementById("tempCanvas");
var tempContext = tempCanvas.getContext("2d");
var img_mask;
var w;
var h;
var cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11;
var arr_data = [cvd0,cvd1,cvd2,cvd3,cvd4,cvd5,cvd6,cvd7,cvd8,cvd9,cvd10,cvd11];
var arr_x = [0,-136,-289,-414,0,-115,-270,-415,0,-118,-288,-415];
var arr_y = [0,0,0,0,-113,-111,-111,-124,-244,-256,-243,-241];
var img_bg;
// using some image(s) loader
var loader = new YAIL({done: draw});
for (var i = 0; i<arr_x.length; i++)
loader.add("img/mask"+i+".png");
loader.load(); // start loading images
// this is called when images has loaded
function draw(e) {
for (var i = 0; i<arr_x.length; i++) {
//img_bg = original; ??
// get the mask
var img_mask = e.images[i]; // loaded images in an array
w = img_mask.width; // now you will have a valid
h = img_mask.height; // dimension here
console.log("w = ", img_mask.width, " h = ", img_mask.height);
tempCanvas.width = w;
tempCanvas.height = h;
// Her lages maska
tempContext.drawImage(img_mask,0,0);
tempContext.globalCompositeOperation = 'source-in';
tempContext.drawImage(img_bg,arr_x[i],arr_y[i]);
myCanvas.width = w;
myCanvas.height = h;
// Draws tempCanvas on to myCanvas
console.log("tempCanvas: ", tempCanvas, " img_mask.src = ", img_mask.src);
context.drawImage(tempCanvas, 0, 0);
arr_data[i] = myCanvas;
sendData(arr_data[i], [i]);
}
};
}
Note: loading images will make your code asynchronous in nature. If the code depends on some other function right after the pieces has been drawn then you must invoke that function from within the inner one after the loop has finished.
Hope this helps. If the pieces still doesn't show correctly please set up a fiddle with the images uploaded to f.ex. imgur.com so we can dig deeper into the problem.
Hope this helps!

Collision with Chipmunk JS failing

http://videobin.org/+70a/8wi.html
You can see what's happening there, and a demo to try it here: http://student.dei.uc.pt/~drgomes/carry/index.html.
So, I'm using Chipmunk JS demos to get an idea of how it works (see https://github.com/josephg/Chipmunk-js). The simple demo starts alright but then things start jumping crazily and I've been trying to figure out this with no luck so far.
var radToDeg = 180 / Math.PI;
function PlayState() {
this.blocks = [];
this.setup = function() {
space.iterations = 100;
space.gravity = new cp.Vect(0, 150);
space.game = this;
this.ground = space.addShape(new cp.SegmentShape(space.staticBody, new cp.v(0, 480), new cp.v(640, 480), 0));
this.ground.setElasticity(0);
this.ground.setFriction(1);
};
this.update = function() {
space.step(this.dt);
for (var i = 0; i < this.blocks.length; i++) {
var block = this.blocks[i];
block.sprite.x = block.body.p.x;
block.sprite.y = block.body.p.y;
block.sprite.angle = block.body.a * radToDeg;
}
if (isMouseDown("left")) {
if (this.canAddBlock) {
this.canAddBlock = false;
this.addBlock(mouseX, mouseY);
}
} else {
this.canAddBlock = true;
}
};
this.draw = function() {
clearCanvas();
for (var i = 0; i < this.blocks.length; i++) {
this.blocks[i].sprite.draw();
}
// this.ground.sprite.draw();
};
this.addBlock = function(x, y) {
width = 64;
height = 64;
var newBlock = new Block(x, y, width, height);
newBlock.body = space.addBody(new cp.Body(1, cp.momentForBox(1, width, height)));
newBlock.body.setPos(new cp.v(x, y));
newBlock.shape = space.addShape(new cp.BoxShape(newBlock.body, width, height));
newBlock.shape.setElasticity(0);
newBlock.shape.setFriction(1);
this.blocks.push(newBlock);
};
}
desiredFPS = 60;
switchState(new PlayState());
The source code is pretty straightforward, I have my doubts about the way I'm creating the ground since I can't really tell in what position it actually is. The cubes seem to find it and collide against it though.
The other source file is a little Block class to help me organize things:
Block = (function() {
function constructor(x, y, width, height) {
this.sprite = new Sprite("res/block.png", x, y);
this.width = width;
this.height = height;
}
constructor.prototype = {
update: function() {
}
};
return constructor;
})();
From watching the behavior, I think it is as simple as the sprites and the chipmunk bodies not rotating around the same point. I believe chipmunk rotations are around the center of mass. It looks like the sprites are rotating around the upper left corner. In fact, they may be drawing from that corner too, which explains why they stack funny, and intersect the bottom plane.
I think you need something like this in the update function. (pseudocode):
offset = Vector(-width/2,-height/2)
offset.rotate_by(block.body.a)
block.sprite.x = block.body.p.x + offset.x
block.sprite.y = block.body.p.y + offset.y
I don't know chipmunk at all but playing around with your demo it seems like the Physics isn't right at all (right from the beginning for me). Just a hunch from looking at your code, but it looks to me like you should be setting the dimensions on the Sprite instance in your Block class, rather than on the Block instance itself.
Block = (function() {
function constructor(x, y, width, height) {
this.sprite = new Sprite("res/block.png", x, y);
// Do you mean to set the width and height of the sprite?
this.sprite.width = width;
this.sprite.height = height;
}
constructor.prototype = {
update: function() {
}
};
return constructor;
})();

draw image to canvas proplem

its very confused i`m designing a 2d game and i use this code to draw images to canvas the alert method return background.x = 0 ! but when i change x to z or any letter its return the number 400 i ! why background.x always equal to zero ???
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
function loadResources(){
background = new Image();
background.src = "11.jpg";
background.width = 128;
background.height = 128;
background.x = 400;
background.y = 450;
}
function drawimage(){
alert(background.x);
context.drawImage(background,background.x,background.y,background.width,background.height);
}
function gameLoop() {
drawimage();
}
loadResources();
setInterval(gameLoop, 1000/60);
Unlike other objects, you are actually not able to set properties of an Image object that do not belong to it. As you've seen, when you try to access them after setting them, the properties will not be available. You can slightly rework your code as follows to get the behavior you're looking for:
var canvas = document.getElementById('game');
var context = canvas.getContext('2d');
var resources = {};
function loadResources(){
resources.background = new Image();
resources.background.src = "11.jpg";
resources.background.width = 128;
resources.background.height = 128;
resources.backgroundx = 400;
resources.backgroundy = 450;
}
function drawimage(){
console.log(resources.backgroundx);
context.drawImage(resources.background,resources.backgroundx,resources.backgroundy,resources.background.width,resources.background.height);
}
function gameLoop() {
drawimage();
}
loadResources();
setInterval(gameLoop, 1000/60);

Render .pdf to single Canvas using pdf.js and ImageData

I am trying to read an entire .pdf Document using PDF.js and then render all the pages on a single canvas.
My idea: render each page onto a canvas and get the ImageData (context.getImageData()), clear the canvas do the next page. I store all the ImageDatas in an array and once all pages are in there I want to put all the ImageDatas from the array onto a single canvas.
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
//Prepare some things
var canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i = 1; i <= pdf.numPages; i ++){
pdf.getPage(i).then(function getPage(page){
var viewport = page.getViewport(scale);
canvas.width = viewport.width;
canvas.height = viewport.height;
page.render({canvasContext: context, viewport: viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
context.clearRect(0, 0, canvas.width, canvas.height);
p.Out("pre-rendered page " + i);
});
}
//Now we have all 'dem Pages in "pages" and need to render 'em out
canvas.height = 0;
var start = 0;
for(var i = 0; i < pages.length; i++){
if(canvas.width < pages[i].width) canvas.width = pages[i].width;
canvas.height = canvas.height + pages[i].height;
context.putImageData(pages[i], 0, start);
start += pages[i].height;
}
});
So from the way I understnad thing this should work, right?
When I run this I end up with the canvas that is big enought to contain all the pages of the pdf but doesn't show the pdf...
Thank you for helping.
The PDF operations are asynchronous at all stages. This means you also need to catch the promise at the last render as well. If you not catch it you will only get a blank canvas as the rendering isn't finished before the loop continues to the next page.
Tip: I would also recommend that you use something else than getImageData as this will store uncompressed bitmap, for example the data-uri instead which is compressed data.
Here is a slightly different approach eliminating the for-loop and uses the promises better for this purpose:
LIVE FIDDLE
var canvas = document.createElement('canvas'), // single off-screen canvas
ctx = canvas.getContext('2d'), // to render to
pages = [],
currentPage = 1,
url = 'path/to/document.pdf'; // specify a valid url
PDFJS.getDocument(url).then(iterate); // load PDF document
/* To avoid too many levels, which easily happen when using chained promises,
the function is separated and just referenced in the first promise callback
*/
function iterate(pdf) {
// init parsing of first page
if (currentPage <= pdf.numPages) getPage();
// main entry point/function for loop
function getPage() {
// when promise is returned do as usual
pdf.getPage(currentPage).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
// now, tap into the returned promise from render:
page.render(renderContext).then(function() {
// store compressed image data in array
pages.push(canvas.toDataURL());
if (currentPage < pdf.numPages) {
currentPage++;
getPage(); // get next page
}
else {
done(); // call done() when all pages are parsed
}
});
});
}
}
When you then need to retrieve a page you simply create an image element and set the data-uri as source:
function drawPage(index, callback) {
var img = new Image;
img.onload = function() {
/* this will draw the image loaded onto canvas at position 0,0
at the optional width and height of the canvas.
'this' is current image loaded
*/
ctx.drawImage(this, 0, 0, ctx.canvas.width, ctx.canvas.height);
callback(); // invoke callback when we're done
}
img.src = pages[index]; // start loading the data-uri as source
}
Due to the image loading it will be asynchronous in nature as well which is why we need the callback. If you don't want the asynchronous nature then you could also do this step (creating and setting the image element) in the render promise above storing image elements instead of data-uris.
Hope this helps!
I can’t speak to the part of your code that renders the pdf into a canvas, but I do see some problems.
Every resetting canvas.width or canvas.height automatically clears the canvas contents. So in the top section, your clearRect is not needed because the canvas is cleared by canvas.width prior to your every page.render.
More importantly, in the bottom section, all your previous pdf drawings are cleared by every canvas resizing (oops!).
getImageData() gets an array where each pixel is represented by 4 consecutive elements of that array (red then green then blue then alpha). Since getImageData() is an array, so it doesn’t have a pages[i].width or pages[i].height—it only has a pages[i].length. That array length cannot be used to determine widths or heights.
So to get you started, I would start by changing your code to this (very, very untested!):
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
//Prepare some things
var canvas = document.getElementById('cv');
var context = canvas.getContext('2d');
var scale = 1.5;
var canvasWidth=0;
var canvasHeight=0;
var pageStarts=new Array();
pageStarts[0]=0;
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
//Render all the pages on a single canvas
for(var i = 1; i <= pdf.numPages; i ++){
pdf.getPage(i).then(function getPage(page){
var viewport = page.getViewport(scale);
// changing canvas.width and/or canvas.height auto-clears the canvas
canvas.width = viewport.width;
canvas.height = viewport.height;
page.render({canvasContext: context, viewport: viewport});
pages[i-1] = context.getImageData(0, 0, canvas.width, canvas.height);
// calculate the width of the final display canvas
if(canvas.width>maxCanvasWidth){
maxCanvasWidth=canvas.width;
}
// calculate the accumulated with of the final display canvas
canvasHeight+=canvas.height;
// save the "Y" starting position of this pages[i]
pageStarts[i]=pageStarts[i-1]+canvas.height;
p.Out("pre-rendered page " + i);
});
}
canvas.width=canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for(var i = 0; i < pages.length; i++){
context.putImageData(pages[i], 0, pageStarts[i]);
}
});
Alternatively, here’s a more traditional way of accomplishing your task:
Use a single “display” canvas and allow the user to “page through” each desired page.
Since you already start by drawing each page into a canvas, why not keep a separate, hidden canvas for each page. Then when the user wants to see page#6, you just copy the hidden canvas#6 onto your display canvas.
The Mozilla devs use this approach in their pdfJS demo here: http://mozilla.github.com/pdf.js/web/viewer.html
You can check out the code for the viewer here: http://mozilla.github.com/pdf.js/web/viewer.js
You can pass the number page to the promises , get that page canvas data and render in the right order on canvas
var renderPageFactory = function (pdfDoc, num) {
return function () {
var localCanvas = document.createElement('canvas');
///return pdfDoc.getPage(num).then(renderPage);
return pdfDoc.getPage(num).then((page) => {
renderPage(page, localCanvas, num);
});
};
};
var renderPages = function (pdfDoc) {
var renderedPage = $q.resolve();
for (var num = 1; num <= pdfDoc.numPages; num++) {
// Wait for the last page t render, then render the next
renderedPage = renderedPage.then(renderPageFactory(pdfDoc, num));
}
};
renderPages(pdf);
Complete example
function renderPDF(url, canvas) {
var pdf = null;
PDFJS.disableWorker = true;
var pages = new Array();
var context = canvas.getContext('2d');
var scale = 1;
var canvasWidth = 256;
var canvasHeight = 0;
var pageStarts = new Array();
pageStarts[0] = 0;
var k = 0;
function finishPage(localCanvas, num) {
var ctx = localCanvas.getContext('2d');
pages[num] = ctx.getImageData(0, 0, localCanvas.width, localCanvas.height);
// calculate the accumulated with of the final display canvas
canvasHeight += localCanvas.height;
// save the "Y" starting position of this pages[i]
pageStarts[num] = pageStarts[num -1] + localCanvas.height;
if (k + 1 >= pdf.numPages) {
canvas.width = canvasWidth;
canvas.height = canvasHeight; // this auto-clears all canvas contents
for (var i = 0; i < pages.length; i++) {
context.putImageData(pages[i+1], 0, pageStarts[i]);
}
var img = canvas.toDataURL("image/png");
$scope.printPOS(img);
}
k++;
}
function renderPage(page, localCanvas, num) {
var ctx = localCanvas.getContext('2d');
var viewport = page.getViewport(scale);
// var viewport = page.getViewport(canvas.width / page.getViewport(1.0).width);
// changing canvas.width and/or canvas.height auto-clears the canvas
localCanvas.width = viewport.width;
/// viewport.width = canvas.width;
localCanvas.height = viewport.height;
var renderTask = page.render({canvasContext: ctx, viewport: viewport});
renderTask.then(() => {
finishPage(localCanvas, num);
});
}
PDFJS.getDocument(url).then(function getPdfHelloWorld(_pdf) {
pdf = _pdf;
var renderPageFactory = function (pdfDoc, num) {
return function () {
var localCanvas = document.createElement('canvas');
///return pdfDoc.getPage(num).then(renderPage);
return pdfDoc.getPage(num).then((page) => {
renderPage(page, localCanvas, num);
});
};
};
var renderPages = function (pdfDoc) {
var renderedPage = $q.resolve();
for (var num = 1; num <= pdfDoc.numPages; num++) {
// Wait for the last page t render, then render the next
renderedPage = renderedPage.then(renderPageFactory(pdfDoc, num));
}
};
renderPages(pdf);
});
}

Categories

Resources