代码之家  ›  专栏  ›  技术社区  ›  Wonka

画布-如何正确旋转垂直/水平图像?

  •  2
  • Wonka  · 技术社区  · 6 年前

    我看过许多旋转画布/缩放画布解决的问题,但这些解决方案并没有真正解决这个问题,因此仍然不确定如何让它与画布一起正常工作。

    有一个垂直固定尺寸的矩形100W_150H,如下面的红色边框所示。添加并旋转图像(垂直/水平/正方形)时,应在垂直固定尺寸矩形内正确旋转和缩放,如下面的示例所示。

    在第一个示例中,我们将使用一个 垂直的 图像(Eiffel Tower Original Image at 240W______墠400H),这是它在所有四个旋转角度下应该看起来的样子:

    在第二个示例中,我们将使用一个 水平的 图像(Dog Original Image at 1280w_720h),这是它在所有四个旋转角度下应该看起来的样子:

    使用画布最有效的方法是什么?

    (我知道CSS可以使用 transform:rotate(90deg) 和play around with the background size/position properties,but I'm trying to learn how to complete the example above using canvas for vertical/horizontal/square images).]

    here is a fiddle.

    有一个垂直固定尺寸的矩形100W_150H,如下面的红色边框所示。添加并旋转图像(垂直/水平/正方形)时,应在垂直固定尺寸矩形内旋转并正确缩放,如下面的示例所示。

    在第一个示例中,我们将使用 垂直的 图像(埃菲尔铁塔原始图像在240W 400H处),这是它在所有四个旋转角度下的外观: enter image description here

    在第二个示例中,我们将使用 水平的 图像(1280W_720H处的狗原始图像),这是它在所有四个旋转角度下的外观:

    enter image description here

    使用画布最有效的方法是什么?

    (我知道CSS可以使用 transform: rotate(90deg) 并使用背景大小/位置属性,但我正在尝试学习如何使用画布来完成上面的示例(用于垂直/水平/方形图像)。

    Here is a fiddle.

    1 回复  |  直到 6 年前
        1
  •  2
  •   Spencer Wieczorek    6 年前

    我们不需要任何 canvas.width/2-image.width/2 code,so change your onload to simply by using ctx.drawimage(image,0,0,canvas.width,canvas.height) 。除此之外,您还可以定义一个全局 ratio variable,当您侧向旋转并需要向上缩放时,该变量将用于正确缩放:

    var ratio=1;
    image.onload=函数()。{
    canvas.width=100;
    canvas.height=150;
    ratio=canvas.height/canvas.width;//我们将使用它来缩放图像以适应
    
    ctx.drawimage(图像,0,0,canvas.width,canvas.height);
    }
    

    现在,按图像中心旋转图像的最佳方法是将图像中心转换为画布的点。然后你可以旋转并把它移回原来的位置。这是因为当应用旋转时,画布(0,0)point is the point of rotation.

    函数drawRotated(degrees){
    ctx.clearrect(0,0,canvas.width,canvas.height);
    ctx.save();
    ctx.translate(canvas.width/2,canvas.height/2);//将图像中心移动到0,0
    ctx.rotate(degrees*math.pi/180);//旋转将从中心开始
    ctx.translate(-canvas.width/2,-canvas.height/2);//将图像移回正常位置
    ctx.drawimage(图像,0,0,canvas.width,canvas.height)
    ctx.restore();
    }
    

    到目前为止,使用该代码,正常和180度的图像看起来很好。但是侧边的图像需要向上缩放,这样做需要添加一些逻辑来检测图像是向左还是向右翻转,然后按ratio.variable(1.5.在这种情况下,)缩放。

    函数drawRotated(degrees){
    ctx.clearrect(0,0,canvas.width,canvas.height);
    ctx.save();
    ctx.translate(canvas.width/2,canvas.height/2);
    ctx.旋转(度*数学.pi/180);
    如果((度-90)%180==0)//图像是侧面的吗?
    ctx.scale(ratio,ratio);//放大以填充画布
    ctx.translate(-canvas.width/2,-canvas.height/2);
    ctx.drawimage(图像,0,0,canvas.width,canvas.height)
    ctx.restore();
    }
    

    updated fiddle.

    更新:

    水平图像看起来奇怪的原因有两个原因。目前,缩放假设图像在侧面时需要放大,如果水平图像发生逻辑翻转,则需要放大。相反,我们希望在正常翻转或倒置时放大:

    函数drawRotated(degrees){
    ctx.clearrect(0,0,canvas.width,canvas.height);
    …
    
    如果(imgratio<1)角度比例+=90
    如果(角度比例%180==0)
    cTx.比例(比率、比率);
    
    ctx.translate(-canvas.width/2,-canvas.height/2);
    …
    }
    

    这里我们根据图像是否水平来确定。否则它将是垂直的。虽然这是一个有点宽的笔画主张垂直与水平,它将工作的目的,假设我们只是有垂直或水平的图像。

    虽然即使在这些更改之后,仍有一些内容关闭(请参见此小提琴)。这是因为当我们绘制图像时,我们将其与垂直的画布相匹配,从而使图像在绘制到画布时拉伸。

    这可以通过更改绘制图像目标的位置来解决。对于水平图像,我们希望水平绘制:

    一个注意事项是对onload>方法的一些更改:

    var ratio=0;
    var ximgoffset=0;
    var yimgoffset=0;
    image.onload=函数()。{
    canvas.width=100;
    canvas.height=150;
    比率=canvas.height/canvas.width;
    var imgratio=image.height/image.width;
    
    如果(imgratio<1)//水平图像设置高度,然后按比例缩放宽度
    var dimdiff=image.height/canvas.width;
    image.height=canvas.width;//这会记住图像
    image.width=image.width/dimdiff;//旋转,这就是使用宽度的原因
    }else//垂直图像设置高度,然后按比例缩放高度
    var dimdiff=image.width/canvas.width;
    image.width=canvas.width;
    image.height=image.height/dimdiff;
    }
    
    ximgoffset=-(image.width-canvas.width)/2;
    yimgoffset=-(image.height-canvas.height)/2;
    
    旋转牵引(0);
    }
    

    立即调用drawRotated方法以应用缩放更改。除此之外,ximgoffsetandyimgoffsetare the difference in positions between the starting location of a horizontal and vertical canvas size in proportion to the original image dimensions.

    从视觉上看,这看起来像这样:

    在上面的图像中,当我们在画布中绘制水平图像时,我们需要绘制一个绿色的水平矩形。对于垂直图像,绘制图像时,宽度设置为画布宽度,高度按比例缩放,偏移量使图像居中。同样,对于水平图像,这也是一样的,我们只需记住,我们正在绘制这幅图,就像画布最初是水平的一样(请参见第一个图)。

    最后,整个方法如下:

    函数drawRotated(degrees){
    ctx.clearrect(0,0,canvas.width,canvas.height);
    ctx.save();
    ctx.translate(canvas.width/2,canvas.height/2);
    ctx.旋转(度*数学.pi/180);
    var angletoScale=度-90;
    var imgratio=image.height/image.width;
    
    如果(imgratio<1)角度比例+=90
    如果(角度比例%180==0)
    cTx.比例(比率、比率);
    
    ctx.translate(-canvas.width/2,-canvas.height/2);
    ctx.drawimage(图像,ximgoffset,yimgoffset,image.width,image.height);
    ctx.restore();
    }
    
    
    

    更新水平和垂直图像的fiddle,使用原始图像比率和裁剪

    此设置可用于任何画布尺寸和大小。

    . 除此之外,您还可以定义一个全局ratio当您侧向旋转并需要向上缩放时,将用于正确缩放的变量:

    var ratio = 1;
    image.onload=function(){
        canvas.width = 100;
        canvas.height = 150;
        ratio = canvas.height/canvas.width; // We will use this for scaling the image to fit
    
        ctx.drawImage(image,0,0, canvas.width, canvas.height);
    }
    

    现在,按图像中心旋转图像的最佳方法是将图像中心转换为(0,0)画布上的点。然后你可以旋转并把它移回原来的位置。这是因为当应用旋转时,画布(0,0)点是旋转点。

    function drawRotated(degrees){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.save();
        ctx.translate(canvas.width/2,canvas.height/2);   // Move image center to 0,0
        ctx.rotate(degrees*Math.PI/180);                 // Rotate will go from center
        ctx.translate(-canvas.width/2,-canvas.height/2); // Move image back to normal spot
        ctx.drawImage(image,0,0, canvas.width, canvas.height)
        ctx.restore();
    }
    

    到目前为止,使用该代码,正常和180度的图像看起来很好。但是侧面的图像需要向上缩放,这样做需要添加一些逻辑,以检测图像是向左还是向右翻转,然后按比率变量(1.5在这种情况下)

    function drawRotated(degrees){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.save();
        ctx.translate(canvas.width/2,canvas.height/2);
        ctx.rotate(degrees*Math.PI/180);
        if((degrees - 90) % 180 == 0) // Is the image sideways?
            ctx.scale(ratio, ratio);  // Scale it up to fill the canvas
        ctx.translate(-canvas.width/2,-canvas.height/2);
        ctx.drawImage(image,0,0, canvas.width, canvas.height)
        ctx.restore();
    }
    

    Updated Fiddle

    更新:

    水平图像看起来奇怪的原因有两个原因。目前,缩放假设图像在侧面时需要放大,如果水平图像发生逻辑翻转,则需要放大。相反,我们希望在正常翻转或倒置时放大:

    function drawRotated(degrees) {
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ...
    
        if(imgRatio < 1) angleToScale += 90
        if(angleToScale % 180 == 0)
            ctx.scale(ratio, ratio);
    
        ctx.translate(-canvas.width/2,-canvas.height/2);
        ...
    }
    

    这里我们根据imgRatio < 1我们会声称图像是水平的。否则它将是垂直的。虽然这是一个有点宽的笔画主张垂直与水平,它将工作的目的,假设我们只有垂直或水平的图像。

    尽管在这些变化之后,仍有一些东西关闭了。(see this fiddle)这是因为当我们绘制图像时,我们将其与垂直的画布相匹配,从而使图像在绘制到画布时拉伸。

    这可以通过更改绘制图像目标的位置来解决。对于水平图像,我们希望水平绘制:

    enter image description here

    一个注意事项是重载方法:

    var ratio = 0;
    var xImgOffset = 0;
    var yImgOffset = 0;
    image.onload=function(){
        canvas.width = 100;
        canvas.height = 150;
        ratio = canvas.height/canvas.width;
        var imgRatio = image.height/image.width;
    
        if(imgRatio < 1) { // Horizonal images set Height then proportionally scale width
            var dimDiff = image.height/canvas.width;
            image.height = canvas.width;         // This keeps in mind that the image 
            image.width = image.width / dimDiff; // is rotated, which is why width is used
        } else {           // Verticle images set Height then proportionally scale height
            var dimDiff = image.width/canvas.width;
            image.width = canvas.width;
            image.height = image.height / dimDiff;
        }
    
        xImgOffset = -(image.width - canvas.width) / 2;
        yImgOffset = -(image.height - canvas.height) / 2;
    
        drawRotated(0);
    }
    

    这个drawRotated立即调用方法以应用缩放更改。还有那个xImgOffsetyImgOffset水平和垂直画布大小的起始位置与原始图像尺寸成比例的位置差。

    从视觉上看,这看起来像这样:

    enter image description here

    在上面的图像中,当我们在画布中绘制水平图像时,我们需要绘制一个绿色的水平矩形。对于垂直图像,绘制图像时,宽度设置为画布宽度,高度按比例缩放,偏移量使图像居中。同样地,对于水平图像也是如此,我们只需要记住,我们正在绘制这个,就像画布最初是水平的一样。(见第一图)

    最后,整个方法如下:

    function drawRotated(degrees){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.save();
        ctx.translate(canvas.width/2,canvas.height/2);
        ctx.rotate(degrees*Math.PI/180);
        var angleToScale = degrees - 90;
        var imgRatio = image.height/image.width;
    
        if(imgRatio < 1) angleToScale += 90
        if(angleToScale % 180 == 0)
            ctx.scale(ratio, ratio);
    
        ctx.translate(-canvas.width/2,-canvas.height/2);
        ctx.drawImage(image, xImgOffset, yImgOffset, image.width, image.height);
        ctx.restore();
    }
    

    Updated Fiddle For both horizontal and vertical images with original image ratio and cropping

    此设置可用于任何画布尺寸和大小。