In my quest to reduce the bandwidth used by my blog entries, I have reduced the user-pic from 42 KB to 6 KB using inline SVG.
One of the things I wanted to do was have a border on the image that was neither rectangular nor elliptical but instead some approximation to a superellipse.
The significance of rectangles and ellipses is they are shapes you can
do easily in CSS by setting border-radius
but having no actual
border, since CSS borders have the side effect of clipping the
content of the box.
The other usual way to do non-rectangular images it to use a PNG file, so you can use the alpha channel to make the part of the image outside the desired shape transparent (since JPEG does not have an alpha channel). The downside with using this with a photograph is that PNG does not compress photos as well as JPEG does.
My solution is to use SVG to apply a clipping path to the JPEG image, using something like this:
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%" height="100%"
viewBox="-1 -1 2 2">
<defs>
<clipPath id="s">
<path d="M1,0 C1,1 1,1 0,1 S-1,1 -1,0 -1,-1 0,-1 1,-1 1,0Z"/>
</clipPath>
</defs>
<image x="-1" y="-1" width="2" height="2" clip-path="url(#s)"
xlink:href="byantonia-s96w.jpeg"/>
</svg>
The gist of this is that the image has a clip path set to the one in
the defs
section. This uses a cubic Bézier (the C
command in
the path
) with both its control points at the corners of the square (1, 1)
to represent on quarter, then three S
commands to repeat this for
the other three quarters. I can’t be bothered to work out how much
this is or isn’t a match for a genuine superellipse: it looks good
enough for my purposes.
With modern browsers this can be embedded directly in the HTML of the
page, which is convenient because it means I can use Django‘s
static
tag to get the URL of the image file correct. It can also be sized
using CSS like any other content. Very civilized.
The right-sized JPEG image is
5.6 KB (compared with 42.3 KB for the PNG). The svg
fragment is
slightly longer than the img
tag it replaces, but only by a
few hundred bytes. Overall this shaves a little more than 36 KB
from the first uncached view of my blog pages.