Giter Site home page Giter Site logo

spreet's Introduction

Spreet: create spritesheets from SVGs

Spreet is a command-line tool that creates a spritesheet (aka texture atlas) from a directory of SVG images. You'll need this when you create MapLibre or Mapbox vector web maps, where cartographic stylesheets require that icons be loaded from a spritesheet.

Compared to other tools for creating spritesheets from SVGs, Spreet:

  • outputs smaller spritesheets (both fewer pixels and fewer bytes)
  • is a self-contained ~2.2 MB binary
  • is faster

Spreet (also spreit, spret, sprit) is the Scots word for a sprite, the fairy-like creature from Western folklore.

CI status Latest release

Table of contents

Installation

You can install Spreet using Homebrew, cargo install, by downloading pre-built binaries, or by building from source.

Homebrew

If you use Homebrew on MacOS or Linux you can install Spreet from the command-line:

brew install flother/taps/spreet

(You can review the code run by the formula before you install.)

Installing from crates.io (cargo install)

Rust's cargo install command lets you install a binary crate locally. You can install the latest published version of Spreet with:

cargo install spreet

Download pre-built binaries

Pre-built binaries are provided for MacOS, Linux, and Windows. The MacOS and Linux binaries are built for both Intel and ARM CPUs. Visit the releases page to download the latest version of Spreet.

Build from source

You'll need a recent version of the Rust toolchain (try Rustup if you don't have it already). With that, you can check out this repository:

git clone https://github.com/flother/spreet
cd spreet

And then build a release:

cargo build --release

Once finished, the built binary will be available as ./target/release/spreet.

Tutorial

When you're making your own style for a vector map, you'll have icons that you want to appear on top of the map. Symbols for roads or icons for hospitals and schools — that sort of thing. You'll have a directory of SVGs (like the icons directory in the osm-bright-gl-style) and you'll want to convert them into a single raster image (like the spritesheet from osm-bright-gl-style).

Let's say you have a directory of SVGs named icons and you want to create a spritesheet named my_style.png. Run Spreet like this:

spreet icons my_style

Spreet will also create an index file named my_style.json that contains a description of the dimensions and location of each image contained in the spritesheet.

If you want to create a "retina" version of the spritesheet named [email protected], use the --retina option:

spreet --retina icons my_style@2x

You might have multiple copies of the same icon — for example, you might use the same "open book" icon for both libraries (library.svg) and bookshops (bookshop.svg). If you pass the --unique option, Spreet will include only the icon once in the spritesheet, but reference it twice from the index file. This helps reduce the size of your spritesheet.

spreet --retina --unique icons my_style@2x

By default the JSON index file is pretty-printed, but you can minify it with the --minify-index-file option:

spreet --retina --unique --minify-index-file icons my_style@2x

When you create a spritesheet for your production environment, use --unique --minify-index-file for best results.

Command-line usage

$ spreet --help
Create a spritesheet from a set of SVG images

Usage: spreet [OPTIONS] <INPUT> <OUTPUT>

Arguments:
  <INPUT>   A directory of SVGs to include in the spritesheet
  <OUTPUT>  Name of the file in which to save the spritesheet

Options:
  -r, --ratio <RATIO>      Set the output pixel ratio [default: 1]
      --retina             Set the pixel ratio to 2 (equivalent to `--ratio=2`)
      --unique             Store only unique images in the spritesheet, and map them to multiple names
      --recursive          Include images in sub-directories
  -m, --minify-index-file  Remove whitespace from the JSON index file
      --sdf                Output a spritesheet using a signed distance field for each sprite
  -h, --help               Print help
  -V, --version            Print version

Using Spreet as a Rust library

The main purpose of Spreet is to be command-line tool, but you can also use it as a library in your own Rust code. To add Spreet as a dependency, include this in your Cargo.toml:

spreet = { version = "0.11.0", default-features = false }

To learn how to build your spritesheets programmatically, see the Spreet crate docs on docs.rs and have a look at the spritesheet tests.

Benchmarks

To compare the output from spritezero and Spreet, benchmarks are run against SVG sprite sets from four diverse map styles: osm-bright-gl-style, openstreetmap-americana, mapbox-gl-styles (basic), and mapbox-gl-whaam-style. Unique, retina spritesheets are output (--unique --retina), and Spreet also uses --minify-index-file (spritezero doesn't have that option).

Spritesheet size (total pixels)

Map style Spritezero pixels Spreet pixels Change
osm-bright-gl-style 208,810 130,048 -38%
openstreetmap-americana 577,548 389,640 -33%
mapbox-gl-styles (basic) 271,488 258,064 -5%
mapbox-gl-whaam-style] 90,944 59,136 -35%

Spritesheet file size (bytes)

Map style Spritezero file size Spreet file size Change
osm-bright-gl-style 43,860 24,588 -44%
openstreetmap-americana 140,401 78,617 -44%
mapbox-gl-styles (basic) 76,383 30,771 -60%
mapbox-gl-whaam-style 17,342 5,037 -71%

Index file size (bytes)

Map style Spritezero file size Spreet file size Change
osm-bright-gl-style 10,695 6,957 -35%
openstreetmap-americana 20,142 13,574 -33%
mapbox-gl-styles (basic) 17,013 11,101 -35%
mapbox-gl-whaam-style 553 372 -33%

spreet's People

Contributors

dependabot[bot] avatar derzade avatar flother avatar nyurik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

spreet's Issues

File Input or SymLinks

Thanks for making this library!
I previously used Spritezero in Javascript. Not the Spritezero-CLI version.

Here I could input a list of files instead of pointing to a folder.
Would it be possible to implement something like this?

I probably have a weird use case, where I can upload to 3 different folders, for example:
/sprites/public
/sprites/version-a
/sprites/version-a/part-b

where I want to generate a spritesheet for part-b, but including the sprites in public and version-a.
But not including /sprites/version-a/part-a.

I tried to use Symbolic Links to create a new directory first /sprites/temp then create symbolic links to all .svgs.
They work in other programs correctly.

But this gives me the error:

Error: cannot make a valid sprite name from "/sprites/temp/new-sprite.svg"

When i copy the files to the same folder, so no symlinks, they work correctly.

Add support for SDF sprites

Really cool project!

I'm currently looking for a solution to converts SVG files to SDF sprites. In MapLibre, this kind of sprites allow to change the color of the icons in the style.

Here is a PNG storing SDF icons:
https://tiles.baremaps.com/sprites/osm/[email protected]

The corresponding sprite definition file:
https://tiles.baremaps.com/sprites/osm/[email protected]

And a demonstration:
https://demo.baremaps.com/#14.59/46.52182/6.63022

Spritezero works well for small SVG icons, but I'm struggling to convert more complex SVG files to SDF sprites (e.g. forest pattern). Is SDF in your roadmap?

Support for optional properties (content, stretchX & stretchY)

I don't think there is currently a way to set the content, stretchX and stretchY optional properties in the inext file, correct? (take a look at the mapbox docs)

Maybe these values could be read from data attributes of the SVG root element or an optional json file with the same name as the svg or another JSON as another input, which includes optional properties for all sprites.

Thoughts?

Support for png/jpg source images

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!

Convert all `.unwrap()` and similar panics to proper errors

Currently there are many .unwrap() calls that would cause a lib user to have an unexpected crash. I think actix web framework will handle when a URL path handler would crash, but clearly it would be better to have proper error handling instead.

I propose to add thiserror-implementing Error enums instead. Would that be ok?

Unable to parallelize pixmap loading

with the recent release, it is no longer possible to pre-process each SVG pixmap independently, and merge the results. I was doing it all in parallel using Tokio, and I think there is a significant enough benefit, esp for a high-load scenario, to offer rapid sprite generation.

How could we make this a bit more optimized? Thx!

Crates.io release

Thanks a bunch for making this project! It would be great if it were on crates.io as well for ease of installation on non-macOS platforms (like my CI/CD pipelines).

Add a CLI argument to allow sprite index file to be minified

When a sprite index file is output by Spreet, it's pretty-printed. There should be an option to allow it to be output without any optional whitespace. For example, this should be the default output:

{
  "poi": {
    "width": 32,
    "height": 32,
    "x": 0,
    "y": 0,
    "pixelRatio": 1
  }
}

But when the --minify-index-file argument is passed it should be output as:

{"poi":{"width":32,"height":32,"x":0,"y":0,"pixelRatio":1}}

The SDF icons seem to lack antialiasing

In the following example, the icons generated with spritezero seem to apply some antialiasing whereas the spreet one does not:

spritezero

spreet

The svg file used to generate the veterinary icon is located here:

https://github.com/apache/incubator-baremaps/blob/main/basemap/assets/icons/veterinary.svg

The following README contains instructions to generate a sprite that contains most openstreetmap-carto icons:

https://github.com/apache/incubator-baremaps/blob/main/basemap/assets/README.md

All the icons seem to be affected by this issue.

Padding support

First off, excellent library, it has worked really well for us! One small need we have is actually applying a 1-2px padding around each icon. While this can be done at the SVG asset level we found it is a little easier to blanket apply it at the time of spritesheet generation. Current thought is a --spacing=1 flag or similar that would apply padding around each asset for the defined value.

Include sub directories

I have a the following directory structure:

input
├── category1
│   ├── foo.svg
│   └── bar.svg
├── baz.svg
└── category2
    ├── foo.svg
    └── bar.svg

When calling spreet i only get a spritesheet including baz.svg. Instead I would like to include all files with the following ids: category1/foo, category1/bar, baz, category2/foo, category2/bar.

As far as I can tell this is not possible at the moment. Would you be open to a PR which adds this functionality?
If yes, should this this be disabled by default and behind an option (--deep or something)?

Add `--unique` command-line argument

It's not mentioned in the README but spritezero-cli has had a --unique option since v1.1.0 in June 2016, added in mapbox/spritezero-cli#10. When given, it only includes unique images in the spritesheet but maps them to multiple names in the index file. For Spreet to be compatible with spritezero-cli it should have the same option.

For two sprites to be considered unique, Spritezero actually compares the text of the SVG files (see 00dd132b), but it would be better to compare the rendered raster sprites. That would take care of any differences in e.g. whitespace between the two original SVGs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.