PNG Image Compressor
Reduce PNG file size in your browser — lossless compression, files never leave your device.
Drop images here or click to select
JPG, PNG, WebP, GIF, BMP, AVIF, TIFF — multiple files supported
How to compress PNG images
- Drop your PNG or other image files onto the compressor above — or click to browse.
- Click Compress on a single file or Compress all to process everything in one go.
- Download files individually or click Download all for a ZIP archive of all compressed PNGs.
- Tip: if you need even smaller files, try the WebP compressor — WebP achieves 25–35% smaller sizes than PNG with the same visual quality.
Your files stay on your device — 100% private
PNG is the format people use for screenshots, and screenshots are the single most sensitive kind of image a developer handles — dashboards, internal tools, client admin panels, error pages with real customer data in them. Uploading those to an unknown compression service to save a few hundred kilobytes is a bad trade.
This compressor never uploads anything. The file is read locally, re-encoded by the browser's own PNG encoder, and handed back as an in-memory download. Open DevTools → Network while you compress: no request carries your image. Disconnect from the network afterwards and it still works.
// No quality argument for PNG — the encoding is always lossless
canvas.getContext('2d').drawImage(img, 0, 0)
canvas.toBlob(blob => download(blob), 'image/png')What is PNG compression and how does it work?
PNG uses lossless compression — every pixel comes out exactly as it went in. Nothing is approximated and nothing is discarded, which is the opposite of how JPG works. That is what makes PNG right for graphics, logos, screenshots, and anything with sharp edges or transparency.
Under the hood, PNG works in two stages. First it filters each row of pixels, storing the difference from the row above or the pixel to the left instead of the raw value — long runs of identical colour become long runs of zeros. Then it runs DEFLATE (the same algorithm as ZIP) over the filtered data. This is why a flat UI screenshot compresses brilliantly and a photograph barely compresses at all: photographs have no repeating patterns for the filter stage to exploit.
What this tool actually removes
Because the image is redrawn onto a canvas before re-encoding, everything that is not pixel data is dropped: EXIF blocks, embedded colour profiles, XMP metadata, text chunks, editor histories and embedded thumbnails. Files exported from Figma, Sketch, Photoshop or a phone screenshot tool often carry a surprising amount of this — which is where the savings come from. The pixels themselves are bit-for-bit identical.
When PNG is the right format
- Logos and icons — sharp edges stay crisp, with none of the haloes JPG produces
- Screenshots and UI mockups — small text stays readable instead of smearing
- Images with transparency — PNG has a full alpha channel, JPG has none
- Master files you will keep editing — lossless means re-saving never degrades anything
PNG vs JPG vs WebP — which one should this image be?
| PNG | JPG | WebP | |
|---|---|---|---|
| Compression | Lossless | Lossy | Both |
| Transparency | Yes, full alpha | No — fills white | Yes, full alpha |
| Photographs | Poor — huge files | Excellent | Excellent |
| Flat graphics, text, UI | Excellent | Poor — haloes | Excellent |
| Typical size vs PNG | baseline | 5–20% of PNG (photos) | ~26% smaller than PNG |
| Browser support | Universal | Universal | All modern browsers |
| Animation | APNG, rarely used | No | Yes |
The short version: if the image is a photograph, PNG is the wrong container and no amount of compression will fix that — convert it to JPG or WebP instead. If it is a screenshot, logo or UI element, PNG is correct, and WebP is the same thing but around a quarter smaller.
Why your PNG sometimes will not get any smaller
Lossless means there is a hard floor. Once the metadata is gone and DEFLATE has done its work, there is nothing left to remove without changing pixels. If you compress a PNG and get back a file of roughly the same size, that is the tool telling you the file was already close to optimal.
Cases where you should expect little or no reduction
- PNGs that already went through an optimiser such as pngquant, OxiPNG or ImageOptim
- Photographs saved as PNG — the pixel data is inherently noisy and incompressible
- Small icons where metadata was never large in the first place
- Files exported by a build pipeline that already strips metadata
What to do instead
- Switch to WebP — roughly 26% smaller than PNG at identical quality, with transparency intact
- Switch to JPG if the image is a photograph and does not need transparency
- Reduce the colour palette in your design tool before export — a 32-colour PNG-8 is dramatically smaller than a 16-million-colour PNG-24
- Resize — an image displayed at 400 px wide does not need to be 3000 px wide
How browser-based PNG compression works under the hood
The whole pipeline is a handful of native browser calls. There is no library doing the encoding — the browser ships a PNG encoder and this tool just drives it.
// 1. Read the dropped file as a local object URL — no network involved
const img = new Image()
const url = URL.createObjectURL(file)
img.onload = () => {
// 2. Draw at native resolution onto an off-screen canvas.
// This step is what discards EXIF, colour profiles and text chunks.
const canvas = document.createElement('canvas')
canvas.width = img.naturalWidth
canvas.height = img.naturalHeight
canvas.getContext('2d').drawImage(img, 0, 0)
// 3. Re-encode as PNG. Note: no quality argument —
// PNG encoding is lossless, so there is nothing to tune.
canvas.toBlob((blob) => {
URL.revokeObjectURL(url)
resolve(blob)
}, 'image/png')
}
img.src = urlBecause the source is decoded to raw pixels first, any input format works — drop a JPG, WebP, AVIF, TIFF, GIF or BMP and you get a lossless PNG back. Transparency in the source is preserved through the canvas, so a transparent WebP becomes a transparent PNG. Going the other way, a JPG has no transparency to preserve, so the result is simply an opaque PNG that is usually larger than the JPG you started with — expected, not a bug.