如何使用HTML5水平翻转图像

61

在IE中,我可以使用:

<img src="http://example.com/image.png" style="filter:FlipH">

如何在HTML5中实现图像水平翻转?(或者通过使用canvas?)

谢谢大家:)

7个回答

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

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

这是从一个精灵对象中提取的代码片段,用于测试并产生了你所期望的结果。

这是另一个网站,提供更多详细信息。http://andrew.hedges.name/widgets/dev/


我们为什么不使用CSS呢?transform: scaleX(-1);是否存在保存/发布图像等问题? - sairfan
2
如果我需要在同一个画布上绘制多个图像,但只需要将其中一个水平翻转怎么办? - rahul cp
@sairfan - 是的,用于保存到数据库、云等。 - louisik1
@rahulcp你可以使用ctx.save()来保存当前的ctx设置,并使用ctx.restore()在绘制翻转图像后恢复到这些设置。 - Nathanael

77

不需要使用 HTML5,可以通过 CSS 来实现,与在 IE 中一样:

-moz-transform: scale(-1, 1);
-webkit-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
filter: FlipH;

1
我以前怎么能没有这个过日子?太棒了! - Adam Fraser
这绝对是最酷的解决方案;再次感谢 CSS 让我们的生活更轻松... - vhora

14

我喜欢Eschers上面的函数。我把它弄得更整洁更好了。我在翻转旁边添加了垂直翻转(flop)功能。此外,还可以选择以图像中心为中心绘制/旋转,而不是左上角。最后,该函数不需要所有参数。img、x和y是必需的,但其余参数不是。

如果您正在使用类似context.drawImage(...)这样的东西,现在可以只使用drawImage(...)并添加在此处解释的旋转/翻转/垂直翻转功能:

function drawImage(img, x, y, width, height, deg, flip, flop, center) {

context.save();

if(typeof width === "undefined") width = img.width;
if(typeof height === "undefined") height = img.height;
if(typeof center === "undefined") center = false;

// Set rotation point to center of image, instead of top/left
if(center) {
    x -= width/2;
    y -= height/2;
}

// Set the origin to the center of the image
context.translate(x + width/2, y + height/2);

// Rotate the canvas around the origin
var rad = 2 * Math.PI - deg * Math.PI / 180;    
context.rotate(rad);

// Flip/flop the canvas
if(flip) flipScale = -1; else flipScale = 1;
if(flop) flopScale = -1; else flopScale = 1;
context.scale(flipScale, flopScale);

// Draw the image    
context.drawImage(img, -width/2, -height/2, width, height);

context.restore();
}

示例:

var myCanvas = document.getElementById("myCanvas");
var context = myCanvas.getContext("2d"); // i use context instead of ctx

var img = document.getElementById("myImage"); // your img reference here!

drawImage(img, 100, 100); // just draw it 
drawImage(img, 100, 100, 200, 50); // draw it with width/height specified
drawImage(img, 100, 100, 200, 50, 45); // draw it at 45 degrees
drawImage(img, 100, 100, 200, 50, 0, true); // draw it flipped
drawImage(img, 100, 100, 200, 50, 0, false, true); // draw it flopped
drawImage(img, 100, 100, 200, 50, 0, true, true); // draw it flipflopped
drawImage(img, 100, 100, 200, 50, 45, true, true, true); // draw it flipflopped and 45 degrees rotated around the center of the image :-)

1
我喜欢那个想法,我稍微改进了一下,这样我就可以在精灵表和特定位置上使用它。 - InsOp

5

使用画布镜像图像或渲染。

注意。这也可以通过CSS完成。


镜像

这是一个简单的实用函数,可以水平、垂直或同时镜像图像。

function mirrorImage(ctx, image, x = 0, y = 0, horizontal = false, vertical = false){
    ctx.save();  // save the current canvas state
    ctx.setTransform(
        horizontal ? -1 : 1, 0, // set the direction of x axis
        0, vertical ? -1 : 1,   // set the direction of y axis
        x + (horizontal ? image.width : 0), // set the x origin
        y + (vertical ? image.height : 0)   // set the y origin
    );
    ctx.drawImage(image,0,0);
    ctx.restore(); // restore the state as it was when this function was called
}

使用方法

mirrorImage(ctx, image, 0, 0, true, false); // horizontal mirror
mirrorImage(ctx, image, 0, 0, false, true); // vertical mirror
mirrorImage(ctx, image, 0, 0, true, true);  // horizontal and vertical mirror

可绘制图像

