Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for png/jpg source images #60

Closed
brodysmith1 opened this issue Jun 14, 2023 · 5 comments
Closed

Support for png/jpg source images #60

brodysmith1 opened this issue Jun 14, 2023 · 5 comments
Assignees

Comments

@brodysmith1
Copy link

Hey, really nice tool! Happy to discover this after dealing with spritezero's (via mapnik) Node versioning issues.

It would be cool to be able to include jpg or png images in the source folder and to have them map across to the sprite sheet too.

Cheers and well done!

@flother
Copy link
Owner

flother commented Aug 1, 2023

Thanks for the kind words, I appreciate it.

Supporting PNGs would be relatively easy, since that's the format used both internally and for outputting sprites. JPEG would be a bit more work but I'm sure I could rely on an external crate for loading JPEGs and converting them to PNGs.

The problem with supporting raster formats like JPEG and PNG is that they won't work well with the multiple pixel ratios needed for modern vector maps. You usually need at least 1x and 2x (see the style spec sprite docs) and so the icons would need to be scaled up, causing pixelisation. Much better to use a vector format like SVG wherever possible.

Do you have a real-world example of where this would be useful?

@brodysmith1
Copy link
Author

Interesting, thanks for unpacking the technicals a little for me.

My use-case was showing the positions of multiple military groups on a map. I wanted to use a symbol layer where the icons were the flags of the group. These flags were fairly complex and svg's weren't available for them. Possibly a niche, but I imagine people having similar needs out there.

Only supporting PNG would have been fine, as it's easy enough for a dev to convert jpg->png if need be.

(Note: I ended up using custom html Markers which was fine but a little pesky.)

Thanks!

@flother
Copy link
Owner

flother commented Sep 28, 2023

I've been thinking about this a bit more recently, and I realised that actually — with a little sleight of hand — Spreet does already support PNG, JPEG, and GIF input.

The sleight of hand is that SVG supports embedded images, and so all you need to do to include a PNG in your spritesheet is to create a thin SVG wrapper around the PNG. Let's say you have a flag image named flag.png. Create a flag.svg file in the same directory with this content:

<svg xmlns="http://www.w3.org/2000/svg">
  <image href="./flag.png" />
</svg>

The SVG is doing nothing more than referencing the local PNG image. By default, resvg (the library Spreet relies on for SVG support) will create an SVG that is the same width and height as the embedded PNG. Now let's say you have your flags (PNGs and their SVG wrappers) in a sub-directory named flags, and you want to create a sprite sheet named flags-sheet.png. Run Spreet like this:

spreet flags flags-sheet

And, hey presto, you have a spritesheet built from your raster images. (You can of course mix-and-match "real" vector SVGs and SVGs-with-embedded-PNGs together in one spritesheet.)

One further goodie is that resvg allows you to resize your PNGs too. If you have a PNG that's 400x400px but you want to resize it to 32x32px for your spritesheet, try something like this:

<svg xmlns="http://www.w3.org/2000/svg">
  <image href="./flag.png" width="32" height="32"/>
</svg>

Given that a) vector input gives the best results, b) there doesn't seem to be any demand for raster input in the original spritezero project (in fact they moved from raster to vector input in 2015 with v2.0.0), c) my concerns about scaling above, and d) support via SVG's <image> element, I'm going to close this issue. But I'll make sure to add a test for the SVG wrapper technique first.

@flother flother self-assigned this Sep 28, 2023
flother added a commit that referenced this issue Oct 1, 2023
When rendering an SVG, without setting the resource_dir option, any
URLs in the SVG are resolved relative to the current working directory
rather than the SVG itself. The SVG spec expects it to be the directory
that contains the SVG file.

Discovered while writing a test to check that PNG input is supported
according to the method mentioned in #60.
@flother
Copy link
Owner

flother commented Oct 1, 2023

I wrote the test and discovered a bug that caused the URLs referenced in <image> elements to be resolved relative to the current working directory rather than relative to the SVG. Oops. That's fixed in d444fc1, so the method works properly on master. You can of course also embed the PNG as a base64-encoded image too (which works in the released version):

<svg xmlns="http://www.w3.org/2000/svg">
  <image>data:image/png;base64,...</image>
</svg>

I hope this helps you with your map!

@flother flother closed this as completed Oct 1, 2023
@brodysmith1
Copy link
Author

Thanks Matt, great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants