Search code examples
javascriptjqueryhtmlimagecanvas

canvas- Cropping images in different shapes


I'm working on a website that I need to crop images on different shapes . I found lots of libraries and I've tested some ,but the main problem is they only can crop images on pre defined shapes like rectangle , circle . What I need is to crop images in any shapes

for example ,I've written a code the users can define their shapes ( by using Map Area ) and the exact shape is make ,Now I need to crop image or copy this area and make a new image from it .

I can use php ,jquery and other platforms

Could you help me to manage this problem ?

King Regards


Solution

  • Here's one way to do it using html5 Canvas:

    enter image description hereenter image description here

    1. Use the area element's coords to draw a path on the canvas.

    // assume you've put the `coords` points as {x:,y:} objects into a points[] array:
    
        ctx.beginPath();
        ctx.moveTo(points[0].x,points[0].y);
        for(var i=1;i<points.length;i++){
            var p=points[i];
            ctx.lineTo(points[i].x,points[i].y);
        }
        ctx.closePath();
    

    2. Create a clipping path from the coords path you've just defined:

        ctx.clip();
    

    3. Draw the image on the canvas. The image will be clipped into your defined path:

         ctx.drawImage(yourImageObject,0,0);
    

    4. Create a second canvas sized to the clipping path size and use the clipping version of context.drawImage to draw just the clipped image onto the second canvas.

    // see demo below for details 
    

    5. Create a new Image() from the second canvas...Mission Accomplished!

    // create a new Image() from the second canvas
    
        var clippedImage=new Image();
        clippedImage.onload=function(){
            // append the new image to the page
            document.body.appendChild(clippedImage);
        }
        clippedImage.src=secondCanvas.toDataURL();
    

    Annotated example code and a Demo:

    // canvas related variables
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw,ch;
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    
    // set some canvas styles
    ctx.strokeStyle='black';
    
    // an array to hold user's click-points that define the clipping area
    var points=[];
    
    // load the image 
    var img=new Image();
    img.crossOrigin='anonymous';
    img.onload=start;
    img.src="https://dl.dropboxusercontent.com/u/139992952/multple/houses1.jpg";
    function start(){
    
      // resize canvas to fit the img
      cw=canvas.width=img.width;
      ch=canvas.height=img.height;
    
      // draw the image at 25% opacity
      drawImage(0.25);
    
      // listen for mousedown and button clicks
      $('#canvas').mousedown(function(e){handleMouseDown(e);});
      $('#reset').click(function(){ points.length=0; drawImage(0.25); });
    }
    
    
    
    function handleMouseDown(e){
    
      // tell the browser that we're handling this event
      e.preventDefault();
      e.stopPropagation();
    
      // calculate mouseX & mouseY
      mx=parseInt(e.clientX-offsetX);
      my=parseInt(e.clientY-offsetY);
    
      // push the clicked point to the points[] array
      points.push({x:mx,y:my});
    
      // show the user an outline of their current clipping path
      outlineIt();
    
      // if the user clicked back in the original circle
      // then complete the clip
      if(points.length>1){
        var dx=mx-points[0].x;
        var dy=my-points[0].y;
        if(dx*dx+dy*dy<10*10){
          clipIt();
        }
      }
    }
    
    
    // redraw the image at the specified opacity
    function drawImage(alpha){
      ctx.clearRect(0,0,cw,ch);
      ctx.globalAlpha=alpha;
      ctx.drawImage(img,0,0);
      ctx.globalAlpha=1.00;
    }
    
    // show the current potential clipping path
    function outlineIt(){
      drawImage(0.25);
      ctx.beginPath();
      ctx.moveTo(points[0].x,points[0].y);
      for(var i=0;i<points.length;i++){
        ctx.lineTo(points[i].x,points[i].y);
      }
      ctx.closePath();
      ctx.stroke();
      ctx.beginPath();
      ctx.arc(points[0].x,points[0].y,10,0,Math.PI*2);
      ctx.closePath();
      ctx.stroke();
    }
    
    // clip the selected path to a new canvas
    function clipIt(){
    
      // calculate the size of the user's clipping area
      var minX=10000;
      var minY=10000;
      var maxX=-10000;
      var maxY=-10000;
      for(var i=1;i<points.length;i++){
        var p=points[i];
        if(p.x<minX){minX=p.x;}
        if(p.y<minY){minY=p.y;}
        if(p.x>maxX){maxX=p.x;}
        if(p.y>maxY){maxY=p.y;}
      }
      var width=maxX-minX;
      var height=maxY-minY;
    
      // clip the image into the user's clipping area
      ctx.save();
      ctx.clearRect(0,0,cw,ch);
      ctx.beginPath();
      ctx.moveTo(points[0].x,points[0].y);
      for(var i=1;i<points.length;i++){
        var p=points[i];
        ctx.lineTo(points[i].x,points[i].y);
      }
      ctx.closePath();
      ctx.clip();
      ctx.drawImage(img,0,0);
      ctx.restore();
    
      // create a new canvas 
      var c=document.createElement('canvas');
      var cx=c.getContext('2d');
    
      // resize the new canvas to the size of the clipping area
      c.width=width;
      c.height=height;
    
      // draw the clipped image from the main canvas to the new canvas
      cx.drawImage(canvas, minX,minY,width,height, 0,0,width,height);
    
      // create a new Image() from the new canvas
      var clippedImage=new Image();
      clippedImage.onload=function(){
        // append the new image to the page
        document.body.appendChild(clippedImage);
      }
      clippedImage.src=c.toDataURL();
    
    
      // clear the previous points 
      points.length=0;
    
      // redraw the image on the main canvas for further clipping
      drawImage(0.25);
    }
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <h4>Click to outline clipping region.<br>Click back in starting circle to complete the clip.</h4>
    <button id=reset>Reset clipping path</button><br>
    <canvas id="canvas" width=400 height=300></canvas>
    <p>Clipped images by user</p>