Cropping images with html5 canvas in a non-rectangular shape and transforming

后端 未结 1 1059
隐瞒了意图╮
隐瞒了意图╮ 2021-01-03 09:05

I am new to html5 canvas but I am creating a html5 canvas based image cropper which includes next features.

  • It should crop image in a polygon shape, but doesn\
相关标签:
1条回答
  • 2021-01-03 09:27

    What you are asking for is similar to Photoshop's Perspective Crop Tool.

    This allow you to take in an un-straightened, skewed image and convert it into a straight, undistorted image.

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

    Left: unstraight, warped image, Right: straightened, unwarped image

    enter image description here

    You can also straighten and unwarp a 4-sided polygon in html5 canvas like this:

    1. Create a second destination canvas to hold your straightened, unwarped image.
    2. Divide the warped, 4-sided polygon into 2 triangles.
    3. Calculate the transformation matrix needed to map the first warped triangle into an unwarped triangle. A transformation matrix uses it's tools (scaling, rotation, skewing, movement) to take each pixel from the warped source triangle and transform that pixel onto the unwarped destination triangle.
    4. Clip the destination canvas to draw only in the calculated destination triangle.
    5. Draw the source image onto the destination canvas. Because the destination canvas has a clipping region defined, the image will only be drawn into that clipping region. Because the destination canvas has a transformation applied to it, the previously warped triangle will be draw as unwarped.
    6. Repeat steps #3-5 for the second warped triangle.

    So your warped image (on the left) can be unwarped (as shown on the right):

    enter image description here

    This is what the 2 unwarped triangles look like before they are stitched together to form 1 unwarped rectangle:

    enter image description here

    Here is example code and a Demo:

    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>

    0 讨论(0)
提交回复
热议问题