Image Compressor

Make JPG and WebP files smaller — by picking a quality, or by naming a target size in KB and letting the tool search out the quality that hits it. PNGs get the honest treatment: a real conversion to a lossy format, not a fake "PNG compression". Every result shows true before/after byte counts. All file processing is performed entirely in your browser.

Compress images

Drop JPG, WebP, or PNG files. JPG/WebP re-encode in place; PNG converts to the lossy format you choose below.

or drag and drop images here

Up to 40 files · 100 MB each · 300 MB per selection

Compression mode

    Guide: Quality parameters and compress-to-target walks through the quality scale, the binary search and the PNG-to-lossy labeling behind this tool, with the planner's own worked examples. The other guides cover detection, the pipeline, metadata and verification.

    What the detector sees before anything is encoded

    Nothing on this page trusts a filename. The leading bytes of every dropped file are read and matched against the signatures the detector knows. Three illustrative headers, built at build time and run through that detector: a file beginning FF D8 FF is identified as JPEG; one beginning \x89PNG is PNG; one beginning RIFF…WEBP is WebP. Only those three families are accepted here — a GIF, BMP, HEIC or AVIF file is recognized and named on its row with a plain wrong-tool message, rather than being forced through this one.

    The extension is then compared against that reading. An illustrative file named holiday.png whose bytes carry the JPEG signature comes back from the check as actual JPEG, claimed PNG, mismatch true: the row shows a notice, and the file is compressed as the JPEG it is — not converted as the PNG its name promised. The same bytes under the name holiday.jpg report mismatch false and get no notice.

    WebP gets one more look. The detector walks the RIFF chunk list for a VP8X chunk with the animation flag set, or an ANIM/ANMF chunk. A still header built with a plain VP8 chunk reports animated false; a header whose VP8X flags byte sets the animation bit reports true. When that reading is true, the row says so before encoding, because canvas decoding keeps only the first frame and the output will be a still image.

    Two modes, one honest readout

    The quality slider is the direct route: one encode at the setting you choose. The target-size mode is for the real-world constraint — "the form says maximum 200 KB" — and works like a disciplined guess-and-check: encode, measure the actual bytes, then binary-search the quality range, converging in at most eight attempts. Both modes end the same way: the row shows your file's genuine input size, output size, and (in target mode) the quality the search settled on. When the target is unreachable even at minimum quality, the tool says so and offers the smallest real result instead of quietly failing.

    The slider's number is the encoder's quality parameter, carried on a 0–1 scale internally and shown as a whole number. It is not a percentage of the original file, of its size, or of anything else — it is the single knob the browser's JPEG or WebP encoder exposes. The planning module carries a default per format — 92 for JPEG and 85 for WebP — and keeps the two scales distinct, so the same number should not be read as the same setting across formats. This page overrides the default with the slider's position; the default applies only if the slider cannot be read. The module also refuses values outside its range rather than clamping them silently; asked at build time to plan at a quality below the range, it answers: "Quality must be between 0.05 and 1."

    The target field is read in kilobytes of 1,024 bytes, the unit the result row displays. With no encodes made yet, the planner's first instruction is always the same: encode at quality 95, the ceiling of its search range. From then on it sees nothing but the list of attempts so far — each one a quality and the byte count it produced — and brackets between the highest quality known to fit and the lowest known to overshoot, halving the gap each round.

    Here is the planner driven to completion against an invented encoder — one whose output grows with the square of the quality parameter, from an invented original of 1,200,000 bytes. The byte counts are arithmetic on made-up numbers, chosen to exercise the search; they are not measurements of any image and say nothing about what your file will do. Target: 200 KB, which is 204,800 bytes.

    1. Encode 1: quality 95 → 1,088,850 bytes (1.04 MB) — over the target
    2. Encode 2: quality 48 → 317,213 bytes (309.8 KB) — over the target
    3. Encode 3: quality 24 → 124,033 bytes (121.1 KB) — fits
    4. Encode 4: quality 36 → 204,479 bytes (199.7 KB) — fits

    Verdict after 4 encodes: done, at quality 36 and 204,479 bytes — the largest attempt that fits. Against the invented original the row would read "83% smaller", computed by the same size-change function the tool uses, from those two byte counts and nothing else.

    Two shortcuts and one failure mode fall out of the same function. If the very first encode already fits — an invented result of 150,000 bytes at quality 95 against the same 200 KB target — the planner stops at once with 150,000 bytes, because there is no higher quality left to search. If an attempt lands just under the target, the search also stops rather than spend more encodes chasing the last few bytes: with a target of 100,000 bytes, an invented pair of attempts at 240,000 bytes and 97,000 bytes ends with the attempt at 97,000 bytes accepted. And when nothing fits, the planner probes downward until its bracket collapses at the floor of the range, then reports failure plainly. The same invented encoder asked for 40 KB (40,960 bytes) runs 5 encodes, the lowest at quality 6, and returns the verdict unreachable with the smallest result it found: 63,968 bytes at quality 6. The row offers that file and says the target was not met.

    What the plan decides for each kind of file

    Before any encode, the planning module is asked for a plan from the detected format to this tool's target for it — JPEG stays JPEG, WebP stays WebP, PNG goes to the lossy format chosen in the control above. Four plans, computed at build time:

    • JPEG to JPEG: flatten false, first-frame caveat false, output type image/jpeg. A JPEG has no transparency to lose and no frames to drop. holiday.jpg downloads as holiday-compressed.jpg, so the result cannot shadow the original in your downloads folder; Holiday.JPEG becomes Holiday.jpg, since the canonical extension differs from the one it arrived with.
    • WebP to WebP: flatten false — WebP output can hold transparency, so nothing is composited — but first-frame caveat true, because the container can be animated; the row shows the notice only when the detector actually found animation. banner.webp becomes banner-compressed.webp.
    • PNG to JPEG: flatten true onto #ffffff (the default; the color control above changes it), quality default 92 before the slider is applied, output type image/jpeg. Transparent pixels become that color, and the row says so. logo.png becomes logo.jpg.
    • PNG to WebP: flatten false, quality default 85, output type image/webp; transparency survives. logo.png becomes logo.webp.

    The PNG policy: convert honestly or not at all

    Browser-side "PNG compression" tools generally re-encode your PNG… as a PNG of nearly the same size, because PNG is already losslessly compressed and canvas encoders lack the palette-quantization tricks of dedicated optimizers. This tool refuses to stage that pantomime. Drop a PNG and it converts to a genuinely smaller lossy format of your choice — JPEG (transparency flattens onto your chosen background, stated on the row) or WebP (keeps transparency) — with the conversion named plainly in the result.

    The refusal is enforced by the planning module, not by a note in the interface. PNG's capability record says lossy false: there is no quality parameter to turn, so a quality slider aimed at PNG output would be a decoration. Asked at build time to plan a PNG-to-PNG encode with a quality attached, the module answers with an error — "This output format is lossless and has no quality setting." — and the tool is built so that this request is never made. What a PNG input gets instead is a real format change, labeled on the row as a conversion, with the output filename carrying the new extension so nothing pretends to be the original.

    The encoder, and what a re-encode strips

    This tool uses no vendored codec. The pixels are decoded by the browser with createImageBitmap and imageOrientation: 'from-image', so EXIF rotation is applied and a sideways phone photo comes out upright; drawn to a canvas, composited over the background color first only when the plan says so; and handed to the browser's own JPEG or WebP encoder with the quality parameter. The canvas WebP encoder has only a lossy mode — the format's lossless mode is not exposed through canvas — so any WebP input, however it was originally encoded, leaves as lossy WebP. The MozJPEG encoder lives on Compress JPEG; it is a different lane with its own page.

    A canvas re-encode strips all embedded metadata: EXIF (including GPS location, camera model and timestamps), color-profile tags, and text chunks. That is both a feature and a caveat — a compressed photo cannot leak where it was taken, and equally, copyright fields and ICC profiles are gone, so keep your originals. Orientation is applied during decoding, before the metadata is discarded, so uprightness survives even though the orientation tag does not. A re-encode is also another lossy pass over pixels that have already been through one; the tool measures what it produced in bytes, not what the pass removed.

    How every output is verified

    A download button means the output has already been checked. The produced bytes are sniffed with the same signature detector applied to inputs: if the browser quietly produced something other than the planned format — a PNG where WebP was requested, which happens when a browser cannot encode WebP — the row reports an error instead of handing over a mislabeled file. The blob is then re-decoded and its pixel width and height compared with the canvas that was encoded; a mismatch is an error, never a silent pass. The sizes shown are the output blob's true byte count against the input file's, and the percent on the row comes from those two numbers through the same function that produced "83% smaller" above. Two more illustrative pairs, again invented bytes: 410,000 bytes to 423,000 bytes reads "3.2% larger — keep your original"; 500,000 bytes to 499,900 bytes reads "less than 0.1% smaller". A result that is not smaller than the input gets a note recommending the original.

    What this tool cannot know

    The planner receives qualities and byte counts; it never sees pixels. It cannot tell whether a result looks acceptable, whether a photo was already compressed hard, or whether a particular quality is "enough" for a purpose — it knows only that one attempt was under the target and another was over. The detector reads a WebP's signature and animation flag, not whether it was lossless. No part of the pipeline measures how much detail a re-encode removed. For the same reason, this page states no expected savings, no recommended quality and no "best settings": the only numbers it shows are the ones measured from your file.

    Common misreadings

    • "Quality 92 means 92% of the original." It is the encoder's parameter, not a fraction of the file, its size or its detail. The planner's defaults differ by format for that reason.
    • "The search found the best quality for my target." It found the highest quality among the attempts it made that fits, within a budget of eight encodes and a stop band just under the target. A quality between two probes might also have fit.
    • "Reached the target, so the image is fine." Reaching the target is a statement about bytes. Nothing here judges appearance.
    • "It came out larger, so the tool failed." It means this encoder at this setting could not beat what the input already was. The row says to keep the original; that is the correct result, not an error.
    • "My PNG was compressed." It was converted to JPEG or WebP, and the row and the filename say so.
    • "The file is a .jpg, so it will be treated as JPEG." The bytes decide. A PNG named .jpg is handled as a PNG, with a notice.
    • "Compressing again will shrink it again." Each pass re-encodes already-encoded pixels; the measured result decides, and the row reports growth as plainly as shrinkage.

    When compression is the wrong lever

    Quality settings fight for kilobytes; dimensions fight for megabytes. A 4000-pixel photo destined for an 800-pixel slot should be resized first — then compressed. This tool never changes dimensions: the output is verified to decode at exactly the input's width and height. And a file that is already tightly encoded may simply not shrink: when the output is not smaller than your input, the row tells you to keep the original. Inputs are limited to 50 megapixels, 100 MB per file, and 40 files or 300 MB per selection, so a browser tab cannot be overwhelmed.

    Cut pixels before bytes with the Image Resizer. The Compress JPEG page keeps the same target-size planner on its MozJPEG lane; the AVIF lanes do not offer a target-size mode and say why on their pages. For format switches with full control, the directional pages — PNG to JPG, PNG to WebP, JPG to WebP — explain each trade-off in depth. The quality and compress-to-target guide goes deeper on the search itself.

    Frequently asked questions

    How does the "target size" mode work?

    You name a size in KB; the tool encodes at maximum quality, checks the real result, and binary-searches the quality setting — halving the search range each attempt, converging within eight encodes. You get the largest quality that fits under your target, with the search summarized on the file row.

    What if my target size is impossible?

    The tool tells you. If even minimum quality cannot fit your target, the row reports the smallest size actually achievable and offers that file — it will not silently hand you a file that misses the target, and it will not pretend. Try a smaller target only after resizing dimensions down.

    Why does this tool convert my PNGs instead of compressing them?

    Because "PNG compression" through a browser is mostly fiction: PNG is already losslessly compressed, and a canvas re-encode cannot apply the specialized quantization tricks real PNG optimizers use. Rather than fake it, this tool offers the honest route — converting the PNG to JPEG or WebP, which genuinely shrinks it — and says exactly that on the row.

    How much smaller will my image get?

    This page will not quote a percentage, because none is honest for every image. The result depends on your image’s content and how compressed it already was. Every row shows the actual input and output bytes — including the case where re-encoding gains nothing and keeping your original is best.

    Does compressing change my image’s dimensions?

    No — this tool only re-encodes pixels at the same width and height, verified by re-decoding the output. To shrink dimensions (often the far bigger lever on file size), use the Image Resizer, then compress.

    Why does the downloaded file have a different name?

    The output keeps your file’s base name and takes the target format’s canonical extension; when that would reproduce the original name exactly, a "-compressed" suffix is added so the download cannot overwrite the original. Computed by the same function the tool uses: holiday.jpg becomes holiday-compressed.jpg, Holiday.JPEG becomes Holiday.jpg, banner.webp becomes banner-compressed.webp, and a PNG converted to JPEG, logo.png, becomes logo.jpg.

    What happens to an animated WebP?

    The detector reads the WebP chunk list for the VP8X animation flag or an ANIM chunk before anything is decoded. If animation is found, the row says so up front: canvas decoding keeps only the first frame, so the compressed output is a still image of that frame. Still WebP files carry no such notice.

    Is anything uploaded?

    Nothing. All encoding attempts happen in your tab — even the target-size search, which may encode the image several times, costs zero network traffic. The methodology page shows how to verify with DevTools.

    Local processing: every encode attempt happens in your browser — nothing is transmitted, even in target-size mode. See the methodology page for the search algorithm and how to verify the no-upload claim.