Image compressor

Make a PNG smaller without changing a pixel, and a JPEG smaller than your browser can.

Or drop them here, or paste. PNG, JPEG, GIF or BMP, any number. Nothing is uploaded.

Options

75

Applies to JPEG files only. MozJPEG’s numbers are its own: its 75 is not your camera’s 75 and not your browser’s, so judge the before and after, not the number.

Lossy — it throws away detail to save bytes, and what it throws away does not come back.

The engine is picked from each file: PNG, GIF and BMP go to oxipng and come out lossless; JPEG goes to MozJPEG and does not. Re-encoding a JPEG also drops its EXIF metadata, including any GPS coordinates the camera wrote in.

More optionsPNG effort: Fast (level 2) · lossless at every level

PNG effort · oxipng

Captures about 98% of the saving. The right default.

Lossless — every pixel comes out identical. It changes how the file is stored, never what it shows. GIF and BMP are decoded once and come out as an optimised PNG.

Add an image, or try a sample, to start.

What lossless image compression is

Rewriting how an image is stored — the filter applied to each scanline, the palette, the bit depth, the ordering of the compressed stream — without altering a single pixel value. It is a different operation from lossy compression, which discards detail, and from a canvas re-encode, which is neither.

What this tool does that others do not

  • The PNG path never touches a canvas

    Most browser image tools decode onto a canvas and ask the canvas to write the file back out. A general-purpose encoder in a hurry makes very different choices from one whose entire job is to find the smallest legal encoding of the same pixels, and the difference is not small. Here the bytes you drop go straight into oxipng and the bytes it returns come straight back.

    A 21,493-byte flat interface graphic came out of a canvas PNG encode at 38,905 bytes — 81% larger. A one-megabyte photograph came back 23% larger.

  • Two engines, two different promises

    oxipng is lossless and handles PNG, plus GIF and BMP by decoding once and writing an optimised PNG instead — a 256-colour GIF is usually smaller as an optimised PNG than it was as a GIF. MozJPEG handles JPEG and is not lossless; it works by throwing detail away, and that is said next to the slider rather than in a footnote.

  • Effort levels buy search time, not quality

    Output is lossless at every oxipng level, so a higher level costs time and nothing else. The default is the low one because the measurements say so, and WebAssembly runs two to three times slower than the native figures, which makes the top levels noticeably slow on large images.

    On a 1600 × 1000 photograph, level 2 took 0.97 seconds for 884,853 bytes; the maximum took 3.45 seconds for 864,362 — 2.3% more saving for three and a half times the work.

  • No “we beat the browser by X%” badge

    It would sometimes be a lie, and the measurements say exactly when. A quality number is one encoder’s private dial rather than a shared scale, so comparing two encoders at the same number compares nothing.

    On identical pixels: MozJPEG 113,935 bytes against Chromium’s 139,476 at quality 75, an 18% win; 188,448 against 176,567 at quality 92, a 7% loss.

How to use it

  1. Drop in PNG, JPEG, GIF or BMP

    The engine is chosen from the file. There is no format decision to make and no count to watch.

  2. Leave the effort at the default for a first pass

    It captures most of the available saving in under a third of the time of the maximum, and the output is lossless either way.

  3. For JPEG, judge the two panes rather than the number

    A quality of 75 here does not mean what 75 meant in the tool the file came from.

  4. Read the per-file deltas

    A red figure with a plus sign means the file was already efficient and there was nothing left to take. Keep the original for those.

Worked examples

Real input, real figures.

A flat interface graphic through both routes

You give it

A 21,493-byte PNG.

You get

Canvas re-encode: 38,905 bytes, 81% larger than the source. oxipng: 3,350 bytes — 6.4 times smaller than the source and 91% smaller than the canvas output, with every channel of every pixel identical.

A photograph where the canvas route looked fine

You give it

A one-megabyte photograph.

You get

The canvas output was 1,236 KB — larger than the source. oxipng took that to 864 KB, a 30% saving against the canvas result and still 14% below the original file, losslessly.

Against a canvas-based compressor

