HTML Canvas: How to Draw a Flipped/Mirrored Image

HTML Canvas: How to draw a flipped/mirrored image?

  1. You can do this by transforming the context with myContext.scale(-1,1) before drawing your image, however

  2. This is going to slow down your game. It's a better idea to have a separate, reversed sprite.

How to rotate and mirror canvas element?

setTransform(1,0,0,-1,0,canvas.height);

Use setTransform it takes 6 numbers. The first 2 are the direction and scale of the x axis in pixels. By default it is 1,0. The next two are the direction and scale of the y axis. By default it is 0,1. The last two are the origin. Where on the canvas something will be drawn if you draw at 0,0. By default it is at 0,0 top left.

Rotating the canvas 180 will flip both the x and y axis. the x axis goes from 1,0 to -1,0 and y axis from 0,1 to 0,-1.

To mirror on the x axis just reverse x component of the x Axis thus the rotated -1,0 mirrors to 1,0.

Now we need to set the origin. The x axis moves from left to right as normal 1,0 so the x origin is on the left at 0. The y axis moves from bottom up thus the origin needs to be at the bottom of the canvas.

The result then is

ctx.setTransform(1,0,0,-1,0,canvas.height);
ctx.drawImage(0,0)

BTW rotate 180 then mirror X is the same as just mirror Y.

How to flip images horizontally with HTML5

canvas = document.createElement('canvas');
canvasContext = canvas.getContext('2d');

canvasContext.translate(width, 0);
canvasContext.scale(-1, 1);
canvasContext.drawImage(image, 0, 0);

Here's a snippet from a sprite object being used for testing and it produces the results you seem to expect.

Here's another site with more details. http://andrew.hedges.name/widgets/dev/

Flipping and mirroring an image multiple times on a canvas

Flipping an image horizontally (left to right) involves:

  • translate to the horizontal middle of the image. This sets the rotation point as the horizontal middle of the image. It does this by moving the canvas's [0,0] origin horizontally to the middle of the image.

    context.translate(x+img.width/2,0);
  • Use scale to flip the image horizontally. This causes the image to be drawn as a horizontal mirror of itself.

    context.scale(-1,1);
  • drawImage the image offset by half the image's width. This offset is necessary because context.translate has moved the [0,0] to the midpoint of the image so the image must be pulled leftward so that it's drawn at the desired X location.

    context.drawImage(img,-img.width/2,y);

Sample Image

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 img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/multple/car1.png";function start(){ drawImageExtended(img,50,50); drawImageExtended(img,50,92,true);}
function drawImageExtended(img,x,y,flipHorizontally){ if(flipHorizontally){ ctx.translate(x+img.width/2,0); ctx.scale(-1,1); ctx.drawImage(img,-img.width/2,y); }else{ ctx.drawImage(img,x,y); }}
body{ background-color: ivory; }#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

How to flip an image with the HTML5 canvas without scaling

Negative region does not seem to be supported (yet?), or this line may affect how the implementation is done, ref. step 4:

The image data must be processed in the original direction, even if
the dimensions given are negative.

In any case, we can't do much about it but to look at alternative ways -

This leaves you with some options though - I assume you want to avoid using save/restore, and you can -

Reset transformation

This is the fastest method, but you need to be aware of that it will reset any transformation. And this may be OK in most cases, so:

ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0);

The last call is resetting the transformation matrix using an identity matrix.

Reversing last transformation operation

If you depend on other transformations, you can simply reverse the last transformation operation. This is the second fastest option (it need to do a matrix multiplication internally):

ctx.scale(-1, 1);
ctx.drawImage(image, -image.width, 0);
ctx.scale(-1, 1); // revert scale only

Using save/restore

As you already know... but slow as it saves and restores the whole state of the canvas, not just the transformation.

Flipping manually

If there for some reason is a requirement not to use transformation at all, you can always flip it scanline by scanline. This is the second least efficient method but allows you to work without transformations, and it does allow you to do other things like displacing:

for(var x = 0; x < width; x++)
ctx.drawImage(img, x, 0, 1, height, width - x, 0, 1, height);

