<div id="comparator">
<img src="https://meyerweb.com/eric/thoughts/wp-content/uploads/wikipedia-home.png" alt="">
<img src="https://meyerweb.com/eric/thoughts/wp-content/uploads/wikipedia-home.png" alt="">
</div>
<svg xmlns='http://www.w3.org/2000/svg'>
<filter id='pixelate' x='0' y='0'>
<!-- <feComposite result="box-blur"/> -->
<feConvolveMatrix order="3" kernelMatrix="1 1 1 1 1 1 1 1 1" result="box-blur" />
<!-- generate tiling pattern -->
<feFlood x='3' y='3' height='1' width='1'/>
<feComposite width='3' height='3'/>
<feTile result='tiles'/>
<!-- apply tiling pattern -->
<feComposite in='box-blur' operator='in'/>
<!-- expand pixels to (2r + 1) large -->
<feMorphology operator='dilate' radius='1'/>
</filter>
</svg>
The feConvolveMatrix is only needed if you want input pixel averaging rather than point sampling. (It automatically divides by the sum of taps.)Note that:
- I'm told that feConvolveMatrix becomes slower for higher orders. For composite input sizes (like powers of 2), you can instead combine multiple passes of sampling with increasing amounts of zero-spacing between taps (the other meaning of dilation LMAO). I don't know if browsers will optimize the filter to skip processing input data, to make the filtering runtime O(log n) rather than O(n^2).
- I don't know any way to make <feMorphology operator='dilate'> expand point-sampled images to even pixel sizes. You may need to start with a different source point-sampling filter.