AspectThis toolA canvas re-encoder
PNG routeoxipng, bytes in and bytes outDecode to canvas, re-encode
PNG result on a flat graphic3,350 bytes from 21,49338,905 bytes — larger
JPEG engineMozJPEG, labelled lossyThe browser’s encoder
Same-number comparisonRefused, with the figures showing whyPresented as a win
Files that grewShown in red with a plus signUsually hidden

Guide

What it will not do

  • WebP and AVIF are refused. Both are already compressed by better encoders, and routing one through a PNG or JPEG path reliably produces a bigger file. If you need a WebP turned into something else, that is a conversion rather than a compression.
  • Animated GIFs and animated PNGs are refused. Decoding an animation in a browser returns the first frame and silently discards the rest, so a forty-frame GIF would come back as a still reported as a 95% saving — a data-loss bug dressed up as a result.
  • JPEGs, GIFs and BMPs past the canvas ceiling — roughly 8,192 pixels a side or about 16 megapixels — are turned away rather than quietly scaled down, because a silent resize sold as compression is the same dishonesty in a different coat. A PNG never goes through a canvas, because oxipng works on the file itself, so the only limit on a PNG is your device’s memory.

Re-encoding is not optimising

Most browser-based image tools work the same way: decode your file onto a canvas, then ask the canvas to write it back out. That is the right trade for changing a format — it costs no download and the browser's decoders are excellent. It is the wrong tool for making a file smaller, and the numbers are not close.

We measured it. A flat interface graphic of 21,493 bytes came back out of a canvas PNG encode at 38,905 bytes — 81% larger than the file we put in. A one-megabyte photograph came back 23% larger. Not corrupted, not visibly different: just bigger, because a general-purpose encoder writing a PNG in a hurry makes different choices from one whose entire job is to find the smallest legal encoding of the same pixels.

So the PNG path here never touches a canvas. The bytes you drop go straight into oxipng and the bytes it returns come straight back. On that same flat graphic oxipng produced3,350 bytes — 91% smaller than the canvas output and 6.4 times smaller than the file the user brought in. On the photograph it took the canvas output from 1,236 KB down to 864 KB, a 30% saving, and still beat the original source file by 14%. Every pixel identical.

Two engines, two different promises

The tool picks the engine from the file you give it, and the two promises are not the same, so they are not presented as if they were.

oxipng is lossless. It handles PNG, and it handles GIF and BMP by decoding them once and writing an optimised PNG instead — a 256-colour GIF is usually smaller as an optimised PNG than it was as a GIF. Its only control is effort, which costs time and nothing else. The default is level 2 because the measurements say so: level 2 took 0.97 seconds for 884,853 bytes on a test photograph, and the maximum took 3.45 seconds to reach 864,362. That is 2.3% more saving for three and a half times the work. A default should never be the slow one.

MozJPEG is not lossless. It handles JPEG, it is genuinely better than the browser's encoder — 18% smaller on identical pixels at quality 75 — and it works by throwing detail away. The tool says so next to the slider rather than in a footnote, because "compressed" and "unchanged" are different claims and only one of them is true here.

Why there is no "we beat the browser by X%" badge

Because it would sometimes be a lie, and we know exactly when. On the same source pixels, MozJPEG at quality 75 produced 113,935 bytes against Chromium's 139,476 — an 18% win. At quality 92 MozJPEG produced 188,448 bytes against Chromium's 176,567 — a 7%loss. Same encoder, same image, same dial, opposite verdict.

The reason is simple and widely ignored: a quality number is one encoder's private dial, not a shared scale. Chromium's 92 and MozJPEG's 92 do not describe the same amount of information discarded, so comparing two encoders at the same number compares nothing. Any tool showing you a same-number comparison is either unaware of this or counting on you being unaware of it. What you get instead is the two images at the same size on the same background, and the real byte figure underneath each one.

What it refuses, and why that is the feature

