Batch Image Resize Tool That Teaches Scripts

batch-image-resize-tool-that-teaches-scripts

Batch Image Resize Tool That Teaches Scripts. A Build Next Stack field guide for learners shipping small projects.

Scope: one folder in, resized copies out

Write a CLI that walks an input directory, resizes images to a max width or height while preserving aspect ratio, and writes copies to an output directory without touching originals. Support JPEG and PNG at minimum; skip or warn on others. No GUI, no cloud upload, no ML enhancement—just filesystem traversal, image decode/encode, and argparse.

Use Pillow in Python, Sharp in Node, or ImageMagick bindings—pick one dependency and pin version. The lesson is safe batch IO: never overwrite by default, predictable naming, and exit codes that shell scripts can chain.

Start with a folder of twenty photos, not ten thousand. Correctness on small sets first; performance tuning after profiling on real archive size. Premature parallelization hides off-by-one path bugs.

Milestone one: walk a directory safely

Implement –input dir and –output dir. Create output if missing; refuse if input equals output unless –in-place flag explicitly set with confirmation prompt. Traverse with library that skips symlinks outside input root—avoid accidental /etc tours via bad symlinks.

For each file, check extension allowlist .jpg .jpeg .png .webp. Non-images log warning and continue. Output filename: preserve stem, append -800w before extension if max width 800—document pattern. Acceptance: run on folder with ten mixed files; only images copy; originals byte-identical.

Normalize extensions to lowercase before processing. .JPG and .jpg on case-sensitive filesystems skip half a vacation folder silently; one .lower() on suffix prevents support tickets to yourself.

Milestone two: preserve aspect ratio every time

Resize logic: if width > max_width, scale down proportionally; else leave dimensions (optional upscale off by default). Use high-quality filter (LANCZOS in Pillow). Strip EXIF orientation by applying rotation before resize so phones do not produce sideways thumbs.

Preserve ICC profiles only if you understand color management; otherwise convert to sRGB for web outputs and document that choice. Mismatched profiles on wide-gamut monitors look fine locally and dull elsewhere—consistency beats perfection for learning scripts.

JPEG quality flag –quality 85 default; PNG preserve alpha. Fail single file on corrupt image without aborting batch—collect failures, print summary 3 failed / 47 ok, exit 1 if any failed, 0 if all ok. Summary line is what users screenshot when asking for help.

Log dimension changes at verbose level: IMG_1234.jpg 4032×3024 → 1600×1200. When aspect looks wrong, that line explains whether EXIF rotation ran.

Acceptance checks on mixed file types

Validation set:

  • Landscape 4000×3000 → fits max width 1200 with height 900.
  • Portrait phone photo respects EXIF rotate.
  • PNG with transparency keeps alpha after resize.
  • Zero-byte file increments failure count, not crash.
  • Output dir recreates cleanly on second run (overwrite policy documented).

Include samples/ with two tiny test images in repo for CI. One test asserts output dimensions without comparing pixels blindly—dimension math is the contract.

Document maximum supported megapixels in README when you add the guard. Users with medium-format scans need to know limits before running on originals folder.

Traps when image scripts eat originals

Trap: in-place default. Destructive defaults ruin photo archives. Output dir separate; in-place behind flag and prompt.

Trap: ignoring color profiles. Colors shift on wide-gamut photos; convert to sRGB on save for web-bound outputs.

Trap: memory on giant TIFFs. Cap max megapixels processed; skip with message if over threshold.

Trap: parallel before sequential works. Add multiprocessing only after single-thread batch is correct—race bugs hide in copies.

Trap: re-encoding JPEG many times. Document generation loss; prefer one resize pass from originals.

Trap: skipping progress output on large folders. Print every tenth file at default verbosity so users know the script is alive. Silent minutes feel like hangs; progress lines cost almost nothing.

Integrate with shell workflows

Accept –glob optional pattern defaulting to all images. Accept –jobs 1 for future parallel flag without implementing yet—parsing practice. Return non-zero exit when any file fails so CI or bash chains stop.

Example chain: export photos → resize → upload web folder via rsync. Document the chain in README; your script is one step, not the whole pipeline. Composability is the Unix lesson adjacent to imaging.

On Windows, test path handling with spaces in folder names. Quote paths in docs; PowerShell users hit this first. Cross-platform scripts teach empathy for teammates on different OSes even on solo projects.

Write a –version flag printing semver and exit 0. Tiny polish that helps when you have three resize scripts and forget which one supports WebP.

CLI flags worth adding on day three

After core works, add only:

  1. –max-width and –max-height (maintain aspect, fit inside box).
  2. –dry-run listing planned outputs without writing.
  3. –verbose per-file dimension lines.

Document examples in README:

resize.py –input ~/Photos/export –output ~/Photos/web –max-width 1600 –quality 82

Wrap in Makefile target for non-developer you six months later. Scripts teach future-you empathy; README examples are acceptance tests in prose.

Compare output file size to input; if JPEGs grow larger after resize, your quality default is too high or you upscaled accidentally. A one-line stat summary at end—saved 12.4 MB across 47 files—confirms the tool did useful work.

Resize one real export folder this weekend

Pick last vacation photos or design assets—copy folder, run tool, compare side by side in your viewer. Trust builds from real pixels, not unit tests alone. Fix EXIF handling before adding WebP output.

When batch finishes in under a minute for hundreds of files, you have learned IO and imaging basics that transfer to thumbnails, CI artifacts, and static site pipelines.

Keep originals sacred; output dir is disposable. That habit prevents the most common regret in batch media scripts.

Add a one-line license file if you open-source the tool. Resize scripts are useful portfolio pieces precisely because scope stays small and verifiable.

Run –dry-run before your first real folder; the preview list catches wrong output paths cheaper than restore from backup.