Reputation: 7004
I am trying to fill a canvas iteratively piece by piece. Moreover, I want an the canvas to be filled in iteratively with squares of the original image.
For performance reasons, I first render the original image to an offscreen canvas and then get the imagedata using getImageData().
In the onscreen canvas, I then try to iteratively plot the pieces using the following code:
var x = 0;
var y = 0;
for (var i = 0; i <= (nbPiecesHorizontal*nbPiecesVertical-1); i++) {
onscreenContext.putImageData(
offScreenData.imageData,
x*pieceWidth,
y*pieceHeight,
x*pieceWidth,
y*pieceHeight,
pieceWidth,
pieceHeight);
// iter
x = x + 1;
if (x == (nbPiecesHorizontal)) {
x = 0;
y = y +1;
}
};
However, I only get that a couple of pieces are drawn, more specific only the pieces in the corners. I want off course, all pieces to be drawn. How can I solve this?
Upvotes: 0
Views: 1462
Reputation: 105015
Using .getImageData
and .putImageData
are slow and expensive methods to draw to the canvas because they manipulate the canvas at the pixel level.
A better way of incrementally draw an image to canvas is to use the clipping version of context.drawImage
. The clipping version of drawImage will clip a specified portion of your original image and draw it onto the canvas.
Using drawImage is much faster because pixels are just copied from the source image to the destination canvas instead of going through the additional "filter" pixel manipulation.
Here's how the clipping version of drawImage works:
context.drawImage(
sourceImage, // the source image to clip from
sX, // the left X position to start clipping
sY, // the top Y position to start clipping
sW, // clip this width of pixels from the source
wH, // clip this height of pixels from the source
dX, // the left X canvas position to start drawing the clipped sub-image
dY, // the top Y canvas position to start drawing the clipped sub-image
dW, // scale sW to dW and draw a dW wide sub-image on the canvas
dH // scale sH to dH and draw a dH high sub-image on the canvas
}
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var nextTime=0;
var duration=500;
var nextX=0;
var nextY=0;
var cols=5;
var rows=3;
var iw,ih,colWidth,rowHeight;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/annotateMe.jpg";
function start(){
iw=canvas.width=img.width;
ih=canvas.height=img.height;
colWidth=iw/cols;
rowHeight=ih/rows;
requestAnimationFrame(animate);
}
function animate(time){
// check if the elapsed time has reached nextTime
// if not, just request another animation loop
if(time<nextTime){requestAnimationFrame(animate); return;}
// reset nextTime
nextTime=time+duration;
// calc the x,y of the subimage to clip from the whole img
var x=parseInt(nextX*colWidth);
var y=parseInt(nextY*rowHeight);
// clip the subimage from the source image
// and draw the subimage onto the canvas
ctx.drawImage(
// use img as the source for clipping
img,
// clip the next cell from the img at x,y
// and clip out a subimage with size colWidth x rowHeight
x,y,colWidth,rowHeight,
// draw the clipped subimage to the canvas
x,y,colWidth,rowHeight
);
// calc the next subimage x,y for the next loop
var imageIsComplete=false;
nextX++;
if(nextX>cols-1){
nextX=0;
nextY++;
if(nextY>rows-1){ imageIsComplete=true; }
}
// if the image is not complete, request another loop
if(!imageIsComplete){ requestAnimationFrame(animate); }
if(imageIsComplete){alert('Image is complete!');}
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
Upvotes: 4