spreet icon indicating copy to clipboard operation
spreet copied to clipboard

Scaled SDF sprites aren't generated correctly

Open dschep opened this issue 10 months ago • 3 comments

I recently discovered that spreet isn't correctly generating scaled SDF sprites. Namely, the radius within which the signed distance from the sprite is computed should be scaled too.

1x sheet. everything looks good: image

2x sheet. sprite-one and spreet look wrong but the change from my fork of sprite-one looks correct: image

My repo containing a demo reproducing this issue is: https://github.com/dschep-bug-repos/sdf-2x-generation/

dschep avatar Feb 19 '25 19:02 dschep

Interesting... So the SDF Glyph Renderer code just takes the data as-is. It deals with pixels in a bitmap.

https://github.com/stadiamaps/sdf_font_tools/blob/1cd94bb413f350dbd4869ce1df852ff23b7b044f/sdf_glyph_renderer/src/core.rs#L98

I can see that the buffer is a fixed value in pixels and not adjusted for the scale:

https://github.com/flother/spreet/blob/02d3e76aec80f8e36c5a2c837156819f13b0ebe3/src/sprite/mod.rs#L89C24-L90C1

I'm having a hard time grokking the JS implementation is spritezero, but it seems like the same bug would be present there too?

https://github.com/elastic/spritezero/blob/3b89dc0fef2acbf9db1e77a753a68b02f74939a8/index.js#L144

ianthetechie avatar Feb 20 '25 03:02 ianthetechie

This could well be the same underlying issue as reported in #80. I keep meaning to find the time to look into this — I want to compare Spreet's @2x sprites to those generated by Spritezero, and see if it's simply a case of scaling the buffer. It's on my to-do list now, but I'd also welcome a PR

flother avatar Mar 01 '25 16:03 flother

I don't think it's related. The sprite that spreet generates does have the "blurring". It's just that the blurring the wrong size for @2x. I'm not sure what the reporter of #80 is doing wrong. This what spreet generates:

dschep avatar Mar 05 '25 14:03 dschep

I think I've fixed this in #96. The problem stemmed from both buffer and sampling radius being set in stone (3px and 8px respectively). Changing both to scale with the pixel ratio gives us this:

SDF sprites

This looks correct to me, but I'm learning about the details of SDF sprites on the fly, so if anyone wants to give this a once-over and check my working, please do!

My repo containing a demo reproducing this issue is: https://github.com/dschep-bug-repos/sdf-2x-generation/

@dschep Thanks for providing that repo, it was very useful for testing this out quickly. Really appreciate it.

I'm having a hard time grokking the JS implementation is spritezero, but it seems like the same bug would be present there too?

@ianthetechie I struggle to get spritezero running on my machine these days, so I haven't tested it (but probably should). But my guess is that it does have the same bug. Has anyone tried it?

flother avatar Sep 10 '25 22:09 flother

Awesome! That looks right, it's the same approach I took in sprite-one AFACT

dschep avatar Sep 11 '25 17:09 dschep

I've tested this on a handful of other sprites and I'm happy that this is working as expected now. One last thing I wanted to do was see what Spritezero did with retina SDF sprites, thinking that this is as close as we get to a reference implementation. But of course the OG Spritezero has never supported SDF sprites — it was only Elastic's fork that included SDF support.

After faffing with Docker for a while I managed to get Elastic's fork running, and I could test its retina SDF output. Turns out the latest release has a bug that causes it to generate unusable SDF sprites at 2x.

Example of Spritezero's flawed retina SDF sprites

I took a look at the repo, and while the bug has been fixed, it was never actually included in a release before the project was archived. That was the end of that rabbit hole, with the answer that Spritezero isn't a useful source for understanding SDF sprites.

It feels like SDF is such a niche feature of web vector maps that there's little bug-free support for them. It's nice to think that once this is merged and released, Spreet should have full support.

flother avatar Sep 14 '25 12:09 flother

Nice work! Sorry for the late reply; I haven't even tried to get spritezero running in years, so I'd probably have done the same thing 🤷

ianthetechie avatar Sep 15 '25 02:09 ianthetechie

@ianthetechie I forget to mention, but you were right to say that the same bug is present in Spritezero. You can see in the image above that it has the same anaemic halo in the 2x sprite. So it's doubly buggy 😉

flother avatar Sep 15 '25 13:09 flother