Skip to content

Instantly share code, notes, and snippets.

@jemc
Created November 14, 2024 02:58
Show Gist options
  • Save jemc/99e70b18d35b2ea9639fa1e9123aae34 to your computer and use it in GitHub Desktop.
Save jemc/99e70b18d35b2ea9639fa1e9123aae34 to your computer and use it in GitHub Desktop.
Export BMFont definitions from Aseprite slices
#!/usr/bin/env bash
set -e
# Given an Aseprite file containing pixel art font characters, with an
# Aseprite slice marking each character, export it as a .png file alongside an
# output BMFont .fnt file defining a font composed of those characters.
#
# Use environment variables to specify options, and pass the input Aseprite
# file itself as the only CLI argument.
#
# If you have an Aseprite file containing multiple fonts, you can export them
# one by one by specifying a `slice_prefix` to filter the slices by.
#
# If a `face` name is not specified, the font will be named based on the
# input Aseprite filename (and the `slice_prefix` if given).
#
# If an `out` path is not specified, the .fnt file will be saved alongside the
# input Aseprite file, with the same name (with added `slice_prefix` if given).
#
# The `.png` is always exported alongside the aseprite file with the same name
# (only the file extension changes).
#
# Information about the process is logged to stderr.
# The `.fnt` file is in a human-editable format, allowing for additional tweaks.
# The content of the `.fnt` file is also logged to stderr for visibility.
in="${in:-$1}"
if [ -z "$in" ]; then
echo "Usage: env [out=''] [face=''] [slice_prefix=''] $0 /path/to/input.aseprite" >&2
exit 1
fi
slice_prefix="${slice_prefix:-}"
face="${face:-${slice_prefix}$(basename "$in" .aseprite)}"
json_file="$(mktemp --suffix .json)"
png_file="$(dirname "$in")/$(basename "$in" .aseprite).png"
fnt_file="${out:-$(dirname "$in")/${slice_prefix}$(basename "$in" .aseprite).fnt}"
echo "Exporting $in file as png" > /dev/stderr
aseprite --batch "$in" --save-as "$png_file"
echo "Extracting slice data" > /dev/stderr
aseprite --batch --data "$json_file" --list-slices "$in"
line_height=$(cat "$json_file" | jq '[.meta.slices[].keys[0].bounds.h] | max + 1')
base_height=$(cat "$json_file" | jq '[.meta.slices[].keys[0].bounds.h] | min')
png_width=$(cat "$json_file" | jq ".meta.size.w")
png_height=$(cat "$json_file" | jq ".meta.size.h")
echo "Writing font data to ${fnt_file}" > /dev/stderr
echo > /dev/stderr
echo "info face=\"${face}\" size=${base_height} bold=0 italic=0 charset=\"\" unicode=0 stretchH=100 smooth=0 aa=1 padding=0,0,0,0 spacing=0,0 outline=0" | tee /dev/stderr > "$fnt_file"
echo "common lineHeight=${line_height} base=${base_height} scaleW=${png_width} scaleH=${png_height} pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0" | tee /dev/stderr >> "$fnt_file"
echo "page id=0 ${png_file}" | tee /dev/stderr >> "$fnt_file"
cat "$json_file" | jq --arg slice_prefix "$slice_prefix" -r '.meta.slices[] | select(.name | startswith($slice_prefix)) | "char id=\(.name[($slice_prefix | length):] | explode | .[-1]) x=\(.keys[0].bounds.x) y=\(.keys[0].bounds.y) width=\(.keys[0].bounds.w) height=\(.keys[0].bounds.h) xoffset=0 yoffset=0 xadvance=\(.keys[0].bounds.w) page=0 chnl=15"' | tee /dev/stderr >> "$fnt_file"
echo > /dev/stderr
echo "output fnt: ${fnt_file}" > /dev/stderr
echo "output png: ${png_file}" > /dev/stderr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment