0

I was messing around with SVG Masks and after reading a few articles and testing some codes for a fancier mask, more than just simple polygons, I came up with this:

<div class="picture">
  <img src="https://i.postimg.cc/0Njq2C60/bartrix.png"
    alt="" style="clip-path: url(#myClip)">
</div>

<svg width="0" height="0">
  <defs>
    <clipPath id="myClip">
      <path id="blob" fill="none"
            d="M351,264.5Q338,279,387.5,332.5Q437,386,400.5,396Q364,406,324,380.5Q284,355,267,420Q250,485,225.5,443Q201,401,158,418.5Q115,436,82,416Q49,396,112.5,335Q176,274,100,262Q24,250,75,230Q126,210,100,166Q74,122,135.5,150Q197,178,197.5,134Q198,90,224,60Q250,30,275.5,62Q301,94,314.5,118.5Q328,143,348,153.5Q368,164,397.5,178Q427,192,395.5,221Q364,250,351,264.5Z" />
    </clipPath>
  </defs>
</svg>

Looks very nice, but I stumbled on two problems:

  1. As you can see the image used in this test is not quite well positioned within the visible part of the mask. Therefore I would like to know if it's possible to reposition it
  2. It's huge! Because I'm not very well versed with SVG, I couldn't resize it as the usual properties does nothing on the parent (.picture), in the SVG itself and, if applied to the image instead, it vanishes. Re-scale it with transform, works, though, but I highly doubt this is the right way to do it.

So, in summary, how could I mask any image, adjusting it within this mask without editing the images themselves (which would be the most desirable - a code that works for images instead of images that works for a code, if you know what I mean).

If, by any chance, any other mask can be used, would be even better. This shape was one of the best I could find but I have a few others to test too.

2 Answers2

1

First I want to know the size and the position of the path used as clipping path. For this I'm using the getBBox() method. This is what I get for your #blob:

height: 414.00213623046875
width: 361.4715881347656
x: 54.519683837890625
y: 45.48387145996094

I want to use clipPathUnits="objectBoundingBox" and in this case

This value indicates that all coordinates inside the element are relative to the bounding box of the element the clipping path is applied to. It means that the origin of the coordinate system is the top left corner of the object bounding box and the width and height of the object bounding box are considered to have a length of 1 unit value.

Read more about clipPathUnits

Since I want a bounding bow of 1/1 I would scale the path 1/361 = 0.0028 in x and 1/414 = 0.0024 in y (361 is the width of the path's bounding box and 414 is the height). But now I have another problem: the bounding box of the path used for clipping is begining at x=54 and y=45. So I need to translate back the path translate(-54,-45)

I'm using rounded values of the bounding box (see javascript). You may want to use the exact values.

Now you can size the image as you like, for example width="200" height="200" or you may choose a value like img{width:45vw; height:45vw}

div,svg{display:inline}

img,.visible{width:45vw; height:45vw}
<svg width="0" height="0">
  <defs>
  <path id="blob"  d="M351,264.5Q338,279,387.5,332.5Q437,386,400.5,396Q364,406,324,380.5Q284,355,267,420Q250,485,225.5,443Q201,401,158,418.5Q115,436,82,416Q49,396,112.5,335Q176,274,100,262Q24,250,75,230Q126,210,100,166Q74,122,135.5,150Q197,178,197.5,134Q198,90,224,60Q250,30,275.5,62Q301,94,314.5,118.5Q328,143,348,153.5Q368,164,397.5,178Q427,192,395.5,221Q364,250,351,264.5Z" />
    <clipPath id="myClip" clipPathUnits="objectBoundingBox">
      <use xlink:href="#blob" transform="scale(0.0028,0.0024) translate(-54,-45)"/>
    </clipPath>
  </defs>
</svg>


<div class="picture">
  <img src="https://i.postimg.cc/0Njq2C60/bartrix.png" alt="whatever" style="clip-path: url(#myClip)">
</div>

<svg viewBox="0 0 414 414" class="visible">
 <image xlink:href="https://i.postimg.cc/0Njq2C60/bartrix.png" width="414" height="414"/>
 <use xlink:href="#blob" transform="translate(-54,-45)" fill="none" stroke="gold" stroke-width="4" />
</svg>
enxaneta
  • 31,608
  • 5
  • 29
  • 42
  • I didn't test much further because it's weekend after all but I assume this `blob` refers to the ``, right? That solves the resizing problem - which I think was the culprit for the topic flagging. Now, although the inner positioning is MUCH better, it's still not quite perfect (you may agree Bart's head is more important than the background) so I quickly tried an `object-position: 15px 15px` on the` `to adjust and with this some of the curves became flat, losing the original aspect of the shape. What should I do then? Adjust first, then recalculate and adjust those properties? –  May 15 '21 at 22:20
  • I thought Bart is just an example image. If not you may need to change the path. To understand why I've edited my answer by adding an SVG element with both the image and the #blob path so that you can see. – enxaneta May 16 '21 at 09:49
  • Bart was indeed just an example image. As I said, I'm looking for a way to resize and reposition **any** image within **any** mask (this is one of the many I'm playing around with). If it's *really* impossible to have one single "plug and play" solution (one code to rule them all :P), by knowing the adjustment process, I can adjust others accordingly, even if by trial and error. But, if in the end, `clip-path` isn't the best approach and you have an alternative, I'm all ears. –  May 16 '21 at 15:47
0

You could play around with the transform property of the clipPath

eq: transform="translate(0, -20) scale(0.7, 0.6)"

Docs here

<div class="picture">
  <img src="https://i.postimg.cc/0Njq2C60/bartrix.png"
    alt="" style="clip-path: url(#myClip)">
</div>

<svg width="0" height="0">
  <defs>
    <clipPath id="myClip" transform="translate(0, -20) scale(0.7, 0.6)">
      <path id="blob" fill="none"
            d="M351,264.5Q338,279,387.5,332.5Q437,386,400.5,396Q364,406,324,380.5Q284,355,267,420Q250,485,225.5,443Q201,401,158,418.5Q115,436,82,416Q49,396,112.5,335Q176,274,100,262Q24,250,75,230Q126,210,100,166Q74,122,135.5,150Q197,178,197.5,134Q198,90,224,60Q250,30,275.5,62Q301,94,314.5,118.5Q328,143,348,153.5Q368,164,397.5,178Q427,192,395.5,221Q364,250,351,264.5Z" />
    </clipPath>
  </defs>
</svg>
Charles Lavalard
  • 2,061
  • 6
  • 26