Is there something similar to fillColor but instead of filling the Path with color it fills it with a raster image?

1,611 views
Skip to first unread message

Brynjar Harðarson

unread,
Mar 3, 2013, 6:44:51 PM3/3/13
to pap...@googlegroups.com
Think the title pretty much speaks for itself, I just want to do arbitrary Paths and its "fillColor" is not a color but an image. So far the best idea I've got is to somehow match the shape to pixel locations in the image, arrange a raster by extracting individual pixels, draw the raster and the path over the raster with just the stroke.

Jonathan Puckey

unread,
Mar 4, 2013, 10:28:25 AM3/4/13
to pap...@googlegroups.com
I am not sure if you are still trying to mask an image using a circle, but here is how you would do that:

The following example code uses the latest nightly version of Paper.js (http://paperjs.org/downloads/paperjs-nightly.zip)

// Load from Server:

// Move the image to the center of the view:
raster.position = view.center;

// Create the mask path using an
// arbitrary position and radius,
// since we will resize later:
var circle = new Path.Circle([0, 0], 10);

// Mask the image:
var group = new Group({
children: [circle, raster],
clipped: true
});

// When the image loads:
raster.onLoad = function() {
// Fit the circle snugly around the image:
path.fitBounds(raster.bounds);
};

Brynjar Harðarson

unread,
Mar 6, 2013, 5:02:16 AM3/6/13
to pap...@googlegroups.com
This is exactly what I am looking for, except for one problem, the resulting image has "jagged edges" / is not anti-aliased, is there any way to amend that? I guess I could render a white stroke around the image, but what if the background is black or multicolored?

Brynjar Harðarson

unread,
Mar 6, 2013, 11:47:53 AM3/6/13
to pap...@googlegroups.com
Okay so I noticed that this only happens in chrome, and it seems like making an extra circle is the only thing one can do at the moment: http://stackoverflow.com/questions/9536257/how-to-anti-alias-clip-edges-in-html5-canvas-under-chrome-windows

Brynjar Harðarson

unread,
Mar 6, 2013, 1:01:27 PM3/6/13
to pap...@googlegroups.com
Found a better solution! It can be done using destination-in on an additional canvas and then move the result over to the main canvas: http://jsbin.com/akisah/3/edit

      function imgClip(image, x, y, radius) {
        var scratchCanvas = document.getElementById('scratch');
        scratchCanvas.width = radius*2;
        scratchCanvas.height = radius*2;
        var scratchCtx = scratchCanvas.getContext('2d');
        
        //drawing code
        scratchCtx.clearRect(0, 0, scratchCanvas.width, scratchCanvas.height);
        scratchCtx.globalCompositeOperation = 'source-over'; //default
        //Do whatever drawing you want. In your case, draw your image.
        scratchCtx.drawImage(image, 0,0);
        
        
        //As long as we can represent our clipping region as a single path, 
        //we can perform our clipping by using a non-default composite operation.
        //You can think of destination-in as "write alpha". It will not touch
        //the color channel of the canvas, but will replace the alpha channel.
        //(Actually, it will multiply the already drawn alpha with the alpha
        //currently being drawn - meaning that things look good where two anti-
        //aliased pixels overlap.)
        //
        //If you can't represent the clipping region as a single path, you can
        //always draw your clip shape into yet another scratch canvas.
        
        scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
        scratchCtx.globalCompositeOperation = 'destination-in';
        scratchCtx.beginPath();
        scratchCtx.arc(x, y, radius, 0, 2 * Math.PI, true);
        scratchCtx.closePath();
        scratchCtx.fill(); 
        
        return scratchCanvas;
      }
      
      var img = new Image();
      var x = 200;
      var y = 200;
      var radius = 200;
      
      img.onload = function() {
        var image = imgClip(img, x, y, radius);      
        // Load from Server:
        var raster = new Raster(image);

Brynjar Harðarson

unread,
Mar 6, 2013, 1:31:12 PM3/6/13
to pap...@googlegroups.com
Now I just need to make destination-in work with Paper.js, changing:

scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
scratchCtx.globalCompositeOperation = 'destination-in';
scratchCtx.beginPath();
scratchCtx.arc(x, y, radius, 0, 2 * Math.PI, true);
scratchCtx.closePath();
scratchCtx.fill(); 

To:

scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
scratchCtx.globalCompositeOperation = 'destination-in';
new Path.Circle([0,0], 100);
scratchCtx.fill(); 

Does not work and just cuts a rectangle off the image, so how do I use globalCompositeOperation with Paper.js, specifically "destination-in'"?
Reply all
Reply to author
Forward
0 new messages