canvas shadow with globalCompositeOperation[ destination-out ] - javascript

..Hi there, After a long gap,i again got the opportunity to work with JavaScript and canvas.
here i am trying to draw, transparent image using canvas [ globalCompositeOperation ] helps me alot,
i got success on draw image[img1] and removed a overlapped part of image[ img2 ].
search alot but failed : Wanna try to drop shadow on output of canvas,look like below,
Please check out and give me your valuable suggestion OR solution.
$('.bg').one("load", function() {
var canvas = document.getElementById('canva'),
context = canvas.getContext('2d'),
img1 = $('.bg')[0],
img2 = $('.bgover')[0];
context.drawImage(img1, 0, 0);
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.drawImage(img2, 10, 10);
context.closePath();
//drop shadow -> Doesn't work
context.shadowBlur = 5;
context.shadowOffsetX = 10;
context.shadowOffsetY = 10;
context.shadowColor = "black";
});
body {
background: #E7FF00
}
.bg {
background: url() center;
width: 300px;
height: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<img class='bg' src="http://www.qdtricks.org/wp-content/uploads/2015/02/hd-wallpapers-for-mobile.jpg" style='display:none'>
<img class='bgover' src="http://spotremoval.coit.com/sites/spotremoval.coit.com/files/styles/stain_sidebar/public/Feces%20Stain%20Removal%20-%20SPOT%20REMOVAL%20GUIDE.png?itok=j6f96IHQ" style='display:none'>
<canvas id="canva" width="400" height="400" style="position:absolute;left:0;top:0"></canvas>

Inner shadow with destination-out & source-atop
This is my solution. Load the image then create a copy with a 2D context so it can be drawn to. Then create a second image a little bigger to accommodate the shadow, offsets, and blur. Make it an inverted mask with comp destination-out. Set the original image's shadow settings. Then draw the mask image on top with comp source-atop
Now the image has the shadow and can be draw where you want it.
The function innerShadow(image,col,offX,offY,blur) does the work. Code is commented so enjoy :)
/** CanvasCtx.js begin **/
var canvas = document.getElementById("canV");
var ctx = canvas.getContext("2d");
/** CanvasCtx.js end **/
// copies an image adding the 2d context
function copyImage(img){
var image = document.createElement("canvas");
image.width = img.width;
image.height = img.height;
image.ctx = image.getContext("2d");
image.ctx.drawImage(img,0,0);
return image;
}
// creates a blank image with 2d context
var createImage = function(w,h){
var image = document.createElement("canvas");
image.width = w;
image.height =h;
image.ctx = image.getContext("2d");
return image;
}
// load an image from URL. Create a editable copy and then
// call the function ready
var loadImage = function(url,ready){
function onload(){
this.removeEventListener("load",onload);
image = copyImage(this);
ready(image);
}
var image = new Image();
image.src = url;
image.addEventListener("load",onload);
}
function innerShadow(image,shadowCol,offX,offY,blur){
var mx, my, img1;
// create a mask image, with pixel alpha the invers of original
// Needs to be bigger so that the shadow is consistant at edges
img1 = createImage(image.width+Math.abs(offX)+blur,image.height+Math.abs(offY)+blur);
// set the shadow colur to requiered but only for alising the edge
img1.ctx.fillStyle = shadowCol;
img1.ctx.fillRect(0,0,img1.width,img1.height); // fill the mask
img1.ctx.globalCompositeOperation = "destination-out"; // remove dest pixels
mx = img1.width/2- image.width/2; // recalculate offsets
my = img1.height/2- image.height/2;
// draw it 3 times to remove the slight alpha edge bleading
img1.ctx.drawImage(image,mx,my); // cut out the images shape from mask
img1.ctx.drawImage(image,mx,my); // cut out the images shape from mask
img1.ctx.drawImage(image,mx,my); // cut out the images shape from mask
// set up shadow settings
image.ctx.shadowColor = shadowCol;
image.ctx.shadowOffsetX = offX;
image.ctx.shadowOffsetY = offY;
image.ctx.shadowBlur = blur;
// draw the mask with the shadow on original image
image.ctx.globalCompositeOperation = "source-atop"; // only visible pixels
image.ctx.drawImage(img1,-mx,-my); // draw the shadow
}
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height)
// load and add shadow.
var imageWithInnerShadow;
var shadowOffX = 10;
var shadowOffY = 10;
var shadowBlur = 10;
var shadowCol = "Black";
// load the image
loadImage("http://i.stack.imgur.com/Jafta.png",function(img){
// add the shadow
innerShadow(img,shadowCol,shadowOffX,shadowOffY,shadowBlur);
ctx.drawImage(img,20,20); // show that it worked
imageWithInnerShadow = img; // hold the image for use
})
.canC { width:500px; height:500px;}
<canvas class="canC" id="canV" width=500 height=500></canvas>