(width and height being the image's width and height).

Pixel manipulation

And the last, just for the record, is of course to get the pixel data and loop through, switch places etc. This is the slowest method and it depends on CORS requirement, and is not recommended for this.

How to horizontally flip an image

First, to remove your 2 unwanted image, just clear the canvas and redraw the desired images. You can clear the canvas using context.clearRect(0,0,canvas.width,canvas.height).

Flip image(s) horizontally

Sample Image

How to horizontally flip an image:

  1. Move (translate) the canvas origin to your desired X-coordinate plus the image width: context.translate(x+img.width,y); Adding the img.width is necessary because we are grabbing the left edge of the image and flipping it leftward. Without adding img.width, the img would be drawn leftward of the desired x-coordinate.

  2. Flip horizontally using context.scale(-1,1);

  3. Draw the image: `context.drawImage(img,0,0);

  4. Clean up by resetting transformations to their default values: context.setTransform(1,0,0,1,0,0);

Annotated code and a Demo:

var canvas=document.getElementById("canvas");var ctx=canvas.getContext("2d");var cw=canvas.width;var ch=canvas.height;
var img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/multple/sillouette2.png";function start(){
ctx.fillText('original',10,30); ctx.drawImage(img,10,30);
ctx.fillText('flipped',150,30); flipHorizontally(img,150,30);
}
function flipHorizontally(img,x,y){ // move to x + img's width ctx.translate(x+img.width,y);
// scaleX by -1; this "trick" flips horizontally ctx.scale(-1,1); // draw the img // no need for x,y since we've already translated ctx.drawImage(img,0,0); // always clean up -- reset transformations to default ctx.setTransform(1,0,0,1,0,0);}
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>

How to Flip & Rotate images on HTML5 Canvas

value: function drawRotatedImage(canvas, image, angle, mirrorImage) {
var context = canvas.getContext('2d');
if (angle > 0) {
context.rotate(angle * (Math.PI / 180));
}
if (mirrorImage === true) {
if (angle > 0) {
context.scale(-1, 1);
context.drawImage(image, -image.width, -image.height, image.width, image.height);
}
}

if (mirrorImage === true) {
if (angle < 1) {
context.scale(-1, 1);
context.drawImage(image, -image.width, 0, image.width, image.height);
}
} else {
context.drawImage(image, 0, angle === 0 ? 0 : -image.height);
}
return canvas;
}

getusermedia - Mirror image instead of flip

The arguments to CanvasContext2d.setTransform are

setTransform(scaleX, skewX, skewY, scaleY, translateX, translateY)

You are setting scaleY to -1 and translating by height on the Y axis. So indeed, you flipped vertically.

To flip horizontally, you'd do

ctx.setTransform(-1,0,0,1,canvas.width,0);

const vid = document.createElement('video');const ctx = canvas.getContext('2d');// gUM has problems with StackSnippet's overprotected iframes// so we'll use a normal video insteadvid.src = 'https://upload.wikimedia.org/wikipedia/commons/transcoded/a/a4/BBH_gravitational_lensing_of_gw150914.webm/BBH_gravitational_lensing_of_gw150914.webm.480p.webm';vid.play()  .then(() => {    canvas.width = vid.videoWidth;    canvas.height = vid.videoHeight;    drawloop();  });
function drawloop() { if (inp.checked) { ctx.setTransform(-1, 0, 0, 1, canvas.width, 0); } else { ctx.setTransform(1, 0, 0, 1, 0, 0); } ctx.drawImage(vid, 0, 0); requestAnimationFrame(drawloop);}
canvas {  width: 100%;}
<label>flip horizontally<input type="checkbox" id="inp"></label><br><canvas id="canvas"></canvas>

Flip a sprite in canvas

You can transform the canvas drawing context without flipping the entire canvas.

c.save();
c.scale(-1, 1);

will mirror the context. Draw your image, then

c.restore();

and you can draw normally again. For more information, see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Transformations



Related Topics



Leave a reply



Submit