Canvas. How to get background pixels before drawing - javascript

I created a small plug-in for my map application. This plug-in adds text labels to geometric features. It looks like so:
On the screen above you can see a map, a horizontal linestring and a text label. I created this label by using canvas, canvas.getContext("2d") and a bunch of standard functions like ctx.strokeText, ctx.fillText etc. The problem I face now is that the linestring on the screen is interactive or moveable and I want my label to move as well. I'm not asking about the exact solution to my problem. What I'm interested in is just how to get backround pixels (right below my text label), so that I could restore them before I "move" or redraw the label at a new place. If you can provide a teeny-weeny example where you have some background and then draw some object and then "remove" it, it will be great.

You probably want to use context.getImageData and context.putImageData
Assuming your canvas has the id "myCanvas", calling doDraw() will cause a black rectangle to blink on a complex background.
First, the background is drawn in doDraw(). Then, the background that is to be covered by the rectangle is captured in drawRectangle() and saved in the variable "imageData". Then the rectangle is drawn over the background. Then, 1 second later, eraseRectangle() is called, and the background is replaced by a call to putImageData().
In this fiddle:
https://jsfiddle.net/f3Luxcoc/
Here's the javascript:
//coordinates of rectangle
var xp = 20;
var yp = 20;
var wp = 80;
var hp = 80;
//saved background image
var imageData = null;
function doDraw() {
var can = document.getElementById("myCanvas");
can.width = 500;
can.height = 500;
var context = can.getContext("2d");
//draw background contents
var image = getImage();
context.drawImage(image, 0, 0);
context.drawImage(image, 100, 0);
context.drawImage(image, 0, 100);
context.drawImage(image, 100, 100);
drawRectangle();
}
function drawRectangle() {
var can = document.getElementById("myCanvas");
var context = can.getContext("2d");
//capture background
imageData = context.getImageData(xp, yp, wp, hp);
//draw Rectangle
context.rect(xp, yp, wp, hp);
context.fill();
setTimeout(function() {
eraseRectangle();
}, 1000);
}
function eraseRectangle() {
var can = document.getElementById("myCanvas");
var context = can.getContext("2d");
context.putImageData(imageData, xp, yp);
setTimeout(function() {
drawRectangle();
}, 1000);
}
doDraw();
function getImage() {
var image1 = new Image(237, 110);
image1.src = "data:image/png;base64,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"
return image1;
}

Related

How to apply canvas transformation on multiple images

I'm playing with canvas in HTML5 and Javascript and I have a problem:
I'd like to apply transformations used on the current image to multiple images.
What I did:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
//transformation stuff like:
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img, -img.width / 2, -img.height / 2, img.width, img.height);
ctx.beginPath();
ctx.lineTo(42, 42);
ctx.stroke();
ctx.lineTo(42, 24);
ctx.stroke();
...
ctx.rotate(Math.PI / 2);
...
};
img.src = //base64Img;
So I will apply a lot of transformations like draw some lines, crop, zoomIn etc...
How can I apply this to multiple files (more than 200) once (when these transformations are done) ?
Obviously, it will be done in multiples functions like a function to rotate, to draw a line etc.
Thank you for your help.
Put your transformations, path drawings & image drawing into a function with arguments that tell the function how each image will be treated:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png";
function start(){
// Note: img coordinates are [centerX,centerY] rather than the usual [left,top]
drawTransformedImage(img,25,50,0,.75);
drawTransformedImage(img,75,50,Math.PI*1/6,1);
drawTransformedImage(img,150,50,Math.PI*2/6,2);
drawTransformedImage(img,225,50,Math.PI*3/6,1);
drawTransformedImage(img,275,50,Math.PI*4/6,.5);
}
function drawTransformedImage(img,cx,cy,radAngle,scale){
// save incoming styling
var lw=ctx.lineWidth;
var ss=ctx.strokeStyle;
// cache often used half-sizes
var iwHalf=img.width/2;
var ihHalf=img.height/2;
ctx.lineWidth=2;
// do the specified transformations
ctx.translate(cx,cy);
ctx.rotate(radAngle);
ctx.scale(scale,scale);
// draw the image
ctx.drawImage(img,-iwHalf,-ihHalf);
// stroke some paths
ctx.beginPath();
ctx.moveTo(-iwHalf,ihHalf);
ctx.lineTo(-iwHalf,-ihHalf);
ctx.strokeStyle='orange';
ctx.stroke();
ctx.beginPath();
ctx.moveTo(-iwHalf,-ihHalf);
ctx.lineTo(+iwHalf,-ihHalf);
ctx.strokeStyle='blue';
ctx.stroke();
// clean up: reset transformations and stylings
ctx.setTransform(1,0,0,1,0,0);
ctx.lineWidth=lw;
ctx.strokeStyle=ss;
}
body{ background-color: white; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=150></canvas>
Transforming an Image
Your example does not show a image being transformed, making your question unclear.
The transform is independent of the image, it is used to transform pixel coordinates drawn onto the canvas. It does not affect the image. You can set the transform and then draw the 200 images and they will all have the same transformation applied when their content is rendered to the canvas.
Code example
To transform the image you must create a canvas, set the transform, then render the image onto that canvas. The canvas is now the transformed image.
An example of transforming an image.
var mirrorImage = function (image, vertical, horizontal) {
var imageResult, ctx, vF, hF, posX, posY;
// create new canvas
imageResult = document.createElement("canvas");
// set the pixels size to match the image
imageResult.width = image.width;
imageResult.height = image.height;
// create a drawable surface
ctx = imageResult.getContext("2d");
// create the mirror transformation
hF = horizontal ? -1, 0;
vF = vertical ? -1 : 0;
posX = horizontal ? image.width, 0;
posY = vertical ? image.height : 0;
// Apply the transform to the new image
ctx.setTransform(hF, 0, 0, vF, posX, posY);
// transform the original image by drawing it onto the new
ctx.drawImage(image, 0, 0);
// return the new image.
return imageResult;
}
// create image
var img = new Image();
img.src = "ship.png";
// when loaded transform the image
img.onload = function () {
img = mirrorImage(img, true, true);
// the image has been transformed.
}
To do that to 200 images you have to call mirrorImage (or what ever you are doing) for each image.

Multiple HTML5 canvas on one page

So I have a canvas which I want to draw multiple images onto and then layer them, so; first image would have opacity: 0.5; image two would have opacity: 0.7 and then third being opacity: 0.3;. My question.
Should I have multiple canvas elements on one page and then position: absolute; them on top of each other or try something else?
Just wondering A. Performance and B. is this semantically correct? Thanks.
You can draw the images in the same canvas.
Just change the .globalAlpha property before drawing the image.
ctx.save();
ctx.globalAlpha = 0.8;
ctx.drawImage(image1, 0, 0);
ctx.restore();
ctx.save();
ctx.globalAlpha = 0.3;
ctx.drawImage(image2, 0, 0);
ctx.restore();
ctx.save();
ctx.globalAlpha = 0.5;
ctx.drawImage(image3, 0, 0);
ctx.restore();
//...
fiddle
Yes, multiple canvas elements on top of each other is a good way to achieve layering. Though, of course, I'd stick with only two or three, for performance reasons, unless you know that your site will only be viewing by performant browsers/processors. If you don't mind losing the layering in the output, you could just use one hidden canvas as a cache to prepare drawing on, and then copy each layer over from that to another canvas which you display.
If you use multiple elements, you might want to place them within a div wrapper, or something similar, for better organisation. And note that canvases are transparent by default: in other words, you can see what's underneath them so long as you don't draw over what you want to see or set a background colour.
Rather than setting the CSS opacity on your canvas elements, use instead the globalAlpha javascript property on your canvas context when you are drawing; or set the alpha as a fillStyle before any of your individual drawing function calls, like so:
var red = 255, // 100%
green = 128, // 50%
blue = 0, // 0%
alpha = 0.5; // 50%
canvasContext.fillStyle = "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
// orange at half opacity
With CSS you can set the position and opacity of an img, so why would you want to use the canvas tag? A: Having multiple canvases don't seem to have an effect however we are only displaying 1 image on each canvas, B Well if it provides the output you want yes, however I would just stick with one canvas.
Exmaple 1 using one canvas : https://jsfiddle.net/CanvasCode/jae7snxh/
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var image1 = new Image();
image1.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQRsJ_wNvd0PfISyPZ5a_QI3Dpeo0g4T5Tuk-R26JXPxfhyFxBTVQ";
var image2 = new Image();
image2.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQQqnYE7Xtre5W0seeFETl00OPSGoujI6xUOHr18GzB4hJE5bCIaQ";
var image3 = new Image();
image3.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRkg3mvI5DwGqG9AUmOEVU6bDDQgM6fT7nQKr8D7XwbQ59lxDiVlA";
context.fillStyle = "#FF0000";
context.fillRect(0,0,500,400);
// Save original state of the context settings
context.save();
context.globalAlpha = 0.8;
context.drawImage(image1, 0, 0);
context.globalAlpha = 0.3;
context.drawImage(image2, 0, 0);
context.globalAlpha = 0.5;
context.drawImage(image3, 0, 0);
context.restore();
// Restore original state of the context settings
Chrome network shows it takes 334MS
Multiple canvas example : https://jsfiddle.net/CanvasCode/jae7snxh/3/
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');
var canvas2 = document.getElementById('canvas2');
var context2 = canvas2.getContext('2d');
var canvas3 = document.getElementById('canvas3');
var context3 = canvas3.getContext('2d');
var image1 = new Image();
image1.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQRsJ_wNvd0PfISyPZ5a_QI3Dpeo0g4T5Tuk-R26JXPxfhyFxBTVQ";
var image2 = new Image();
image2.src = "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQQqnYE7Xtre5W0seeFETl00OPSGoujI6xUOHr18GzB4hJE5bCIaQ";
var image3 = new Image();
image3.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRkg3mvI5DwGqG9AUmOEVU6bDDQgM6fT7nQKr8D7XwbQ59lxDiVlA";
context1.globalAlpha = 0.8;
context1.drawImage(image1, 0, 0);
context2.globalAlpha = 0.3;
context2.drawImage(image2, 0, 0);
context3.globalAlpha = 0.5;
context3.drawImage(image3, 0, 0);
Chrome network shows it takes 334MS

How to draw circles OVER an image background of a HTML5 canvas?

So I'm drawing a world map to a canvas. I want this world map to plot the coordinates of things dynamically by drawing circles with the arc method. I draw the world map to the canvas, get a URL for the canvas, and there are no errors in drawing the circles... The only problem is the circles are being drawn underneath the image background. Here is my code.
// The containing function is a method of an object.
createCanvas: function(done) {
var imageObj = new Image();
imageObj.onload = _.bind(function(){
var canvas = document.createElement("canvas"),
context = canvas.getContext('2d'),
w = imageObj.width,
h = imageObj.height;
canvas.width = w;
canvas.height = h;
context.drawImage(imageObj, 0, 0, w, h);
for(var i = 0; i < arrayOfCoords.length; i++){
var mapPoint = arrayOfCoords[i];
//Invoke a function that gets an object {long: x, lat: y}
var coordinates = returnCoordinatesObject(mapPoint.long, mapPoint.lat)
context.beginPath();
context.arc(coordinates, long, coordinates.lat, 10, 0, Math.PI*2, true);
context.closePath();
context.fill();
}
var canvasImage = canvas.toDataURL('image/png');
console.log(canvasImage);
done.call(this, canvasImage);
}, this);
imageObj.src="img/le-world-map.png";
},
The code isn't erroring so I presume the circles are being drawn, but drawn behind the map. There are other threads on stackoverflow that have asked similar questions but I found them unclear and was unable to implement the solutions suggested...
Thx
--Gaweyne

how to split a canvas diagonally or non-square pieces

Say I have a canvas that's a rectangle. I want to take that canvas and split it diagonally and be able to manipulate those pieces to do whatever I want.
My end goal is to have a rectangle split diagonally and the 2 pieces animate off screen in opposite directions. I was thinking of doing this entirely within the canvas in an animation loop or converting each segment into an image element and using CSS3 animations to move those pieces. I'm just trying to figure out the best way to do this.
The code, codepen link, and image below are just to illustrate where I want my canvas to be split. You'll see it's not an exact split with equal sides.
http://codepen.io/FranciscoG/pen/YPjzbQ
<div id="container">
<img id="dog" src="http://i.imgur.com/1GUzYh9.jpg" width="375"
height="667">
</div>
<script>
var container = document.getElementById('container');
var dogImg = document.getElementById('dog');
function convertImageToCanvas(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
return canvas;
}
function drawLine(canvas) {
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(0,0);
context.lineTo(345, 0);
context.lineTo(0, 567);
context.lineTo(0,0);
context.stroke();
context.closePath();
return canvas;
};
var newDog = convertImageToCanvas(dogImg);
var divided = drawLine(newDog);
container.innerHTML = "";
container.appendChild(divided)
</script>
You could always use clipping but note that this would involve save/restore calls which is a relative slow business. There has been suggested to get resetClip() included in the specs but it seem to be hard to get the message across to the group why it is needed.
In any case, I would recommend the following approach:
Create an object or function that can reproduce a single mask (path) of one of the half-side of the image (ie. the diagonal line with containing box).
For left half: Draw image, set composite mode to destination-in, draw mask, extract canvas as image
For right half: Draw image, set composite mode to destination-out, draw mask, extract canvas as image
Now put the to images (just use the canvas elements directly) inside a container so that they are stacked on top of each other.
Animate using a transition or animation class.
var img = new Image(375, 667);
img.onload = setup;
img.src = "http://i.imgur.com/1GUzYh9.jpg";
function setup() {
var path = [0,0, 345,0, 0, 567]; // last point not needed..
var left = createCanvas(this, path, "destination-in");
var right = createCanvas(this, path, "destination-out");
var cont = document.getElementById("cont");
cont.appendChild(left);
cont.appendChild(right);
// animate here by setting animation/transition class or using JS:
var x = 0;
(function loop() {
left.style.left = x + "px"; // translate is smoother, but need
right.style.left = -x + "px"; // prefix in some browser. Update as needed..
x-=5; if (x < -400) x = 0;
requestAnimationFrame(loop);
})();
function createCanvas(img, path, mode) {
var canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
// draw image
ctx.drawImage(img, 0, 0);
// create mask
ctx.moveTo(path[0], path[1]);
for(var i = 2; i < path.length; i += 2) ctx.lineTo(path[i], path[i+1]);
ctx.closePath();
// composite mode and create half
ctx.globalCompositeOperation = mode;
ctx.fill();
return canvas
}
}
#cont {
position:relative;width:375px;height:667px;overflow:hidden;
}
#cont>canvas {position:absolute;left:0;right:0;}
<div id="cont"></div>
You can use context.clip to achieive your image-splitting effect
context.clip restricts an image to being drawn withing a specified path.
You can define several of these clipping regions to divide your image into several pieces (paths).
Then in an animation loop, you can clear the canvas and redraw each of these clipping regions with an changing offset. The left clipping region will move (offset) leftward in each loop. The right clipping region will move (offset) rightward in each loop.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var nextTime=0;
var duration=1000/60*3;
var offset=0;
var paths=[];
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/Dog-With-Cute-Cat.jpg";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height;
paths.push({path:[{x:0,y:0},{x:150,y:0},{x:0,y:ch}],direction:-1});
paths.push({path:[{x:150,y:0},{x:0,y:ch},{x:cw,y:ch},{x:cw,y:0}],direction:1});
requestAnimationFrame(animate);
}
function draw(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<paths.length;i++){
var path=paths[i].path;
var offX=offset*paths[i].direction;
ctx.save();
ctx.beginPath();
var pt=path[0];
ctx.moveTo(pt.x+offX,pt.y);
for(var j=1;j<path.length;j++){
var pt=path[j];
ctx.lineTo(pt.x+offX,pt.y);
}
ctx.closePath();
ctx.stroke();
ctx.clip();
ctx.drawImage(img,offX,0);
ctx.restore();
}
}
function animate(time){
if(offset<cw){requestAnimationFrame(animate);}else{log('done');}
if(time<nextTime){return;}
nextTime=time+duration;
draw();
offset++;
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

blend two images on a javascript canvas

How do you blend two arrays of pixel data to create one image? with the option of using different blending modes?
Pixastic is a special framework for advanced use of canvas, here are blending examples: http://www.pixastic.com/lib/docs/actions/blend/
If you would like do this alone, you can extract pixel data from 2 images, blend it with a mathematical equation, and put into a canvas. Here is information how to get and put pixel data from/to canvas:
http://ajaxian.com/archives/canvas-image-data-optimization-tip
Update:
Simple example with alpha blending of 2 images in proportion 50-50.
(Images borrowed from http://www.pixastic.com/sample/Butterfly.jpg and http://www.pixastic.com/sample/Flower.jpg )
<img src="Butterfly.jpg" id="img1">
<img src="Flower.jpg" id="img2">
<p>Blended image<br><canvas id="canvas"></canvas></p>
<script>
window.onload = function () {
var img1 = document.getElementById('img1');
var img2 = document.getElementById('img2');
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = img1.width;
var height = img1.height;
canvas.width = width;
canvas.height = height;
var pixels = 4 * width * height;
context.drawImage(img1, 0, 0);
var image1 = context.getImageData(0, 0, width, height);
var imageData1 = image1.data;
context.drawImage(img2, 0, 0);
var image2 = context.getImageData(0, 0, width, height);
var imageData2 = image2.data;
while (pixels--) {
imageData1[pixels] = imageData1[pixels] * 0.5 + imageData2[pixels] * 0.5;
}
image1.data = imageData1;
context.putImageData(image1, 0, 0);
};
</script>
I have created a separate, lightweight, open-source library for perform Photoshop-style blend modes from one HTML Canvas context to another: context-blender. Here's the sample usage:
// Might be an 'offscreen' canvas
var over = someCanvas.getContext('2d');
var under = anotherCanvas.getContext('2d');
over.blendOnto( under, 'screen', {destX:30,destY:15} );
See the README for more information.
I am tasked with recreating this java applet using JavaScript (must be tablet friendly, and work in all modern browsers > IE8).
I am creating images using: var image1 = new Image(); and then setting source: img.src = "some path";
So, from pepkin88 I see that the following function will blend two images by combining their pixel array data, overriding previous data from the first image with the new blended data, and finally putting the new data on the canvas resulting in a blended image:
window.onload = function () {
var img1 = document.getElementById('img1');
var img2 = document.getElementById('img2');
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = img1.width;
var height = img1.height;
canvas.width = width;
canvas.height = height;
var pixels = 4 * width * height;
context.drawImage(img1, 0, 0);
var image1 = context.getImageData(0, 0, width, height);
var imageData1 = image1.data;
context.drawImage(img2, 0, 0);
var image2 = context.getImageData(0, 0, width, height);
var imageData2 = image2.data;
while (pixels--) {
imageData1[pixels] = imageData1[pixels] * 0.5 + imageData2[pixels] * 0.5;
}
image1.data = imageData1;
context.putImageData(image1, 0, 0); };
HOWEVER, if you viewed the java applet that I'm responsible for recreating, you see that blending happens in real-time continuously as you drag the image around with the pointer the images are constantly blending based on their overlapped regions..
SO, I'm looking to modify the code to account for this, and I continually have the x, y, positions of images drawn (based on top left corner), and the w, h of all images stays static:
the following snippets don't include everything I'm doing, just what I sense is important for you to know
//Rectangle Class from Java converted to JS
function Rectangle(x, y, width, height, src) {
this.x = x;
this.y = y;
this.w = width;
this.h = height;
this.img = new Image();
this.img.src = src;
}
//Stores instance in rect array
rect[0] = new Rectangle(1, (height - 111)/2, 150, 105, "images/mMain.png");
//Draw method that's called
Rectangle.prototype.draw = function(ctx) {
//this.checkBound();
ctx.drawImage(this.img, this.x, this.y, this.w, this.h);
prepareMix(this.img, this.x, this.y, this.w, this.h);
}
So, I'm working on a prepareMix function that receives image info and uses it to get and store image data:
function prepareMix(src, x, y, w, h) {
pixels = 4 * w * h;
var image = mtx.getImageData(x, y, w, h);
var imgData = image.data;
}
Made a list of what to do:
Sense the overlapping
Get and Store the overlapping image data
Mix the overlapping region data arrays
Replace the overlapping image data with the blended data
Put the new data on the canvas
1. Sense the Overlapping:
Plan: Store image positions and compare positions data to know whether or not overlapping is occurring.
IF overlapping is TRUE, which two images is it true for? Distinguish these images that're overlapping from other images so that methods can be called on them.
js, css, html, and images in zip here BOX

Categories