很多时候,您可能想要在图像上进行绘制。我喜欢称它们为可绘制图像。将图像转换为画布即可使其成为可绘制的。

将图像转换为画布的方法如下:

function makeImageDrawable(image){
    if(image.complete){ // ensure the image has loaded
        var dImage = document.createElement("canvas"); // create a drawable image
        dImage.width = image.naturalWidth;      // set the resolution
        dImage.height = image.naturalHeight;
        dImage.style.width = image.style.width; // set the display size
        dImage.style.height = image.style.height; 
        dImage.ctx = dImage.getContext("2d");   // get drawing API
                                                // and add to image
                                                // for possible later use
        dImage.ctx.drawImage(image,0,0);
        return dImage;
    }
    throw new ReferenceError("Image is not complete.");
 }

将所有内容组合在一起

 var dImage = makeImageDrawable(image);  // convert DOM img to canvas
 mirrorImage(dImage.ctx, dImage, 0, 0, false, true); // vertical flip
 image.replaceWith(dImage);  // replace the DOM image with the flipped image
 

更多镜像

如果你想要沿着任意线进行镜像,可以参考这个回答:沿着线镜像


4

One option is to horizontally flip the pixels of images stored in ImageData objects directly, e.g.

function flip_image (canvas) {
    var context   = canvas.getContext ('2d') ;
    var imageData = context.getImageData (0, 0, canvas.width, canvas.height) ;
    var imageFlip = new ImageData (canvas.width, canvas.height) ;
    var Npel      = imageData.data.length / 4 ;

    for ( var kPel = 0 ; kPel < Npel ; kPel++ ) {
        var kFlip      = flip_index (kPel, canvas.width, canvas.height) ;
        var offset     = 4 * kPel ;
        var offsetFlip = 4 * kFlip ;
        imageFlip.data[offsetFlip + 0] = imageData.data[offset + 0] ;
        imageFlip.data[offsetFlip + 1] = imageData.data[offset + 1] ;
        imageFlip.data[offsetFlip + 2] = imageData.data[offset + 2] ;
        imageFlip.data[offsetFlip + 3] = imageData.data[offset + 3] ;
    }

    var canvasFlip = document.createElement('canvas') ;
    canvasFlip.setAttribute('width', width) ;
    canvasFlip.setAttribute('height', height) ;

    canvasFlip.getContext('2d').putImageData(imageFlip, 0, 0) ;
    return canvasFlip ;
}

function flip_index (kPel, width, height) {
    var i     = Math.floor (kPel / width) ;
    var j     = kPel % width ;
    var jFlip = width - j - 1 ;
    var kFlip = i * width + jFlip ;
    return kFlip ;
}


3
如果您想进行更复杂的绘画,其他基于比例的答案并不适用。所谓“复杂”,就是更具有动态性的情况,例如游戏。
问题在于位置也会翻转。因此,如果您想在画布的左上角绘制一幅小图像,然后将其水平翻转,它将重新定位到右上角。
解决方法是将画布平移到要绘制图像的中心,然后缩放,最后再平移回来。如下所示:
if (flipped) {
  ctx.translate(x + width/2, y + width/2);
  ctx.scale(-1, 1);
  ctx.translate(-(x + width/2), -(y + width/2));
}
ctx.drawImage(img, x, y, width, height);

这里的x和y是您希望绘制图像的位置,width和height是您希望绘制图像的宽度和高度。


这对我来说是个不错的解决方案。但是翻转呢?比如水平翻转。 - undefined

2
我发现这个页面上还没有一个函数能够满足我的需求,所以这是我的实现。它可以绘制缩放、旋转和翻转的图像(我用它将应用这些变换的DOM元素渲染到画布上)。
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
var img = document.getElementById("myimage.jpg"); //or whatever
var deg = 13; //13 degrees rotation, for example
var flip = "true";

function drawImage(img, x, y, width, height, deg, flip){
    //save current context before applying transformations
    ctx.save();
    //convert degrees to radians
    if(flip == "true"){ 
        var rad = deg * Math.PI / 180;
    }else{
        var rad = 2*Math.PI - deg * Math.PI / 180;
    }
    //set the origin to the center of the image
    ctx.translate(x + width/2, y + height/2);
    //rotate the canvas around the origin
    ctx.rotate(rad);
    if(flip == "true"){
        //flip the canvas
        ctx.scale(-1,1);
    }
    //draw the image    
    ctx.drawImage(img, -width/2, -height/2, width, height);
    //restore the canvas
    ctx.restore();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接