使用html5画布以非矩形形状裁剪图像并进行转换

时间:2015-06-01 05:11:13

标签: html5 canvas

我是html5画布的新手,但我正在创建一个基于html5画布的图像裁剪器,其中包含下一个功能。

  • 它应该以多边形形状裁剪图像,但不一定是矩形。
  • 裁剪图像后,应将图像转换为矩形。

我尝试搜索满足这些功能的任何图像裁剪器,但无法找到任何功能。

我认为我可以设法调整大小调整处理程序和裁剪内容,但我不知道如何转换裁剪后的图像。 有没有很好的例子或库可以做到这一点?

我正在添加图片以使事情变得清晰。 裁剪第一张图像时,结果应为第二张图像。

selecting cropping area enter image description here

ADDED!

我认为@markE的解决方案可行,但在实施和测试一些图像之后,我发现它在非平行四边形图中不能很好地工作。

sample 1 - original sample 1 - cropped

sample 2 - original sample 2 - cropped

正如你所看到的,由于这种方法将矩形分成两个三角形,扭曲的角度和数量?最终两个三角形都不同。因此,裁剪的图像显示失真。 我正在想办法解决它。

1 个答案:

答案 0 :(得分:1)

您要求的内容类似于Photoshop的Perspective Crop Tool

这使您可以拍摄未拉直的歪斜图像,并将其转换为直线,无失真的图像。

http://www.howtogeek.com/howto/30973/easily-straighten-crooked-photographs-in-photoshop/

左: unstraight,扭曲的图像,右:拉直,未扭曲的图像

enter image description here

您还可以在html5画布中拉直和取消扭曲4面多边形,如下所示:

  1. 创建第二个目标画布,以保持拉直,未扭曲的图像。
  2. 将扭曲的4边多边形分成2个三角形。
  3. 计算将第一个扭曲三角形映射为未扭曲三角形所需的变换矩阵。变换矩阵使用它的工具(缩放,旋转,倾斜,移动)从扭曲的源三角形中获取每个像素,并将该像素转换为未扭曲的目标三角形。
  4. 剪切目标画布,仅在计算出的目标三角形中绘制。
  5. 将源图像绘制到目标画布上。由于目标画布已定义裁剪区域,因此图像将仅绘制到该裁剪区域。由于目标画布已应用了变换,因此先前扭曲的三角形将绘制为未扭曲。
  6. 对第二个扭曲的三角形重复步骤#3-5。
  7. 因此,您的扭曲图片(左侧 )可以不变形(,如右侧所示):

    enter image description here

    这是2个未扭曲的三角形在缝合在一起形成1个未扭曲的矩形之前的样子:

    enter image description here

    以下是示例代码和演示:

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var canvas1=document.getElementById("canvas1");
    var ctx1=canvas1.getContext("2d");
    
    // anchors defining the warped rectangle
    var anchors={
      TL:{x:70,y:40},      // r
      TR:{x:377,y:30},     // g
      BR:{x:417,y:310},    // b
      BL:{x:70,y:335},     // gold
    }
    
    // cornerpoints defining the desire unwarped rectangle
    var unwarped={
      TL:{x:0,y:0},        // r
      TR:{x:300,y:0},      // g
      BR:{x:300,y:300},    // b
      BL:{x:0,y:300},      // gold
    }
    
    // load example image
    var img=new Image();
    img.onload=start;
    img.src="https://dl.dropboxusercontent.com/u/139992952/multple/skewed1.png";
    function start(){
    
      // set canvas sizes equal to image size
      cw=canvas.width=canvas1.width=img.width;
      ch=canvas.height=canvas1.height=img.height;
    
      // draw the example image on the source canvas
      ctx.drawImage(img,0,0);
    
      // unwarp the source rectangle and draw it to the destination canvas
      unwarp(anchors,unwarped,ctx1);
    
    }
    
    
    // unwarp the source rectangle
    function unwarp(anchors,unwarped,context){
    
      // clear the destination canvas
      context.clearRect(0,0,context.canvas.width,context.canvas.height);
    
      // unwarp the bottom-left triangle of the warped polygon
      mapTriangle(context,
                  anchors.TL,  anchors.BR,  anchors.BL,
                  unwarped.TL, unwarped.BR, unwarped.BL
                 );
    
      // eliminate slight space between triangles
      ctx1.translate(-1,1);
    
      // unwarp the top-right triangle of the warped polygon
      mapTriangle(context,
                  anchors.TL,  anchors.TR,  anchors.BR,
                  unwarped.TL, unwarped.TR, unwarped.BR
                 );
    
    }
    
    
    // Perspective mapping: Map warped triangle into unwarped triangle
    // Attribution: (SO user: 6502), http://stackoverflow.com/questions/4774172/image-manipulation-and-texture-mapping-using-html5-canvas/4774298#4774298
    function mapTriangle(ctx,p0, p1, p2, p_0, p_1, p_2) {
    
      // break out the individual triangles x's & y's
      var x0=p_0.x, y0=p_0.y;
      var x1=p_1.x, y1=p_1.y;
      var x2=p_2.x, y2=p_2.y;
      var u0=p0.x,  v0=p0.y;
      var u1=p1.x,  v1=p1.y;
      var u2=p2.x,  v2=p2.y;
    
      // save the unclipped & untransformed destination canvas
      ctx.save();
    
      // clip the destination canvas to the unwarped destination triangle
      ctx.beginPath();
      ctx.moveTo(x0, y0);
      ctx.lineTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.closePath();
      ctx.clip();
    
      // Compute matrix transform
      var delta   = u0 * v1 + v0 * u2 + u1 * v2 - v1 * u2 - v0 * u1 - u0 * v2;
      var delta_a = x0 * v1 + v0 * x2 + x1 * v2 - v1 * x2 - v0 * x1 - x0 * v2;
      var delta_b = u0 * x1 + x0 * u2 + u1 * x2 - x1 * u2 - x0 * u1 - u0 * x2;
      var delta_c = u0 * v1 * x2 + v0 * x1 * u2 + x0 * u1 * v2 - x0 * v1 * u2 - v0 * u1 * x2 - u0 * x1 * v2;
      var delta_d = y0 * v1 + v0 * y2 + y1 * v2 - v1 * y2 - v0 * y1 - y0 * v2;
      var delta_e = u0 * y1 + y0 * u2 + u1 * y2 - y1 * u2 - y0 * u1 - u0 * y2;
      var delta_f = u0 * v1 * y2 + v0 * y1 * u2 + y0 * u1 * v2 - y0 * v1 * u2 - v0 * u1 * y2 - u0 * y1 * v2;
    
      // Draw the transformed image
      ctx.transform(
        delta_a / delta, delta_d / delta,
        delta_b / delta, delta_e / delta,
        delta_c / delta, delta_f / delta
      );
    
      // draw the transformed source image to the destination canvas
      ctx.drawImage(img,0,0);
    
      // restore the context to it's unclipped untransformed state
      ctx.restore();
    }
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    <h4>Warped image transformed into an unwarped image.</h4>
    <canvas id="canvas" width=300 height=300></canvas>
    <canvas id="canvas1" width=300 height=300></canvas>