Is it possible to mirror an image horizontally (flip) with Canvas?

Asked

Viewed 5,448 times

4

I know it’s possible to mirror horizontally <img> with CSS, but wanted to know if it is possible to mirror an image horizontally inside a canvas.

With CSS, I would do like this:

#img-flip{
   transform: scaleX(-1);
}
    <img src="https://i.stack.imgur.com/pA0a1.png" id="img">
        <img src="https://i.stack.imgur.com/pA0a1.png" id="img-flip">

And with canvas? How can I do that?

var onload = function() {
    var canvas = document.querySelector("#canvas");
    var ctx = canvas.getContext("2d");
    var img = document.querySelector("#img");
    canvas.height = img.height;
    canvas.width = img.width;
    ctx.drawImage(img, 0, 0);
}


img.completed ? onload() : img.addEventListener('load', onload);
<div>Imagem original:</div>
<img src="https://i.stack.imgur.com/pA0a1.png" id="img">

<div>Resultado Canvas:</div>
<canvas id="canvas"></canvas>

2 answers

3


You can use the context.scale(-1, 1); and pass as parameter the width of the image times -1 when performing the drawImage() of context.

var onload = function() {
    var canvas = document.querySelector("#canvas");
    var ctx = canvas.getContext("2d");
    var img = document.querySelector("#img");
    canvas.height = img.height;
    canvas.width = img.width;
    ctx.scale(-1, 1);
    ctx.drawImage(img, 0, 0, img.width*-1, img.height);
}


img.completed ? onload() : img.addEventListener('load', onload);
<div>Imagem original:</div>
<img src="https://i.stack.imgur.com/pA0a1.png" id="img">

<div>Resultado Canvas:</div>
<canvas id="canvas"></canvas>

Reference HTML Canvas: How to draw a flipped/Mirrored image?

  • 3

    Beautiful and moral. + 1

  • @Wallacemaxters Thank you! We’re here for this! :)

  • 3

    Just for the record img.width*-1 would be the same as doing -img.width, i.e., the multiplication operation is not so necessary in this use.

1

An additional suggestion to the existing answer would be to use the context.translate to adjust the whole canvas instead of fixing the position in the image X, this because when using the context.scale it affects the whole canvas, so it would have to be adjusting drawImage for drawImage (supposing that it will use more than one) and other added elements also that should appear reversed.

Example of difficulty (note that the rect is not at position x=20):

var onload = function() {
    var canvas = document.querySelector("#canvas");
    var ctx = canvas.getContext("2d");
    var img = document.querySelector("#img");
    canvas.height = img.height;
    canvas.width = img.width;
    ctx.scale(-1, 1);
    ctx.drawImage(img, 0, 0, img.width*-1, img.height);

    ctx.rect(20, 20, 100, 100);
    ctx.stroke();
}

img.completed ? onload() : img.addEventListener('load', onload);
<div>Imagem original:</div>
<img src="https://i.stack.imgur.com/pA0a1.png" id="img">

<div>Resultado Canvas:</div>
<canvas id="canvas"></canvas>

Then to "fix" this, so that the position x=20 in the rect is not reversed in relation to canvas size (<canvas width="...) we would have to compensate by doing something like:

ctx.rect(-(img.width - 100 - 20), 20, 100, 100);

That is, we have to add the width of the rect with the desired position and turn the value into negative, example:

var onload = function() {
    var canvas = document.querySelector("#canvas");
    var ctx = canvas.getContext("2d");
    var img = document.querySelector("#img");
    canvas.height = img.height;
    canvas.width = img.width;
    ctx.scale(-1, 1);

    ctx.drawImage(img, 0, 0, -img.width, img.height);
    ctx.rect(-(img.width - 100 - 20), 20, 100, 100);
    ctx.strokeStyle = "red";
    ctx.stroke();
}

img.completed ? onload() : img.addEventListener('load', onload);
<div>Imagem original:</div>
<img src="https://i.stack.imgur.com/pA0a1.png" id="img">

<div>Resultado Canvas:</div>
<canvas id="canvas"></canvas>


Using Translate

However this can be complicated, costly even for development time and is surely something that can be simplified using the translate, example

var onload = function() {
    var canvas = document.querySelector("#canvas");
    var ctx = canvas.getContext("2d");
    var img = document.querySelector("#img");
    canvas.height = img.height;
    canvas.width = img.width;
    ctx.scale(-1, 1);
    ctx.translate(-canvas.width, 0);
    ctx.drawImage(img, 0, 0, img.width, img.height);

    ctx.rect(20, 20, 100, 100);
    ctx.stroke();
}

img.completed ? onload() : img.addEventListener('load', onload);
<div>Imagem original:</div>
<img src="https://i.stack.imgur.com/pA0a1.png" id="img">

<div>Resultado Canvas:</div>
<canvas id="canvas"></canvas>

Okay, this way you do not need to calculate anything, you can apply more of an object or image to the canvas that it will draw as if it were a mirror without needing adjustments, the same can be done with the axis Y, if you want to flip vertically would look like this:

ctx.scale(1, -1);
ctx.translate(0, -canvas.height);
ctx.drawImage(img, 0, 0, img.width, img.height);

Browser other questions tagged

You are not signed in. Login or sign up in order to post.