Skip to content

Instantly share code, notes, and snippets.

@RexYuan
Last active December 23, 2025 23:37
Show Gist options
  • Select an option

  • Save RexYuan/3147ffa0bb84766d1c6253781ffa6660 to your computer and use it in GitHub Desktop.

Select an option

Save RexYuan/3147ffa0bb84766d1c6253781ffa6660 to your computer and use it in GitHub Desktop.
Upscale an image for print at a specified physical size and DPI using Real-ESRGAN for AI upscaling.
#!/usr/bin/env zsh
#
# to-dpi.zsh
#
# Upscale an image for print at a specified physical size and DPI
# using Real-ESRGAN for AI upscaling.
#
# Notes: This script was vibe-coded but checked in-head by me.
#
# Strategy:
# - Compute required pixel dimensions from mm and DPI
# - Compute total required linear scale
# - Perform multi-pass Real-ESRGAN upscaling (>=2x only)
# - REQUIRE Real-ESRGAN to produce an output file (abort if not)
# - Perform final Lanczos resize to exact target
# - Write DPI metadata (no resampling)
#
# Usage:
# [DEBUG=1] ./to-dpi.zsh <image> <dpi> <widthxheight_mm> [--dry-run]
#
# Examples:
# ./to-dpi.zsh input.png 300 416x578
# DEBUG=1 ./to-dpi.zsh input.tiff 150 1000x1000
#
set -o errexit
set -o pipefail
# -------------------------
# Resolve script directory
# -------------------------
SCRIPT_DIR="${0:A:h}"
REALESRGAN_BIN="${SCRIPT_DIR}/realesrgan-ncnn-vulkan"
# -------------------------
# Argument parsing
# -------------------------
if (( $# < 3 || $# > 4 )); then
echo "usage: [DEBUG=1] to-dpi.zsh <image> <dpi> <widthxheight_mm> [--dry-run]"
exit 1
fi
input="$1"
dpi="$2"
size_mm="$3"
mode="$4"
DRY_RUN=0
[[ "$mode" == "--dry-run" ]] && DRY_RUN=1
[[ -n "$mode" && "$mode" != "--dry-run" ]] && {
echo "to-dpi: unknown option '$mode'"
exit 1
}
# -------------------------
# Validation
# -------------------------
[[ ! -f "$input" ]] && { echo "to-dpi: '$input' not found"; exit 1 }
[[ ! "$dpi" =~ '^[0-9]+$' || "$dpi" -le 0 ]] && {
echo "to-dpi: invalid dpi '$dpi'"
exit 1
}
[[ ! "$size_mm" =~ '^[0-9]+x[0-9]+$' ]] && {
echo "to-dpi: invalid size '$size_mm' (expected WIDTHxHEIGHT in mm)"
exit 1
}
command -v magick >/dev/null || {
echo "to-dpi: ImageMagick (magick) not found"
exit 1
}
[[ ! -x "$REALESRGAN_BIN" ]] && {
echo "to-dpi: Real-ESRGAN binary not found at:"
echo " $REALESRGAN_BIN"
exit 1
}
# -------------------------
# Parse size
# -------------------------
w_mm="${size_mm%x*}"
h_mm="${size_mm#*x}"
# -------------------------
# Target pixels
# -------------------------
tgt_w=$(python3 - <<EOF
import math
print(math.ceil(($w_mm / 25.4) * $dpi))
EOF
)
tgt_h=$(python3 - <<EOF
import math
print(math.ceil(($h_mm / 25.4) * $dpi))
EOF
)
# -------------------------
# Source pixels
# -------------------------
read src_w src_h <<<"$(magick identify -format '%w %h' "$input")"
required_scale=$(python3 - <<EOF
print(max($tgt_w / $src_w, $tgt_h / $src_h))
EOF
)
echo "Math:"
printf " dpi = %d\n" "$dpi"
printf " target_px = %dx%d\n" "$tgt_w" "$tgt_h"
printf " required_scale = %.2fx\n" "$required_scale"
(( $(echo "$required_scale > 32" | bc -l) )) && {
echo "to-dpi: required scale too large (${required_scale}x)"
exit 1
}
# -------------------------
# Scaling loop
# -------------------------
cur="$input"
cur_w="$src_w"
cur_h="$src_h"
remaining_scale="$required_scale"
base="${input%.*}"
pass=1
while (( $(echo "$remaining_scale >= 2.0" | bc -l) )); do
ai_scale=$(python3 - <<EOF
import math
print(min(4, int(math.floor($remaining_scale))))
EOF
)
(( ai_scale < 2 )) && break
printf "\nPass %d (Real-ESRGAN):\n" "$pass"
printf " ai_scale = %dx\n" "$ai_scale"
printf " before = %dx%d\n" "$cur_w" "$cur_h"
tmp="${base}__up${pass}.png"
if (( ! DRY_RUN )); then
if [[ -n "$DEBUG" ]]; then
"$REALESRGAN_BIN" -i "$cur" -o "$tmp" \
-n realesr-animevideov3 -s "$ai_scale"
else
"$REALESRGAN_BIN" -i "$cur" -o "$tmp" \
-n realesr-animevideov3 -s "$ai_scale" \
>/dev/null 2>&1
fi
fi
# STRICT: output must exist
[[ ! -f "$tmp" ]] && {
echo "to-dpi: Real-ESRGAN produced no output file"
echo "to-dpi: input format likely unsupported — aborting"
exit 1
}
cur="$tmp"
cur_w=$(( cur_w * ai_scale ))
cur_h=$(( cur_h * ai_scale ))
remaining_scale=$(python3 - <<EOF
print(max($tgt_w / $cur_w, $tgt_h / $cur_h))
EOF
)
printf " after = %dx%d\n" "$cur_w" "$cur_h"
printf " remaining = %.2fx\n" "$remaining_scale"
(( pass++ ))
done
# -------------------------
# Final resize
# -------------------------
printf "\nFinal resize (Lanczos, non-AI):\n"
printf " from = %dx%d\n" "$cur_w" "$cur_h"
printf " to = %dx%d\n" "$tgt_w" "$tgt_h"
(( DRY_RUN )) && {
echo "\n(dry-run: no files written)"
exit 0
}
final="${base}__final.png"
magick "$cur" -resize "${tgt_w}x${tgt_h}" -filter Lanczos "$final"
output="${base}_${dpi}dpi.png"
magick "$final" -units PixelsPerInch -density "$dpi" "$output"
# -------------------------
# Cleanup (zsh-safe)
# -------------------------
ups=( "${base}"__up*.png(N) )
(( ${#ups[@]} )) && rm -f -- "${ups[@]}"
rm -f -- "$final"
echo "\nOutput:"
echo " $output"
@RexYuan
Copy link
Author

RexYuan commented Dec 23, 2025

Download the xinntao/Real-ESRGAN-ncnn-vulkan binary here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment