Got custom raster stroke working, but it gets clipped off, how to fix?

129 views
Skip to first unread message

RP

unread,
Mar 8, 2017, 2:32:57 PM3/8/17
to Paper.js
I have need to stroke a clipped group and remain performant, and I've found the easiest way is to rasterize my paths and do the outlining in the raster. I found a technique that works for that, but the edges of the outline get cut off due to the initial size of the raster's canvas.

Here's the code (set up to work in Sketch) and the Sketch link. The circle on the left is the original clipped path group, the one on the right is the rasterized version with raster outline. The function outlineRaster is responsible for creating the outline.

I just need a way to increase the canvas size without stretching the raster, so that the outline edges don't get clipped off.

Changing raster.canvas.width/height causes strange behavior, changing the bounds scales it etc.

Sketch: http://sketch.paperjs.org/#S/nVZtb9s2EP4rrAY08qIoSrB9sZsCRQYUG/oytEP3Ic4HmqIkzhJpkJSdNM1/3x1l2pKouUMFv/Dl4fHuuefOfookbXg0jz6vuWVVlERM5Tgn8Cz1UuL3lmpi2pXVlNn3sE1uSEFrwxce0AcqxqkEhOQ78okay3V8Vlm7mV9eilQ0ZatTpprLD2+3v/31ZZ3+synPErIVfJcyLgE9m7RaU5l/3+gvX/54zN58OGUUDaVbYcSqPh0HAt9q1W7w2rauF+H2n9RWfndsgub5O4DEgRP+7Z053AGhuXF8520nDnA/dN5hUlaLzYYjJVa3fNE3WrSSWaEk0dxw+84fiWce8OQH+IiCxC8Odmf9LXw0t62WA/tDRzRv1JbfVqLONZfx0dchDOhwmNjH9r+As0Wf0u8ygIDnSSp8NjbKCFyY5mKkDWeXjEPH5LN9vjCQ9FZoVvP4aUxdIer6VtVKz8ky+qkoMniWUdKHjI90OpkT72YSpIPmojVz8msWbBmr1ZofL8wyvBIunAb+LXJbzcl1f/d5FiQa5XGUeqf12YTnvXJgg8xyqK/+/OlU/Hhbv9EEcgxIDnx8+fI4SQ0vG6DU4GqwmNZclnDiNclm5Nu33jG2V/PgmF/sHwv8m6DjeO8+sJgNte+YHy+MaTtluJXCcrQakvo8zue4Jww86Y+hsfZonQ238JNpTi3/2NpaSN4raxJUDNs3id5th3iDSlWdwX2T1+4rIUqLUkhaH+t2TExQolRuqQGaOhNpNw/07aD2AWXrAGnJ7a2CKnyw8dl1fjYkCNHwa3NAB5vezw7kZ6cuz99oDdC7i6sEXiRzn90Y3hmOMzd0m27v6j7BHKiigFwSqjV9DKWCoQMagbYSbC25McQwWk/ISgA267CgJE2t0iHo4QgqMKhDkwqhjwgdaXwkoFzTHVBJS24ItftYDCm0asBf3kXV+ZuTFYz65wul4wV4/cqxty9IXDi/IddBTUJ6U7zud7wthswkEMu5O3on7n82Cfjrp+dXsDAuz5Hr2NfJTkANMmy2A6XDVWWtVhQaf+P44R83SCgq+wa6slGtZvxCyGW0GB9Eu5/to/vpWUarmrL1f6A+cegiGehir9kd9nI/qbgoKxt2ck+6F2XHPhGSSKUbmDfQcH8kGKhsPeHokfJeUQD1QPeJPjAs/97fDLcgvkITScjkcvi/ESJ+D845PR2i3mDzNIrsONYwsRyTCQVSEWG6QTq2c2i0XvHpA7kApWXZAv4vr6APrjdKwC9KNL+7f/4X



Code: 

var subtractMode = false;

var ocean = new Raster('http://i.imgur.com/NGvDTVk.jpg', view.center);

var land = new Raster('http://i.imgur.com/4VJy0AN.jpg', view.center);
land.visible = false;

var landGroup = null;  
var landPath = null;

addLand(view.center);


landGroup = new Group([landPath, land]);
landGroup.clipped = true;

function resetLandGroup()
{
   if (!landGroup)
       return;

    landGroup.removeChildren();
   landGroup.addChild(landPath);
   landGroup.addChild(land);    
   landGroup.clipped = true;
}

function addLand(position)
{
   land.visible = true;

    var c = new Path.Circle({
       fillColor: "#ff0000",            
       center: position,
       radius: 50,
       strokeColor: "#00ff00",
       strokeWidth: 2
   });

    if (landPath == null)  
        landPath = c;
   else
   {            
       if (subtractMode)
       {
           if (landPath && (landPath.segments && landPath.segments.length > 0) || (landPath.children && landPath.children.length > 0))
               landPath = landPath.subtract(c);
       }
       else
           landPath = landPath.unite(c);      
   }

    resetLandGroup();
   

    c.remove();
}

function outlineRaster(raster, original)
{                
   var canvas = raster.canvas;

    var ctx = canvas.getContext('2d');
   var img = canvas;
   var originalimg = original.canvas;

    var dArr = [-1,-1, 0,-1, 1,-1, -1,0, 1,0, -1,1, 0,1, 1,1],
          s = 1,
          i = 0,
          x = 0,
         y = 0;
     
 
   for(; i < dArr.length; i += 2)
       ctx.drawImage(img, x + dArr[i]*s, y + dArr[i+1]*s);
     

    ctx.globalCompositeOperation = "source-in";
   ctx.fillStyle = "black";
   ctx.fillRect(0,0,canvas.width,canvas.height);

 
    ctx.globalCompositeOperation = "source-over";
   ctx.drawImage(originalimg, x, y);
}

outlineRaster(landGroup.rasterize(), landGroup.rasterize());

landPath.position.x -= 200;


Jürg Lehni

unread,
Mar 9, 2017, 5:17:16 AM3/9/17
to pap...@googlegroups.com

Jürg Lehni

unread,
Mar 9, 2017, 5:19:46 AM3/9/17
to pap...@googlegroups.com

Ross Pawley

unread,
Mar 9, 2017, 12:07:09 PM3/9/17
to pap...@googlegroups.com
My example was minimal but set up like that for a reason, which is that I can't use the path based stroking, because I need to remain in raster-land entirely to maintain performance. So just setting a stroke works for this trivial example but does not work for my intended use, which is to splat raster circles down, then rasterize the entire group and outline the whole thing. I would just use paths but boolean operations are far too slow (they begin to tank to <30fps with only 2-3 compound subpaths). Thus trying to stay as raster and using the raster outline method.

Thanks

To unsubscribe from this group and stop receiving emails from it, send an email to paperjs+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.


--
You received this message because you are subscribed to a topic in the Google Groups "Paper.js" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/paperjs/FgM2u90R0iY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to paperjs+unsubscribe@googlegroups.com.

Jürg Lehni

unread,
Mar 10, 2017, 5:30:01 AM3/10/17
to pap...@googlegroups.com
The canvas resizing you’re looking for is currently not possible. Feel free to create a GitHub issue for it, so we can consider adding something:


Is this the effect your are looking for:


Boolean operations are expensive of course, because the operation is performed on the actual bezier curves, looking for their intersections, splitting at found intersections and then deciding which part of the geometries are part of the result, and merging them. In your case, it sounds like you don’t need the geometries intersected and subtracted / united, you just want the visual appearance of that happening, so there are other ways to achieve that goal. blend modes could be worth looking into.

I am pretty convinced that having to go to the level of the canvas pixels and creating an effect that appears to create a stroke is not necessary though, as there should be enough flexibility to achieve what you’re looking for in other ways.

But in order to help you, we’d need to know what you are actually looking for.

j

To unsubscribe from this group and stop receiving emails from it, send an email to paperjs+u...@googlegroups.com.

Jürg Lehni

unread,
Mar 10, 2017, 5:47:53 AM3/10/17
to pap...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages