Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mask for putImageData with HTML5 canvas?

I want to take an irregularly shaped section from an existing image and render it as a new image in Javascript using HTML5 canvases. So, only the data inside the polygon boundary will be copied. The approach I came up with involved:

  1. Draw the polygon in a new canvas.
  2. Create a mask using clip
  3. Copy the data from the original canvas using getImageData (a rectangle)
  4. Apply the data to the new canvas using putImageData

It didn't work, the entire rectangle (e.g. the stuff from the source outside the boundary) is still appearing. This question explains why: "The spec says that putImageData will not be affected by clipping regions." Dang!

I also tried drawing the shape, setting context.globalCompositeOperation = "source-in", and then using putImageData. Same result: no mask applied. I suspect for a similar reason.

Any suggestions on how to accomplish this goal? Here's basic code for my work in progress, in case it's not clear what I'm trying to do. (Don't try too hard to debug this, it's cleaned up/extracted from code that uses a lot of functions that aren't here, just trying to show the logic).

 // coords is the polygon data for the area I want
   context = $('canvas')[0].getContext("2d");
   context.save();
   context.beginPath();
   context.moveTo(coords[0], coords[1]);
   for (i = 2; i < coords.length; i += 2) {
     context.lineTo(coords[i], coords[i + 1]);
   }
   //context.closePath();
   context.clip();

   $img = $('#main_image');
   copy_canvas = new_canvas($img); // just creates a new canvas matching dimensions of image
   copy_ctx = copy.getContext("2d");

   tempImage = new Image();
   tempImage.src = $img.attr("src");
   copy_ctx.drawImage(tempImage,0,0,tempImage.width,tempImage.height);

  // returns array x,y,x,y with t/l and b/r corners for a polygon
  corners = get_corners(coords)
  var data = copy_ctx.getImageData(corners[0],corners[1],corners[2],corners[3]);
  //context.globalCompositeOperation = "source-in";
  context.putImageData(data,0,0);
  context.restore();
like image 438
Jamie Treworgy Avatar asked May 09 '11 20:05

Jamie Treworgy


1 Answers

dont use putImageData,

just make an extra in memory canvas with document.createElement to create the mask and apply that with a drawImage() and the globalCompositeOperation function (depending on the order you need to pick the right mode;

I do something similar here the code is here (mind the CasparKleijne.Canvas.GFX.Composite function)

like image 98
Caspar Kleijne Avatar answered Oct 19 '22 02:10

Caspar Kleijne