How it works

What happens to your file, and how to choose the settings

Every decode, resize and encode happens on your device. Here is what each step does, what each setting changes, and where the tool stops.

1. Your browser reads the file

The drop zone hands the file to the File API and then to a Web Worker on this device. There is no upload step.

2. A codec works on the pixels

WebAssembly modules built from MozJPEG, the Squoosh PNG codec, oxipng, libwebp and libavif decode and encode the picture off the main thread, and Rust resize ports scale it, so the page stays usable. Each module carries its own license, and the credits page lists them.

3. You download the result

Each finished file gets its own download link, its size before and after, and a preview of what you are about to get.

The Compress Images tool with one picture already converted: the drop zone, the output format, quality, resize, EXIF and target size controls, and a finished row with the size before and after, the output's dimensions, a download button and both pictures side by side.
One real run: a test picture converted to WebP at the default quality. The numbers in the row are what that run produced, not a promise about your file.

Where the work happens

Your file never reaches a server, and neither does the result. The page reads the file with the File API, which gives the browser a handle to bytes that are already on your disk; it does not upload them. Those bytes go to a Web Worker, a background thread, so a long batch does not freeze the page you are reading. Inside that worker the codecs turn your image into plain 8 bit pixels, resize it if you asked for that, and encode the result in the format you chose.

The codecs are WebAssembly modules built from MozJPEG, Squoosh’s PNG codec, oxipng, libwebp and libavif, plus Rust ports for the resize step. The credits page lists each one with its own license, because a wrapper package’s license is not the codec’s. A module is fetched from this site the first time you use its format, which is why the first conversion in a given format is slower than the ones after it. Nothing is fetched from anywhere else, and no request carries your file.

Choosing a quality setting

Quality is a whole number from 1 to 100, and it starts at 75. It applies to JPEG, WebP and AVIF, which are all lossy: a lower number spends fewer bits on the picture, a higher one spends more. PNG is lossless, so it ignores the setting entirely, and the tool says so while PNG is selected.

Neither end of the scale is free. At 1 the picture keeps its shape but loses detail, and where that detail goes first depends on the picture and the encoder, so this page does not promise an order. At 100 the file is large and still not quite the original, because the encoder rebuilds the picture from a compressed description of it. If you are not sure where to start, leave it at 75 and compare the two previews each finished row shows: the one on the left is the file you chose, the one on the right is what you will download.

Choosing a size

Resizing is off until you turn it on. By width, the output is that many pixels wide and keeps the picture’s proportions, so a 3:2 photo at a width of 1280 comes out 1280 by 853. By percent, both dimensions become that share of the original. The percent field stops at 100, so percent mode cannot enlarge a picture; a width you set above the original does enlarge it, which is rarely what makes a file smaller and is why the percent field is the safer of the two.

If your camera stored a rotation in the file, that rotation is applied to the pixels before anything else happens, so a photo taken in portrait comes out the right way up. The four orientations that include a quarter turn, EXIF 5 to 8, swap the width and the height, so a photo tagged 6 comes out 400 by 600 from a file whose numbers read 600 by 400. The other four leave both numbers as they were: no change at all, the two mirroring ones, and the 180 degree turn, which turns the picture on its side without making it taller or wider.

One input format does not carry that rotation into the tool at all: an AVIF input’s EXIF block is not read, so an AVIF file that stores an orientation is used as it is stored, with its dimensions as its file states them.

Hitting a size limit

Forms and servers often want a file under a number of kilobytes rather than merely smaller. The target size field takes that number in KiB, which is 1024 bytes and not 1000, and the tool works towards it: if the first encode is over the number it lowers the quality, as far as 1, until the file fits, and if the first encode comes out well under it, it raises the quality from your setting, never above 100, looking for the highest quality that still fits. The row then tells you whether the file you get is at or under the target.

Three honest limits. The search can only spend quality, and only the upward half of it is bounded by your setting, so a picture that is still over the target at quality 1 will not reach it, and what you get then is the encode at quality 1. In the other direction, a target above what quality 100 can reach for that picture cannot be filled by making the file bigger, because the scale stops at 100: you get the largest file the format made, which is still under your number, and the row reports the target as reached, because the file is under the ceiling. And PNG ignores the quality setting, so the search has nothing to spend there: a PNG output still gets a second pass through oxipng, which can return fewer bytes than the first encode, so a PNG target that the first encode missed can still be met, and one that neither pass can reach is reported as missed.

A target is a ceiling with a floor at 95% of it, not a size to aim at. Quality moves in whole numbers, and one step can jump across the whole band, so the search aims at the band and lands in it when a step falls inside it, returning the closest encode under your target when no step does. It does not promise an exact size or a file within 5% of your number, and the number it reports is whether the file it is about to hand you is at or under your target.

That last sentence is what the verdict is decided on. The bytes are counted after any EXIF block has been written in, so if you ask to keep the metadata and the block pushes the file over your target, the row says the target was missed even though the encode alone was under it. You will never be told a limit was met when the file you download is over it.

When a file is refused

The two limits are checked at different moments, and the difference is worth knowing. A file larger than 32 MiB is turned away from its size alone, before its bytes are read at all, so it costs nothing. A file over 40,000,000 pixels has to be read in full first, because its pixel count is only known once its header has been parsed, so an oversized picture is read and then turned away before anything decodes its pixels.

The row names the limit it refused either way. One refused file never stops the batch: every other file you chose still finishes. Neither limit depends on the machine you are using. They are fixed numbers, not a memory reading, so a faster or a smaller computer does not raise them. What does change them is the input: crop the picture, shrink it elsewhere, or split the work, and then choose the files again (choosing replaces the list).

An input the tool cannot decode at all, because it is damaged or truncated, gets a row that says so in the same place. An encrypted file cannot be opened here: there is no password field, and no part of your file is sent anywhere to be unlocked.

One failure is about the browser rather than the picture. If the worker converting a file cannot be started, or dies partway, that file gets a row saying the browser could not run the image engine, and that worker takes no further files. The other workers carry on with the rest of the queue, and rows that had already finished keep their results. If every worker fails, then every file that had not already started gets that same row rather than waiting: the run ends with an answer for each one instead of stalling on the files no worker reached. A file that merely fails to decode or encode is not this case: that is the one row’s error, and the worker that reported it goes on to the next file. Try a current version of Chrome, Firefox, Edge or Safari.

Getting started guide

Continue exploring this topic

Related topics: Common tasks

Ready to try it on your own pictures?

The tool is on the home page. Drop a few files in and compare the sizes side by side.

Compress an image