WebP and AVIF are turned away. They are already compressed by encoders better than either of ours, and routing them through a PNG or JPEG path would reliably produce a bigger file. Animated GIFs and animated PNGs are turned away too, for a worse reason: decoding an animation in a browser hands back the first frame and drops the rest silently, so the tool would report a spectacular saving for having destroyed the animation. JPEGs, GIFs and BMPs past the canvas ceiling — roughly 8,192 pixels on a side, or about 16 megapixels — are refused rather than quietly scaled down, because a silent resize sold as compression is the same dishonesty in a different coat. A PNG never goes through a canvas, so it has no such ceiling beyond your device’s memory.

If what you actually need is a different format rather than a smaller file, that is a different job: the image converterhandles WebP, JPEG and PNG output and can resize on the way through, and the rest of the set lives under converters.

When a file comes out bigger

It happens, and the number turns red with a plus sign in front of it. A JPEG saved at high quality, a PNG that has already been through an optimiser, a small icon where the format's own overhead is a large share of the file — all of these can come out larger, and all of them are telling you something useful: there was nothing left to take. A compressor that only ever reports savings is not measuring anything, so the honest reading is to keep your original for those files. The batch total is computed by the same arithmetic, which means a single bad file can sit inside a good total and both figures are true.

Questions people ask

Straight answers. Each one links directly: copy the address after opening it.

Is this actually lossless?

For PNG, GIF and BMP, yes. Those go through oxipng, which rewrites how the file is stored — the filter applied to each scanline, the palette, the bit depth, the ordering of the compressed stream — without touching a single pixel value. Decode the result and the original side by side and every channel of every pixel matches. JPEG is the exception and is labelled as such: MozJPEG is a lossy encoder, and the detail it discards to save bytes does not come back.

Why does it refuse my WebP and AVIF files?

Because neither of the two engines here can beat them. WebP and AVIF are already modern compressed formats; re-encoding one as a PNG or a JPEG makes it bigger, every time. A compressor whose honest answer is "+40%" should not have accepted the file in the first place. If you need a WebP turned into something else, that is a conversion rather than a compression, and the image converter does it.

Why not just re-save the PNG in the browser?

Because the browser’s PNG encoder is not an optimiser. We measured it: running a flat interface graphic through a canvas round-trip produced a file 81% larger than the source, and a photograph came out 23% larger. Any tool built that way is an inflater on a meaningful share of real inputs. The PNG path here never touches a canvas — the bytes you dropped go straight into oxipng and the bytes it returns come straight back out.

What do the oxipng levels do?

They buy search effort, not quality — the output is lossless at every level, so a higher level only costs time. On a 1600×1000 photograph, level 2 took about a second and produced 884,853 bytes; the maximum took three and a half seconds and produced 864,362. Level 2 captures roughly 98% of the available saving in under a third of the time, which is why it is the default. WebAssembly runs two to three times slower than those native figures, so the higher levels are noticeably slow on large images.

Is MozJPEG’s quality 75 the same as my camera’s quality 75?

No, and this matters more than it sounds. A quality number is an encoder’s private dial, not a shared scale. On identical pixels MozJPEG came out 18% smaller than Chromium’s canvas encoder at "75" and 7% larger at "92" — same number, different meaning, opposite verdict. Judge the result in the before-and-after panes rather than trusting the number to mean what it meant somewhere else.

Why did one of my files get bigger?

Because it was already efficient and there was nothing left to take. That happens with JPEGs saved at a high quality, with PNGs that have already been through an optimiser, and with small images where format overhead is a large share of the file. The per-file figure turns red and shows a plus sign when it happens. A compressor that only ever reports savings is not measuring anything — keep your original for those files.

What happens to animated GIFs and animated PNGs?

They are refused, deliberately. Decoding an animation in a browser gives you the first frame and silently discards the rest, so a forty-frame GIF would come back as a still image reported as a 95% saving. That is a data-loss bug dressed up as a result. The file is turned away at the door with the reason written next to it.

Is there a file count limit?

No. Nothing is uploaded, so there is no server time to meter. Files are processed one after another rather than all at once, because two WebAssembly codecs decoding large images in parallel is the fastest route to exhausting a phone’s memory and losing the tab. The practical ceiling is your own machine.