Last active
January 12, 2026 22:13
-
-
Save Winterhuman/c03a892f131c17f2ace4a1c42e9de06f to your computer and use it in GitHub Desktop.
A script which finds the minimum PNG dimensions for a given aspect ratio and pixel count, creates a colour-cycling PPM file, and then converts it to PNG.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env -S unshare --mount --map-root-user /bin/sh | |
| # Licensed under the Zero-Clause BSD terms: https://opensource.org/license/0bsd | |
| # Requires: imagemagick & [sisyphus](https://gist.github.com/Winterhuman/21d7b148db40ff041f397b07a7aafb83) | |
| # | |
| # Argument 1: Number of pixels to fill, required | |
| # Argument 2: Height ratio, default 23 | |
| # Argument 3: Width ratio, default 5 | |
| set -Ceuf | |
| pstat() { | |
| printf "%b\033[1m%b\033[0;39m" "${2:-\033[1m\033[34m::\033[0;39m }" "$1" | |
| } | |
| pquit() { | |
| pstat "$1" "\033[1m\033[31m!!\033[0;39m " | |
| exit 1 | |
| } | |
| # Check if all arguments are valid | |
| fill="${1:?"$(pquit "No arguments given!\n")"}" | |
| if ! printf "%d" "$fill" >/dev/null 2>&1 || [ "$fill" -le 0 ]; then | |
| pquit "'$fill' is not a positive integer!\n"; fi | |
| pstat "Fill: $fill\n" | |
| hratio="${2:-"23"}" | |
| wratio="${3:-"5"}" | |
| if ! printf "%d" "$hratio" "$wratio" >/dev/null 2>&1 || | |
| [ "$hratio" -le 0 ] || [ "$wratio" -le 0 ]; then | |
| pquit "Aspect ratio values must be positive integers!\n"; fi | |
| # Calculate the optimal/minimal image dimensions for the given fill value | |
| calc_w() { | |
| ## '+ wratio - 1' yields a rounded up answer, instead of rounded down | |
| printf "%d\n" "$(( (("$1" * hratio) + wratio - 1 ) / wratio ))" | |
| } | |
| calc_h() { | |
| printf "%d\n" "$(( ( ("$1" * wratio) + hratio - 1 ) / hratio ))" | |
| } | |
| height="1" | |
| width="$(calc_w "$height")" | |
| bad="0" | |
| ## 'input + 1' is required to make this round up, since '$wratio' is in | |
| ## both the numerator and denominator (manual calculations verify this). | |
| ### '-1' is omitted from 'hratio + wratio' to handle '2:1' ratios | |
| good="$(( | |
| ( (fill + 1) * wratio + hratio + wratio ) / | |
| (hratio + wratio) | |
| ))" | |
| good="$(( "$(calc_h "$good")" + 2 ))" | |
| if [ "$good" -gt 1 ]; then | |
| while [ "$bad" -le "$(( good - 1 ))" ]; do | |
| if [ "$(( width * height ))" -le "$fill" ]; then | |
| bad="$(( height + 1 ))" | |
| else | |
| good="$height" | |
| fi | |
| height="$(( (bad + good) / 2 ))" | |
| width="$(calc_w "$height")" | |
| done | |
| fi | |
| height="$good" | |
| width="$(calc_w "$height")" | |
| blank="$(( (height * width) - fill ))" | |
| groups="$(( fill / 3 ))" | |
| remainofgroups="$(( fill % 3 ))" | |
| pstat "Image dimensions: $width x $height\n" | |
| pstat "Pixel fill: ${fill}px (${blank}px left)\n" | |
| # Setup a private tmpfs for this script to use, which is what 'unshare' is for. | |
| ## 'nr_inodes' must be >= to 'max number of files + 1' | |
| mount -t tmpfs -o nosuid,nodev,noexec,size=1G,nr_inodes=6 ppm2png /tmp/ || | |
| pquit "Failed to overmount '/tmp/'!\n" | |
| # Create the PPM file. | |
| ## Create the blank lines. | |
| ### This method is faster than: `printf "%*s" "$blank" | sed "s/ /0 0 0\n/g"` | |
| yes "0 0 0" | head --lines="$blank" >>/tmp/blank & | |
| ## Create the filled-in lines. | |
| ### `shuf` is the fastest method, followed by: | |
| ### `while :; do printf "%d\n" "$(( RANDOM % 7 ))"; done | head --lines="$groups"`. | |
| ### `while [ "$count" -gt 0 ]]; do ...; count="$(( count - 1 ))" done`. | |
| #### The `yes` method would re-use the same '$RANDOM' value repeatedly | |
| rand_fill() { | |
| ## `--head-count=` ignores numbers above the upper range value, aka. 6 | |
| shuf --input-range=0-6 --repeat | head --lines="$groups" | |
| } | |
| ### Replace the colour indexes with their RGB values. | |
| #### `[] ||` corrects for unclean divisions (e.g. 5 fill = 1 group + 2 remainder) | |
| { | |
| rand_fill | |
| [ "$remainofgroups" -lt 1 ] || shuf --input-range=0-6 --head-count=1 | |
| } | sed -e "s/^0$/0 255 179/" \ | |
| -e "s/^1$/33 219 155/" \ | |
| -e "s/^2$/43 185 132/" \ | |
| -e "s/^3$/46 151 110/" \ | |
| -e "s/^4$/45 119 88/" \ | |
| -e "s/^5$/41 89 67/" \ | |
| -e "s/^6$/34 60 48/" >>/tmp/1 & | |
| { | |
| rand_fill | |
| [ "$remainofgroups" -ne 2 ] || shuf --input-range=0-6 --head-count=1 | |
| } | sed -e "s/^0$/255 185 0/" \ | |
| -e "s/^1$/219 160 26/" \ | |
| -e "s/^2$/185 137 34/" \ | |
| -e "s/^3$/151 113 37/" \ | |
| -e "s/^4$/119 91 37/" \ | |
| -e "s/^5$/89 69 35/" \ | |
| -e "s/^6$/60 49 30/" >>/tmp/2 & | |
| rand_fill | sed \ | |
| -e "s/^0$/255 47 120/" \ | |
| -e "s/^1$/220 48 105/" \ | |
| -e "s/^2$/186 48 91/" \ | |
| -e "s/^3$/153 46 77/" \ | |
| -e "s/^4$/122 42 64/" \ | |
| -e "s/^5$/91 37 50/" \ | |
| -e "s/^6$/62 31 38/" >>/tmp/3 & | |
| wait | |
| ## Combine the PPM file parts | |
| ppm="/tmp/img.ppm" | |
| { | |
| ## This reads the HEAD heredoc | |
| cat | |
| ## `head` removes any empty line(s) for when '$fill' isn't cleanly | |
| ## divisible by 3 | |
| paste --delimiters="\n" /tmp/1 /tmp/2 /tmp/3 | head --lines="$fill" | |
| cat /tmp/blank | |
| } <<-HEAD >"$ppm" | |
| P3 | |
| $width $height | |
| 255 | |
| HEAD | |
| ## Save some space, just in case '$tmp_img' would bring it over the size limit | |
| rm -- /tmp/1 /tmp/2 /tmp/3 /tmp/blank >/dev/null 2>&1 ||: | |
| # Convert the PPM file to PNG | |
| tmp_img="/tmp/tmp.png" | |
| magick "$ppm" -transparent "#000" "$tmp_img" || | |
| pquit "Failed to create '$tmp_img'!\n" | |
| # Move any existing output to a new '.old' path | |
| mv_exist() { | |
| [ -f "$1" ] || return 0 | |
| mv -- "$1" "$1.old" | |
| } | |
| mv_exist "header.png" | |
| mv_exist "header.webp" | |
| ## Optimise PNG with 'sisyphus' | |
| pstat "Optimising with Sisyphus...\n" | |
| ## '$tmp_img' exists outside Sisyphus's private tmpfs, meaning it can't see it. | |
| ## So, instead of copying '$tmp_img' somewhere, just give it a file descriptor | |
| exec 3<"$tmp_img" | |
| sisyphus --max-procs 24 --all-oxi true --results 16 /proc/self/fd/3 "header" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment