Mike's Notes

Mike Mol's blog. Discussing why's, how's and random technical musings.

View My GitHub Profile

13 February 2018

Asset regeneration script

by Mike Mol

So, in the interest of trying to be lazy (really!), I wrote a script to automate the generation of graphic assets from the dot source files. It does a few things for me:

Workflow

An illustration of the script flow.

Here’s how it works:

  1. Find all dot files in my assets folder.
  2. For each dot file
    1. For each format (I specify SVG and PNG)
      1. Check to see if the dot file is newer than the corresponding PNG or SVG.
        1. If it’s newer:
          1. Commit the dot file to the git repository, in case the work-in-progress hasn’t been committed already.
          2. Render the asset
          3. If the asset is a PNG:
            1. Force the PNG into indexed RGBA mode using pngquant; for many images, this grossly reduces the PNG file size.
            2. Run pngcrush on the indexed PNG, trying all strategies that use the maximum Zlib compression. For PNG images which pngquant didn’t make a significant file size dent in, this will.
          4. Stage the asset for commit.
    2. If there are changes staged for commit, commit them.

Source

#!/bin/bash
fmts="svg png"
banned_branches="master regen-assets"

current_branch=$(git branch -l | grep -e '^*' | cut -d' ' -f2)

for b in ${banned_branches} ; do
    if [[ "${current_branch}" == "${b}" ]]; then
        echo "Not regenerating assets. ${b} is a protected branch."
        exit 1
    fi
done

git_status=$(git status)

if echo "${git_status}" | grep "Changes to be committed" > /dev/null ; then
    echo "Not regenerating assets. You have staged, uncommitted changes."
    exit 1
fi

while IFS= read -r -d '' dotfile ; do
    assetdir=$(dirname "${dotfile}")
    assetname=$(basename "${assetdir}")
    echo "Generating renders for $(basename ${assetdir})"
    for fmt in ${fmts} ; do
        dstfile="${assetdir}/${assetname}.${fmt}"
        if [[ "${dotfile}" -nt "${dstfile}" ]] ; then
            echo "${dotfile} has been updated. Committing $dotfile"
            git commit --quiet -m "Caught uncommited changes to ${assetname}. Preserving separately." "${dotfile}"
            echo "Building ${fmt} for $(basename ${assetdir})"
            dot "-T${fmt}" -o "${assetdir}/${assetname}.${fmt}" "${dotfile}"
            if [[ $fmt == "png" ]] ; then
                orig_size=$(stat -c %s "${dstfile}")
                pngquant --force --ext .png -Q 100-100 "${dstfile}"
                quant_size=$(stat -c %s "${dstfile}")
                pngcrush -ow -brute -l 9 -q "${dstfile}"
                crushed_size=$(stat -c %s "${dstfile}")
                echo "Original: ${orig_size}b. Quantized: ${quant_size}b. Crushed: ${crushed_size}"
            fi
            echo "Adding ${dstfile}"
            git add "${dstfile}"
        fi
        echo "checking for changes"
        if git status | grep "Changes to be committed" > /dev/null ; then
            echo "Committing changes for ${assetname}"
            git commit --quiet -m "Preserving binary renders for ${assetname}"
        fi
    done
done < <(find assets -type f -name '*.dot' -print0)

Pretty handy. We’ll have to see how automating munging of my git repo works out, but I think there’s going to be more value in automating it than is lost digging through some strange git history. At least the visual renders will accompany the various versions of the dotfiles, so understanding the impacts of changes will be easier, and I’ll have snapshots of works-in-progress to go back to illustrate _why__ I took one approach or another while demonstrating more about Dot and Graphviz.

tags: