html5: copy a canvas to image and back - image

I implemented a zoom in and out function on a canvas element.
it works by scaling the canvas, translating it, and then redraw the whole scene again.
the problem is that it takes a lot of time to redraw everything because i got a lot of things on my canvas.
I need a way to copy the canvas to an image object and than copy the image back to the canvas without loosing quality. what are the specific methods to copy canvas to a javascript variable, and to to copy this variable back to the canvas later?
I'll be glad if you write down the code because I couldn't find any good explanation over the internet.
thanks,

The drawImage() method can draw to a canvas using another canvas instead of an image.
You could create a 'backup' canvas, of the same size as your original, draw the first one to there and then draw that one back to the original when you need it.
e.g.
// Assume we have a main canvas
// canvas = <main canvas>
ctx = canvas.getContext('2d');
..
// create backing canvas
var backCanvas = document.createElement('canvas');
backCanvas.width = canvas.width;
backCanvas.height = canvas.height;
var backCtx = backCanvas.getContext('2d');
// save main canvas contents
backCtx.drawImage(canvas, 0,0);
..
// restore main canvas
ctx.drawImage(backCanvas, 0,0);

There are a few ways to do it theres the getImageData and putImageData methods Reference, However putImageData and getImageData are pretty slow. Another way is to save the data to an image in memory and recall it from that which is much faster, then the third way is the one above mentioned by andrewmu which involves copying to another canvas element. I have included examples for the first and second type.
Image in memory method
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
savedData = new Image();
function save(){
// get the data
savedData.src = canvas.toDataURL("image/png");
}
function restore(){
// restore the old canvas
ctx.drawImage(savedData,0,0)
}
getImageData putImageData method
// Setup our vars, make a new image to store the canvas data
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
canvasData = '';
function save(){
// get the data
canvasData = ctx.getImageData(0, 0, 100, 100);
}
function restore(){
// restore the old canvas
ctx.putImageData(canvasData, 0, 0);
}

added image into canvas
var image = new Image();
image.src = "1.jpg";
image.onload = function () {
context.drawImage(image, 0, 0);
};

Related

Drawing an image on a canvas and returning as a texture

Firstly, I'd like to make it clear that I am an absolute beginner when it comes to canvas & three.js
I've taken an existing project and am trying to make some minor modifications, namely, drawing an image on to a texture instead of just writing text. I would like the texture to have a set background color and will be attempting to draw a transparent png image on top of it.
The method that I am attempting to modify returns a texture for use in another function which is currently doing a lot more stuff that I probably won't be able to explain here.
I've tried a few approaches and I can't seem to get the behaviour that I want.
Approach #1
In this approach, I am getting the background color but I am not getting the image displayed
var ts = calc_texture_size(size + size * 2 * margin) * 2;
canvas.width = canvas.height = ts;
context.fillStyle = back_color;
context.fillRect(0, 0, canvas.width, canvas.height);
var img = new Image();
function drawIcon() {
context.drawImage(img,0,0);
}
img.onload = drawIcon();
img.src = "img/test.png";
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
return texture;
Approach #2
After doing some research, it seemed I was supposed to use a TextureLoader but I couldn't figure out how to draw the color/shape on the canvas. In this case, the image appears on its own without any background color.
var imgTex = new new THREE.TextureLoader().load( "img/test.png",function(t){
texture.map = imgTex;
});
texture.needsUpdate = true;
return texture;
How can I successfully draw an image on top of a coloured background and return it as a texture for use by other functions?
Your problem is much related to JavaScript event handling, like a question I answered yesterday: How to make a Json model auto-rotates in the scene?. You can never have an "onload" and then expect that to return the variable for you - the variable is just not going to be defined until the callback is executed. Instead you need to defer the work to the callback, or elsewhere keep polling the variable until it's defined.
More specific to your question though:
With approach #1, you're sending the backfilled texture to the GPU, then rendering additional content to it, but not updating the texture that was sent to the GPU after the image was loaded. Moving the texture.needsUpdate = true; to your drawIcon() would probably solve it here. Untested example:
var ts = calc_texture_size(size + size * 2 * margin) * 2;
var img = new Image();
var texture = new THREE.Texture(canvas);
canvas.width = canvas.height = ts;
context.fillStyle = back_color;
context.fillRect(0, 0, canvas.width, canvas.height);
img.onload = function() {
context.drawImage(img,0,0);
texture.needsUpdate = true;
};
img.src = "img/test.png";
return texture;
NB: You should always define your var variables at the start of a scope in JavaScript to make things clearer ... drawIcon() has access to that texture variable, though it doesn't look like it from your example code because it appears to be defined after it, but that's not how JavaScript works: var variables are always global to the scope they're defined in.
With approach #2, you need a little extra work to paint on the texture, turning the texture back in to a canvas and sending the resulting canvas to the GPU. The ImageLoader and Texture documentation combined hint at how you need to paint to the image you get from the TextureLoader.
Combining the two approaches, it should be something like this (also utterly untested):
var ts = calc_texture_size(size + size * 2 * margin) * 2;
canvas.width = canvas.height = ts;
context.fillStyle = back_color;
context.fillRect(0, 0, canvas.width, canvas.height);
var textureLoader = new THREE.TextureLoader().load(
"img/test.png",
function( texture ) {
var image = texture.image;
context.drawImage( texture.image, 0, 0 0 );
var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
// Now do something with texture, like assigning it
// to your material
}
);
NB: Don't forget about using data URL's, if the image you need to paint with is small then this can be included in your code as a "data:" URL and this avoids the need to go to the server and wait for it to load in an event handler. Example at MDN.

Clear canvas context without knowing the canvas dimensions

To clear a canvas to transparency, you do this:
var ctx = canvas.getContext("2d");
ctx.clearRect(0,0, //Starting coordinates
canvas.width, canvas.height //Ending coordinates
);
But I'm writing a more complex abstract system. To avoid calling .getContext all over the place, I have a pseudo-class to manage contexts of all layers. Every sub-program is then passed a ctx variable without the canvas:
Something.prototype.renderMe = function(ctx) {
//draw Something
}
I occurred to need to clear all context area. Is that possible just with canvas context?
The context contains a property which refers to its canvas.
var myCanvas=ctx.canvas;
ctx.clearRect(0,0,myCanvas.width,myCanvas.height);

HTML5 canvas, scale image after drawing it

I'm trying to scale an image that has already been draw into canvas.
This is the code:
var canvas = document.getElementById('splash-container');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw image at its original size
context.drawImage(imageObj, 0, 0);
};
imageObj.src = 'images/mine.jpeg';
// Now let's scale the image.
// something like...
imageObj.scale(0.3, 0.3);
How should I do?
You're thinking about it wrong. Once you've drawn the image onto the canvas it has no relationship to the imageObj object. Nothing you do to imageObj will affect what's already drawn. If you want to scale the image, do in the drawImage function:
drawImage(imgObj, 0, 0, imgObj.width * 0.3, imgObj.height * 0.3)
If you want to animate the scaling or are looking to achieve some other effect which requires you to draw the image at full size initially you'll have to first clear it before drawing the scaled down image.
What robertc says is correct, but if you really wanted to scale an image on a canvas after drawing it for some reason, you could just scale the whole canvas using the CSS width/height properties and that would scale the image without having to redraw it.

Positioning an HTML5 Canvas Element

I am completely new to HTML5 and have been reading about it for the past few days mainly because I wanted to create a rotating image to put in a <div>. I found a code that does exactly what I want, but it throws the canvas on to the bottom left corner of my page (I'm not sure why, but I think it has something to do with the very first line of the code below). I'm not sure how to adapt the code to a element so that I can put it where I want. From looking at other people's scripts and trying to emulate them, I know you're supposed to do this sort of thing to hold the canvas "<canvas width="100" height="100" id="pageCanvas"></canvas>," but I don't know how to name the below code in order to do that. I greatly appreciate any help anyone can offer me - thank you so much for reading! :)
<script>
window.addEventListener("load", init);
var counter = 0,
logoImage = new Image(),
TO_RADIANS = Math.PI/180;
logoImage.src = 'IMG URL';
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var context = canvas.getContext('2d');
document.body.appendChild(canvas);
function init(){
setInterval(loop, 1000/30);
}
function loop() {
context.clearRect(0,0,canvas.width, canvas.height);
drawRotatedImage(logoImage,100,100,counter);
drawRotatedImage(logoImage,300,100,counter+90);
drawRotatedImage(logoImage,500,100,counter+180);
counter+=2;
}
function drawRotatedImage(image, x, y, angle) {
// save the current co-ordinate system
// before we screw with it
context.save();
// move to the middle of where we want to draw our image
context.translate(x, y);
// rotate around that point, converting our
// angle from degrees to radians
context.rotate(angle * TO_RADIANS);
// draw it up and to the left by half the width
// and height of the image
context.drawImage(image, -(image.width/2), -(image.height/2));
// and restore the co-ords to how they were when we began
context.restore();
}
</script>
Create a canvas element in your HTML code so you can place it exactly where you want (with html + css) :
<canvas id='canvas' height='100' width='100'> Your browser does not support HTML5 canvas </canvas>
And replace this javascript code :
var canvas = document.createElement('canvas');
canvas.width = 100;
canvas.height = 100;
var context = canvas.getContext('2d');
document.body.appendChild(canvas);
by this one :
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

Can we get the real image size through the canvas?

In image tag, if we don't supply width and height property, we will get nothing when retrieving the width and the height of the image. I am using the canvas element to load an image and scale it proportionally. In order to do this, I have to get the actual image size. Is it possible to do that in html 5?
The HTMLImageElement has two properties for this, naturalWidth and naturalHeight. Use those.
As in:
var img = new Image();
img.addEventListener('load', function() {
// once the image is loaded:
var width = img.naturalWidth; // this will be 300
var height = img.naturalHeight; // this will be 400
someContext.drawImage(img, 0, 0, width, height);
}, false);
img.src = 'http://placekitten.com/300/400'; // grab a 300x400 image from placekitten
It is wise to set source only after the event listener is defined, see Phrogz's exploration on that here: Should setting an image src to data URL be available immediately?
You cannot retrieve width/height before image has been loaded.
Try something like:
// create new Image or get it right from DOM,
// var img = document.getElementById("myImage");
var img = new Image();
img.onload = function() {
// this.width contains image width
// this.height contains image height
}
img.src = "image.png";
Anyhow onload will not fire if image has been loaded before script execution. Eventually you can embed script in html <img src="test.jpg" onload="something()">
if I understand you correctly, you can use the getComputedStyle method.
var object = document.getElementById(el);
var computedHeight = document.defaultView.getComputedStyle(object, "").getPropertyValue("width");
Not fully understood your question.
But you can use javascript to get the width and height of the image.
and then pass it into
/ Five arguments: the element, destination (x,y) coordinates, and destination
// width and height (if you want to resize the source image).
context.drawImage(img_elem, dx, dy, dw, dh);
while drawing image on canvas.
or check this if it helps
http://jsfiddle.net/jjUHs/

Resources