Batch resize and convert photos with ImageMagick
Pick a folder of photos and run ImageMagick 7 on every one of them: shrink them for the web, make thumbnails, convert to WebP or PNG, or recompress JPEGs. The unmodified ImageMagick program runs inside this tab on a RISC-V virtual machine; your photos are never uploaded.
Run it on your folder
Nothing is downloaded until you press Run. Works in current Chrome, Edge, Firefox and Safari; saving straight back into the folder needs Chrome or Edge.
ImageMagick runs on an emulated RISC-V CPU, so it is slower than on your desktop: about 3–8 s per 12-megapixel photo on a fast desktop (measured with Node.js on an Apple M3 Max); slower devices and browsers take longer. Thumbnails are the fastest preset.
What you can do
Resize for the web (JPEG)
Scales every photo down so its longest side fits the size (smaller ones keep their size), applies the camera rotation, removes metadata and saves a JPEG in out/.
mkdir -p out && st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; h=; set -- $(magick identify -format '%w %h ' "$f"); { [ "$1" -gt 1600 ] || [ "$2" -gt 1600 ]; } && h="-define jpeg:size=1600x1600"; magick $h "$f" -auto-orient -strip -resize 1600x1600'>' -quality 82 out/"${f%.*}".jpg || st=1; done; exit $stMake thumbnails
Small, metadata-free JPEG thumbnails in out/thumbs/ — the fastest preset.
mkdir -p out/thumbs && st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; h=; set -- $(magick identify -format '%w %h ' "$f"); { [ "$1" -gt 800 ] || [ "$2" -gt 800 ]; } && h="-define jpeg:size=800x800"; magick $h "$f" -auto-orient -strip -thumbnail 800x800'>' -quality 80 out/thumbs/"${f%.*}".jpg || st=1; done; exit $stConvert to WebP
Resizes and converts every image to WebP (fast encoder setting) in out/. WebP files are typically a quarter to a third smaller than JPEG.
mkdir -p out && st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; h=; set -- $(magick identify -format '%w %h ' "$f"); { [ "$1" -gt 1600 ] || [ "$2" -gt 1600 ]; } && h="-define jpeg:size=1600x1600"; magick $h "$f" -auto-orient -strip -resize 1600x1600'>' -define webp:method=0 -quality 80 out/"${f%.*}".webp || st=1; done; exit $stConvert to PNG
Resizes and converts every image to lossless PNG in out/. PNG photos are large; keep the size modest.
mkdir -p out && st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; h=; set -- $(magick identify -format '%w %h ' "$f"); { [ "$1" -gt 1600 ] || [ "$2" -gt 1600 ]; } && h="-define jpeg:size=1600x1600"; magick $h "$f" -auto-orient -strip -resize 1600x1600'>' out/"${f%.*}".png || st=1; done; exit $stRecompress JPEGs at full size
Keeps the full resolution, applies the rotation, removes metadata and re-encodes at the chosen quality into out/.
mkdir -p out && st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; magick "$f" -auto-orient -strip -quality 80 out/"${f%.*}".jpg || st=1; done; exit $stList sizes and formats
Prints format, dimensions and file size of every image. Changes nothing.
st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; magick identify "$f" || st=1; done; exit $st
How it works
- Pick a folder. Choose the folder with your photos (JPEG, PNG or WebP). They are copied into a sandbox in this browser tab, not uploaded.
- Choose a preset. Resize for the web, make thumbnails, convert to WebP or PNG, or recompress JPEGs. Set the size and quality; the magick command appears and can be edited.
- Run ImageMagick. Press Run. ImageMagick processes one photo after another and writes the results into an out/ folder; the output pane shows each file as it starts.
- Save the results. Save out/ back into your folder, or download it as a zip file.
Under the hood the page boots NanoVM, a Linux userland compiled to WebAssembly, in this tab. Your folder is copied into its in-memory filesystem at /work, and a BusyBox shell runs the command, which starts magick on the RISC-V runner. The Terminal tab opens the same folder in an interactive shell, for anything the presets don’t cover.
Your files stay on your device
Your photos are read by your browser and copied into an in-memory filesystem inside this tab, where the ImageMagick program runs on NanoVM's RISC-V emulator. Nothing is uploaded; there is no server that could receive them.
The presets remove EXIF metadata (including GPS location) from the images they write, and apply the camera's rotation first so nothing ends up sideways.
The only network requests are for the ImageMagick program itself: a signed, content-hashed package from the jsDelivr CDN, fetched once and cached. The counter next to the Run button lists every request that leaves this site.
Questions
How long does it take?
About 3–8 seconds per 12-megapixel photo on a fast desktop, measured with Node.js on an Apple M3 Max; browsers and slower machines take longer. Thumbnails are the quickest; PNG output of large photos is the slowest. Smaller photos are much faster.
Does resizing make small images bigger?
No. The size is a maximum for the longest side: larger photos are scaled down, smaller ones keep their size, and the aspect ratio is always kept.
Why WebP?
WebP files are typically a quarter to a third smaller than JPEGs of similar visual quality, and every current browser displays them. The preset uses ImageMagick's fastest WebP encoder setting.
Can it read HEIC photos from an iPhone?
Not yet: this ImageMagick build includes JPEG, PNG, WebP and its built-in formats, but no HEIC decoder. Export the photos as JPEG first, or remove their metadata with the photo metadata tool, which does handle HEIC.
Is this the real ImageMagick?
Yes: ImageMagick 7.1.2 compiled unmodified for 64-bit RISC-V Linux, with zlib, libjpeg-turbo, libpng and libwebp, running on NanoVM's emulator in your browser. The Terminal tab gives you the full magick command line.
Are my photos uploaded?
No. Everything happens inside your browser tab. After the program has loaded you can disconnect from the internet and it keeps working.
The software
- program
- ImageMagick
7.1.2-33 - license
ImageMagick License- source
- github.com/ImageMagick/ImageMagick
- runs on
- the RISC-V VM (static Linux binary)
- delivered as
- a signed, content-addressed package from the NanoVM app catalog (Ed25519 + SHA-256, verified in the browser)
- this page
AGPL-3.0-only OR LicenseRef-UEL· source
Build the same thing into your page
This tool is the <nano-tool> web component from the public NanoVM SDK (@userland-run/nano-sdk/tools), with the built-in imagemagick definition. The same element runs on any page:
<script type="module">
import { defineNanoTool } from "@userland-run/nano-sdk/tools";
defineNanoTool();
</script>
<nano-tool tool="imagemagick" wasm-url="/nano.wasm" terminal url-params></nano-tool>Or headless, with the folder bridge (@userland-run/nano-sdk/folder). Definitions are plain data — presets, form fields and quoted command templates — so you can write one for any catalog app.
import { createNano } from "@userland-run/nano-sdk";
import { mountFolder } from "@userland-run/nano-sdk/folder";
import { runTool } from "@userland-run/nano-sdk/tools";
const nano = await createNano({ image: { wasm: "/nano.wasm" }, ramMB: 1024 });
const dir = await showDirectoryPicker({ mode: "readwrite" });
const folder = await mountFolder(nano, dir, { at: "/work" });
// installs imagemagick from the signed catalog, then runs:
// mkdir -p out && st=0; for f in *.[jJ][pP]*[gG] *.[pP][nN][gG] *.[wW][eE][bB][pP]; do [ -e "$f" ] || continue; echo "$f"; h=; set -- $(magick identify -format '%w %h ' "$f"); { [ "$1" -gt 1600 ] || [ "$2" -gt 1600 ]; } && h="-define jpeg:size=1600x1600"; magick $h "$f" -auto-orient -strip -resize 1600x1600'>' -quality 82 out/"${f%.*}".jpg || st=1; done; exit $st
const r = await runTool(nano, { tool: "imagemagick", preset: "web", folder });
if (r.exitCode === 0) await folder.writeBack(); // new and changed files only; never deletes