Here's a dropShadow function that has the desired effect.
$('.bg').one("load", function() {
var canvas = document.getElementById('canva'),
context = canvas.getContext('2d'),
img1 = $('.bg')[0],
img2 = $('.bgover')[0];
context.drawImage(img1, 0, 0);
context.save();
context.globalCompositeOperation = 'destination-out';
context.drawImage(img2, 10, 10);
context.restore();
dropShadow(canvas, "red", 5, 2, 2);
});
// This function draws the image to left of canvas
// leaving only the shadow then draws the shadow in the
// empty space.
function dropShadow(can, color, blur, offsetX, offsetY) {
var s_can = document.createElement('canvas');
var s_ctx = s_can.getContext('2d');
var ctx = can.getContext('2d');
var w = can.width;
var h = can.height;
s_can.width = w;
s_can.height = h;
s_ctx.shadowBlur = blur;
s_ctx.shadowColor = color;
s_ctx.shadowOffsetX = w;
s_ctx.shadowOffsetY = 0;
s_ctx.drawImage(can, 0, 0, w, h,-w,0,w,h);
ctx.save();
ctx.globalCompositeOperation = 'destination-over';
ctx.drawImage(s_can, offsetX, offsetY);
ctx.restore();
}
body {
background: #E7FF00
}
.bg {
background: url() center;
width: 300px;
height: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<img class='bg' src="http://www.qdtricks.org/wp-content/uploads/2015/02/hd-wallpapers-for-mobile.jpg" style='display:none'>
<img class='bgover' src="http://spotremoval.coit.com/sites/spotremoval.coit.com/files/styles/stain_sidebar/public/Feces%20Stain%20Removal%20-%20SPOT%20REMOVAL%20GUIDE.png?itok=j6f96IHQ" style='display:none'>
<canvas id="canva" width="400" height="400" style="position:absolute;left:0;top:0"></canvas>

Related

How can I crop an area of an image using JavaScript?

How can I crop an area of an image using JavaScript? As I have read, I must use a canvas to project the image on it.
With the following code I am cutting an area of an image, but the size of the cut area is not the indicated one.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// draw cropped image
var sourceX = 0;
var sourceY = 0;
var sourceWidth = 500;
var sourceHeight = 150;
var destWidth = sourceWidth;
var destHeight = sourceHeight;
var destX = canvas.width / 2 - destWidth / 2;
var destY = canvas.height / 2 - destHeight / 2;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
<canvas id="myCanvas" style="border:1px solid red"></canvas>
I am trying to represent in this image what I want to do.
my main problem is that the canvas does not adapt to the size of the cropped image and the final height (sourceHeight ) and width (sourceWidth ) They are not the ones I specified
How can i fix it?
The problem
Your source "width" is the same width as the image.
The solution
When using ctx.drawImage with 9 arguments, think of it like a cut and paste.
You want to "cut" the outline in red, and "paste" it to your new - centered - location.
You want to "cut" all the way up to the half way point of the source. So you need to select all the way up to the half way point of the image.
I also suggest maybe changing the variable name from "source" to "crop" (cropX, cropWidth, etc) to better reflect its purpose, as it is not really the width of the "source" anymore.
If you want the image to fill the entire canvas, "paste" it with the canvas' width and height at (0,0)
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, canvas.width, canvas.height);
The code
...
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
// crop from 0,0, to 250,150
var cropX = 0;
var cropY = 0;
var cropWidth = 250;
var cropHeight = 150;
//resize our canvas to match the size of the cropped area
canvas.style.width = cropWidth;
canvas.style.height = cropHeight;
//fill canvas with cropped image
context.drawImage(imageObj, cropX, cropY, cropWidth, cropHeight, 0, 0, canvas.width, canvas.height);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
...
You'll need to tell the canvas the size of the image you're trying to display to ensure the canvas has the desiredWith size;
However, the size of your example image is 438 × 300, which makes it hard to crop to 500px.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = 'https://placehold.it/700x700';
imageObj.onload = function() {
const desiredWidth = 500;
const desiredHeight = 150;
canvas.width = desiredWidth;
canvas.height = desiredHeight;
context.drawImage(imageObj, 0, 0, desiredWidth, desiredHeight, 0, 0, desiredWidth, desiredHeight);
console.log(canvas.width, canvas.height);
};
<canvas id="myCanvas" style="border:1px solid red"></canvas>

How to scale an image for a canvas pattern?

I want to fill a Canvas with an Image and scale it to a certain width beforehand.
I am trying to achieve an effect where an image in the foreground of the canvas can be erased with the mouse to view an image in the background. This is why I need to use a pattern to fill my canvas instead of just using drawImage(). Everything works apart from the scaling of the foreground image. Here is my code for generating the pattern:
var blueprint_background = new Image();
blueprint_background.src = "myfunurl";
blueprint_background.width = window.innerWidth;
blueprint_background.onload = function(){
var pattern = context.createPattern(this, "no-repeat");
context.fillStyle = pattern;
context.fillRect(0, 0, window.innerWidth, 768);
context.fill();
};
This does exactly what it should do, except that the image keeps its original size.
As you see, I want the image to scale to window.innerWidth (which has the value 1920 when logging it).
If needed, I can provide the rest of the code, but since the error is most likely in this snippet, I decided not to post the rest.
EDIT: Here is my full code with the suggested changes. The front ground image now displays over the full width, however the erasing does not work anymore.
JavaScript (Note that I use jQuery instead of $):
jQuery(document).ready(function() {
var cwidth = window.innerWidth;
var cheight = 768;
function createCanvas(parent, width, height) {
var canvas = {};
canvas.node = document.createElement('canvas');
canvas.context = canvas.node.getContext('2d');
canvas.node.width = width || 100;
canvas.node.height = height || 100;
parent.appendChild(canvas.node);
return canvas;
}
function init(canvas, fillColor) {
var ctx = canvas.context;
canvas.isDrawing = true;
jQuery('#canvas').children().css('position:absolute; top: ' + jQuery('#Top_bar').height() + 'px');
// define a custom fillCircle method
ctx.fillCircle = function(x, y, radius, fillColor) {
this.fillStyle = fillColor;
this.beginPath();
this.moveTo(x, y);
this.arc(x, y, radius, 0, Math.PI * 2, false);
this.fill();
};
// bind mouse events
canvas.onmousemove = function(e) {
if (!canvas.isDrawing) {
return;
}
var x = e.pageX - this.offsetLeft;
var y = e.pageY - jQuery('#Top_bar').outerHeight();
var radius = 30;
var fillColor = '#ff0000';
ctx.globalCompositeOperation = 'destination-out';
ctx.fillCircle(x, y, radius, fillColor);
};
}
var container = document.getElementById('canvas');
jQuery('#canvas').css('position:absolute; top: ' + jQuery('#Top_bar').height() + 'px');
var canvas = createCanvas(container, cwidth, cheight);
init(canvas, '#ddd');
var fgimg = document.getElementById("fgimg");
fgimg.width = cwidth;
var context = canvas.node.getContext("2d");
let canvasP = document.getElementById("pattern");
canvasP.width = window.innerWidth;
canvasP.height = 768;
let ctxP = canvasP.getContext("2d");
ctxP.drawImage( fgimg, 0, 0,window.innerWidth,768 );
context.fillStyle = context.createPattern(canvasP,"no-repeat");
context.fillRect(0,0, canvas.width, canvas.height);
});
CSS:
#canvas {
background:url(http://ulmke-web.de/wp-content/uploads/2019/01/Header-6.jpg);
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
width: 100%;
height: 768px;
}
HTML:
<div id="canvas">
<canvas id="pattern">
</div>
<div style="display:none">
<img id="fgimg" src=" http://ulmke-web.de/wp-content/uploads/2019/01/Header-5.jpg">
</div>
I would use two canvases. On the first one you draw your image and you use this canvas as an image to create the pattern. In order to scale the image you scale the size of the first canvas #pattern in my example.
For example you can do this for a 10/10 image:
canvasP.width = 10;
canvasP.height = 10;
ctxP.drawImage( redpoint, 2.5, 2.5 );
or you can do this for a 20/20 image:
canvasP.width = 20;
canvasP.height = 20;
ctxP.drawImage( redpoint, 5, 5,10,10 );
Furthermore, in my example I'm adding a little margin around the image.
let canvasP = document.getElementById("pattern");
if (canvasP && canvasP.getContext) {
let ctxP = canvasP.getContext("2d");
/*canvasP.width = 10;
canvasP.height = 10;
ctxP.drawImage( redpoint, 2.5, 2.5 ); */
canvasP.width = 20;
canvasP.height = 20;
ctxP.drawImage( redpoint, 5, 5,10,10 );
}
let canvas1 = document.getElementById("canvas");
if (canvas1 && canvas1.getContext) {
let ctx1 = canvas1.getContext("2d");
if (ctx1) {
ctx1.fillStyle = ctx1.createPattern(canvasP,"repeat");
ctx1.fillRect(0,0, canvas1.width, canvas1.height);
}
}
canvas{border:1px solid}
<img id="redpoint" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO 9TXL0Y4OHwAAAABJRU5ErkJggg==">
<canvas id="pattern"></canvas>
<canvas id="canvas"></canvas>
I hope it helps.

Drawing multiple offscreen canvases into onscreen canvas

I am having an issue when I'm trying to render multiple offscreen canvases into onscreen canvas. I do get one offscreen canvas rendered but the problem is that there should be two other rendered before. In other words, only last canvas is rendered. The expected result would be three overlapping rectangles (or squares :) in red, green and blue. Here's the code:
function rectangle(color) {
var offScreenCanvas = document.createElement('canvas');
var offScreenCtx = offScreenCanvas.getContext('2d');
var width = offScreenCanvas.width = 150;
var height = offScreenCanvas.height = 150;
switch(color) {
case 1:
offScreenCtx.fillStyle='rgb(255,0,0)';
break;
case 2:
offScreenCtx.fillStyle='rgb(0,255,0)';
break;
case 3:
offScreenCtx.fillStyle='rgb(0,0,255)';
break;
}
offScreenCtx.fillRect(0,0,width,height);
return offScreenCanvas;
}
function draw(offScreenCanvas, x , y) {
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');
var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;
ctx.drawImage(offScreenCanvas, x, y);
}
var images = [];
var color = 1;
for (var i=0; i<3; i++) {
var img = new rectangle(color);
images.push(img);
color++;
}
var x = 0;
var y = 0;
for (var i = 0; i < images.length; i++) {
draw(images[i], x, y);
x += 100;
y += 100;
}
I did some searching and it seems that I'm not the first with this issue, but I could not get this working properly.
Setting canvas height or width clears the canvas.
The problem with your code is that you are causing the onscreen canvas to be cleared when you set it size in the function draw
Setting the canvas size, even if that size is the same, will cause the canvas context to reset and clear the canvas. All the other canvases are rendered, but erased when you set the onscreen canvas size.
Your draw function
function draw(offScreenCanvas, x , y) {
var canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');
// The cause of the problem ===================================
// Either one of the following lines will clear the canvas
var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;
//=============================================================
ctx.drawImage(offScreenCanvas, x, y);
}
To avoid this just set the canvas size once. If you need to resize the canvas and keep its content you first need to create a copy of the canvas, then resize it, then render the copy back to the original.
Demo shows 5 offscreen canvases being rendered onto one onscreen canvas.
const colours = ['#f00', '#ff0', '#0f0', '#0ff', '#00f'];
const ctx = can.getContext('2d');
can.width = innerWidth - 4; // sub 4 px for border
can.height = innerHeight - 4;
function createCanvas(color, i) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 150;
canvas.height = 150;
ctx.font = "24px arial";
ctx.fillStyle = color;
ctx.fillRect(0, i * 30, canvas.width, 30);
ctx.fillStyle = "black";
ctx.fillText("Canvas "+i,10,(i + 0.75) * 30);
return canvas;
}
colours.forEach((c, i) => {
ctx.drawImage(createCanvas(c, i), 0, 0);
})
canvas {
border: 2px solid black;
position : absolute;
top : 0px;
left : 0px;
}
<canvas id="can"></canvas>

rotate one of the 2 canvas objects placed in canvas

I'm developing web app using canvas and I made three. canvas, canvas_panorama and canvas_image.
First one is something like main canvas, conteiner for the others. canvas_panorama is a background for canvas_image.
After canvas is right clicked, I'm computing angle to rotate canvas_image:
function getAngle( e, pw /*canvas*/ ){
var offset = pw.offset();
var center_x = (offset.left) + ($(pw).width() / 2);
var center_y = (offset.top) + ($(pw).height() / 2);
var mouse_x = e.pageX;
var mouse_y = e.pageY;
var radians = Math.atan2(mouse_x - center_x, mouse_y - center_y);
angle = radians;
}
After I have an angle I'm trying to rotate canvas_image like this:
function redraw(){
var p1 = ctx.transformedPoint(0,0);
var p2 = ctx.transformedPoint(canvas.width,canvas.height);
ctx.clearRect( p1.x, p1.y, p2.x-p1.x, p2.y-p1.y );
canvas_image_ctx.drawImage(image_img, 0, 0, 150, 150);
canvas_panorama_ctx.drawImage(panorama_img, 0, 0, 600, 300);
canvas_panorama_ctx.drawImage(canvas_image, 20, 20);
// rotate panorama_img around its center
// x = x + 0.5 * width
// y = y + 0.5 * height
canvas_panorama_ctx.translate(95, 95);
canvas_panorama_ctx.rotate(angle);
// translate to back
canvas_panorama_ctx.translate(-95, -95);
ctx.drawImage(canvas_panorama, 0, 0);
}
But this rotates both canvas_image and canvas_panorama. It should only rotate canvas_image
JSFiddle to show you my problem
I think you are confusing yourself with this idea of multiple canvases.
Once in the drawImage() method, every of your canvases are just images, and could be just one or even just plain shapes.
Transformation methods do apply to the canvas' context's matrix, and will have effect only if you do some drawing operations when they are set.
Note : To reset your context matrix, you can either use save(); and restore() methods which will also save all other properties of your context, so if you only need to reset the transform, then it's preferred to simply reset the transformation matrix to its default : ctx.setTransform(1,0,0,1,0,0).
Here is a simplified example to make things clearer :
var ctx = canvas.getContext('2d');
// a single shape, with the border of the context matrix
var drawRect = function(){
ctx.beginPath();
ctx.rect(10, 10, 50, 20);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.rect(0, 0, canvas.width, canvas.height);
ctx.stroke();
};
// set the color of our shapes
var gradient = ctx.createLinearGradient(0,0,70,0);
gradient.addColorStop(0,"green");
gradient.addColorStop(1,"yellow");
ctx.fillStyle = gradient;
// here comes the actual drawings
//we don't have modified the transform matrix yet
ctx.strokeStyle = "green";
drawRect();
// here we translate of 100px then we do rotate the context of 45deg
ctx.translate(100, 0)
ctx.rotate(Math.PI/4)
ctx.strokeStyle = "red";
drawRect();
// reset the matrix
ctx.setTransform(1,0,0,1,0,0);
// here we move of 150px to the right and 25px to the bottom
ctx.translate(150, 25)
ctx.strokeStyle = "blue";
drawRect();
// reset the matrix
ctx.setTransform(1,0,0,1,0,0);
<canvas id="canvas" width="500" height="200"></canvas>
In your code, you are setting the transformations on the canvas that does represent your image, and you do draw every of your canvases at each call.
What you want instead, is to set the transformation on the main canvas only, and draw the non-transformed image :
var main_ctx = canvas.getContext('2d');
var img_canvas = canvas.cloneNode();
var bg_canvas = canvas.cloneNode();
var angle = 0;
// draw on the main canvas, and only on the main canvas
var drawToMain = function(){
// first clear the canvas
main_ctx.clearRect(0,0,canvas.width, canvas.height);
// draw the background image
main_ctx.drawImage(bg_canvas, 0,0);
// do the transforms
main_ctx.translate(img_canvas.width/2, img_canvas.height/2);
main_ctx.rotate(angle);
main_ctx.translate(-img_canvas.width/2, -img_canvas.height/2);
// draw the img with the transforms applied
main_ctx.drawImage(img_canvas, 0,0);
// reset the transforms
main_ctx.setTransform(1,0,0,1,0,0);
};
// I changed the event to a simple onclick
canvas.onclick = function(e){
e.preventDefault();
angle+=Math.PI/8;
drawToMain();
}
// a dirty image loader
var init = function(){
var img = (this.src.indexOf('lena')>0);
var this_canvas = img ? img_canvas : bg_canvas;
this_canvas.width = this.width;
this_canvas.height = this.height;
this_canvas.getContext('2d').drawImage(this, 0,0);
if(!--toLoad){
drawToMain();
}
};
var toLoad = 2;
var img = new Image();
img.onload = init;
img.src = "http://pgmagick.readthedocs.org/en/latest/_images/lena_scale.jpg";
var bg = new Image();
bg.onload = init;
bg.src = 'http://www.fnordware.com/superpng/pnggradHDrgba.png';
<canvas id="canvas" width="500" height="300"></canvas>

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.

Categories