flother / spreet

Create a spritesheet from a set of SVG images
MIT License
94 stars 7 forks source link
cartography cli mapbox-gl-js maplibre maplibre-gl-js rust-lang

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:

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 my_style@2x.png, 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%