As I previously blogged, image clipping masks in p5 are possible, but not easy to work with. Stackoverflow explained how to use offscreen graphics to allow "drawn" masks (vs using another image as the alpha channel) but that graphic is stretched to cover the whole image - and then when you position the now masked image, you have to deal with the width and height of the rectangle of the original image, even though you've clipped to some arbitrary part within that rectangle.
I thought I would simplify things by going for circles (vs my original idea of arches, which would be very trick to calculate bounding boxes for and reposition). Even then it wouldn't be trivial; for aesthetic reasons I might prefer a mask where the circle was on one side or the other of the original rectangle, and of course some images are "landscape-mode" and others are "portrait-mode":
It took me longer to wrestle with this problem than I want to admit (I mean not THAT long, but still) - a few false starts where I thought maybe I had to treat portrait vs landscape separately. But the "aha!" moments (more like, "oh, right...") came from noticing that A. for simplicity we are assuming that at least one of the sides of the original image is the size of circle B. we can figure out the "ratio" of how much larger the original image was than the circle for each side C. those ratios tell us how much we have to shift the positioning of the whole image in order to get the circle back to where we want it.function makeMaskedImage(img, dir){
const circleMask = createGraphics(img.width,img.height);
// fill a soft mask so we see the whole frame,
// for educational purposes
circleMask.fill('rgba(0, 0, 0, .5)');
circleMask.rect(0,0,img.width,img.height);
const sz = min(img.width,img.height);
const wRatio = img.width/sz;
const hRatio = img.height/sz;
//hard circle mask
circleMask.fill('rgba(0, 0, 0, 1)');
circleMask.circle(
(sz * wRatio) / 2 + (dir * ((sz * wRatio - sz)/2)),
(sz * hRatio) / 2 + (dir * ((sz * hRatio - sz)/2)),
sz);
img.mask(circleMask);
return {img, wRatio, hRatio, dir};
}function drawMaskedImage(maskedImg, cx, cy, sz, ){
const {img, wRatio, hRatio, dir} = maskedImg;
const trueWidth = sz * wRatio;
const trueHeight = sz * hRatio;
const xCenter = cx - (trueWidth/2);
const yCenter = cy - (trueHeight/2)
const xWiggle = ((trueWidth - sz) / 2) * dir;
const yWiggle = ((trueHeight - sz) / 2) * dir;
image(img,xCenter - xWiggle,yCenter - yWiggle,trueWidth,trueHeight);
}


Great tutorial! Your explanation on creating and positioning circle images using CSS is both practical and easy to follow. It’s always refreshing to see design and development tips that help improve the visual appeal of a website without relying heavily on complex tools. For those working with web visuals, especially in eCommerce or design-heavy platforms, handling detailed images can be challenging. That’s where a professional image masking service can really come in handy. These services are perfect for refining product images or isolating complex subjects while maintaining a clean, crisp look that integrates seamlessly into web designs. It’s a perfect complement to front-end development work like yours. Thanks for the valuable content—looking forward to more posts like this!
ReplyDelete