Process many images at once with one operation, with every output decoded again and checked against what was asked for, and the whole batch downloaded as one ZIP.
Initializing in your browser…
Turn an image into a data URL whose payload is decoded again and compared byte for byte with the file, with the media type taken from the file's own signature rather than its extension and the size cost of embedding stated in full.
Resize with the filter named (Lanczos, Mitchell, Catmull-Rom, bilinear, box or nearest) and the option to average LIGHT rather than stored bytes, which is worth 1.24 stops on a detailed picture.
Convert between the formats a browser can really write, then open the output and name the format its first bytes say it is. AVIF, BMP and GIF are disabled because a canvas returns a PNG for all three.
Three images of different shapes through the Instagram Square preset, whose label says 1080 by 1080 JPEG.
In
resize-photo.png 600x400, conv-alpha.png 200x200, xy-odd.png 301x199
What Pillow reads out of the ZIP
resize-photo-1080x1080.jpg JPEG 1080x1080 conv-alpha-1080x1080.jpg JPEG 1080x1080 xy-odd-1080x1080.jpg JPEG 1080x1080
The previous version produced a PNG here, named it .jpg, and stretched the 3:2 photograph to a square. All eighteen of its outputs across six presets were PNGs whatever was asked for. Every file is now decoded again after it is made, its format read off the bytes and its size off the decoded image, and the page states whether each one matched the plan.
Run one operation over many images at once, with every output checked against what was asked for. Each finished file is decoded again: the format is read off the bytes and the size off the decoded image, and the page says whether every one of them matched the plan. Everything comes back as one ZIP.
Crop hundreds of product photos to one square size as JPEGs, with every output verified rather than assumed.
Take a folder to 1200 pixels across as WebP, with each file keeping its own shape.
Convert a set to WebP or PNG and check that every one of them really is that format before shipping it.
A batch tool makes exactly one claim: every file that comes out is the thing the settings named. Measured on 2026-09-05 by handing every output to Pillow, the previous version did not manage that for a single preset. All EIGHTEEN outputs across six presets were PNGs whatever was asked for, and each was named after what was asked for rather than what it was, so "Instagram Square (1080x1080 JPEG)" produced a PNG called processed-1-photo.jpg.
Three separate causes, one per operation. Resize called the shared resizer with two arguments, and that function's third parameter defaults to image/png, so the format buttons and the quality slider reached nothing at all. Convert passed the string "webp" where canvas.toBlob wants "image/webp", and an unrecognised type makes toBlob fall back to PNG and say nothing. Filter hardcoded PNG at quality 1. The geometry was wrong too: the batch substituted `resizeWidth || 800` and `resizeHeight || 600` before calling the resizer, so a height of 0, which the tool's own tip said meant "auto", became 600 and the aspect-preserving branch could never fire. A 600 by 400 photograph asked for 1080 by 1080 came out stretched, with the maintain-aspect-ratio toggle on. And the size panel added a 15 KB source against a 246.8 KB output, 16.5 times larger, under the heading "Size Comparison".
Everything is now planned before anything runs. Each file is decoded once on arrival, so the page can say exactly what every output will be, at what size, and under what name, and the plan is what the result is checked against. After each file is produced it is decoded AGAIN: the format is sniffed off the bytes rather than taken from the request, the size is read off the decoded image, and the page states whether every finished file matched. Across seven presets and three inputs, every member of the archive is now the format and the size the preset promised, confirmed by Pillow opening each one.
The operations themselves are the audited ones. Resizing goes through the shared resampler, which offers six filters each carrying the paper it comes from, exact fit, crop-to-fill and stretch geometry, alpha premultiplied before filtering, and the option to average LIGHT rather than stored bytes. The effects are the matrices Filter Effects Module 1 section 8 defines, and the page prints the equivalent CSS so a browser can be asked the same question: the greyscale agrees with the browser's own grayscale(1) to ZERO of 255, where the old one used Rec. 601 on the stored bytes and was 32 levels out on pure green. The old effect list also offered Saturate, which had no case in its switch and produced a file identical to the input; its Contrast computed (1 - 0.5) times 259 divided by (259 - 259), which is Infinity, and thresholded every channel at 128; and its Brightness always added exactly 50 whatever the setting. Four effects now produce four different files.
Download All really is one ZIP, which the copy has promised for a long time: the old one called a save once per file in a tight loop, and a browser refuses most of a burst of downloads with no gap. File names come from a pattern with the original name, the position and the output size, the extension is always added from the format the file really is, and two files that would collide are numbered. A file that cannot be decoded is named and skipped rather than stopping the queue, and the size summary is counted only against the files that actually finished, so half a batch does not report a saving against files it has not touched.
There is no fixed limit. Each file is decoded, processed and decoded again in this tab, so the practical ceiling is your device's memory. Batches of 50 to 100 are comfortable.
No. One operation runs over the whole queue, and the page says which. Run the batch twice if you want two, feeding the output of the first into the second.
It is named in the queue with the reason, marked as failed, and skipped. The rest of the batch runs, and the size summary counts only the files that finished.
The page checks and tells you. A canvas silently returns a PNG for a type it cannot write, so every finished file is decoded again and its format read off the bytes. The verdict names any file that is not what was asked for.
Because a format or a size can make a file bigger, and the page says so in those words rather than reporting a saving. A PNG of a photograph is usually several times the JPEG, and enlarging costs bytes too.
Images are decoded, edited, and exported entirely inside this browser tab. No originals, exports, or metadata are uploaded.