Quality parameters and compress-to-target

Every converter and compressor lane that writes JPEG, WebP or AVIF — the directional pages, the Image Compressor, Compress JPEG and Image to PDF, which re-encodes each page as JPEG before embedding it — exposes one number called quality, and two of those lanes add a second control: a target file size. The one lossy re-encode without a slider is the Image Resizer, which writes a JPEG or WebP input back to its own format at the capability table's default. This guide explains what the engine does with both controls. Every figure below was computed at build time by the planning module the tools run on your files; none measures a real photograph and none is a recommendation, because the planner cannot see your image and neither can this page. The other guides are listed at /guides/.

One number, two scales

Inside the engine, quality runs from zero to one: the scale the browser's canvas encoder takes, so the scale the planning module stores and the compress-to-target search brackets over. The two self-hosted encoders — MozJPEG on the Compress JPEG lane, libavif with aom for AVIF output — take a whole number from 0 to 100 instead. The tool-page sliders use the same whole-number scale; the tool pages set their slider bounds to 5 and 95, the search planner's default range (its conversion range tops out higher, at maximum quality). The bridge is one function, encoderQualityPercent: refuse a non-finite input, clamp into the engine's range, scale onto 0–100 and round to the nearest whole number. On illustrative inputs the rounding shows — an engine quality of 0.876 becomes 88, 0.874 becomes 87 — and so does the clamp: an illustrative 1.7 becomes 100, −0.2 becomes 0.

Where each default comes from

A default is the quality planConversion records when no override is passed. It is what the Image Resizer passes, since it has no slider, and where the directional converter pages start their sliders. The Image Compressor and Image to PDF are the exceptions: each starts its slider at its own position and always passes the slider's reading. The capability table lists one default per output format, and the MozJPEG lane carries its own:

Output Takes a quality parameter Engine default (zero to one) Default on the encoder scale (0–100)
PNG via canvas no — lossless none none
JPEG via canvas yes 0.92 92
WebP via canvas yes 0.85 85
AVIF via libavif + aom yes 0.5 50
JPEG via MozJPEG (Compress JPEG) yes 0.75 75

The JPEG and WebP values are the capability table's defaults for the browser encoder. The AVIF value is libavif's own default on the encoder's 0–100 scale, stored by the engine as 0.5 and mapped to 50. The Compress JPEG value is MozJPEG's own default, 75, and that lane turns progressive scan order on by default. PNG has no number because it is lossless; the planner records its quality as null. WebP sits in the lossy column because the engine's capability table records it as lossy — the canvas path it uses produces lossy WebP and takes a quality parameter.

What the number is not

The quality value is not a percentage of anything about your file: not the fraction of detail kept, not the fraction of bytes kept, not a score the result will earn. It is an instruction to one particular encoder, and the engine's own notes say that AVIF quality lives on its own scale. This guide therefore makes no quality recommendations. The planner sees formats, numbers and byte counts, never pixels, and it refuses rather than guesses: asked for JPEG at an illustrative quality of 1.2 it replies "Quality must be between 0.05 and 1."; asked for PNG output with any quality at all, "This output format is lossless and has no quality setting."; asked to search toward a target of zero bytes, "Enter a target size greater than zero.". Those are the engine's own messages, rendered at build time.

"Make this fit under 200 KB" cannot be solved by arithmetic: no formula maps a quality setting to a byte count for an image not yet encoded. The site solves it by measurement. planCompression is a pure function: given the target in bytes and the encodes made so far — each recorded as the quality used and the bytes it produced — it returns one of three steps. Encode names the next quality to try; the client encodes once, measures the blob, appends the attempt and asks again. Done hands back the largest attempt that fits under the target. Unreachable hands back the smallest attempt made, because nothing it tried fit and it can go no lower. Between calls the planner brackets — the highest quality known to fit on one side, the lowest known to overshoot on the other, the midpoint as the next probe — and stops when an attempt lands within a narrow band just under the target, when the bracket is too narrow to split, or when the attempt budget is spent; the methodology page states the bound as convergence within eight encodes. The first probe is always the top of the range, 95 on the slider — what the methodology page calls maximum quality, meaning the top of the search range — and no probe goes below the floor of 5: handed an overshoot at an illustrative engine quality of 0.08, the planner clamps its next probe to 0.05 rather than halving further.

This page drives the real planner against an invented curve from quality to byte count. The curve comes from no image and the byte counts below measure nothing; only the quality sequence and the verdicts are the planner's. Target: 204,800 bytes (200 KB).

Attempt Quality (engine) Quality (slider) Invented bytes Against the target
1 0.95 95 612,475 overshoots
2 0.475 48 213,119 overshoots
3 0.237 24 113,140 fits
4 0.356 36 154,774 fits
5 0.415 42 181,613 fits
6 0.445 45 196,835 fits

After 6 attempts the planner returned done with the attempt at engine quality 0.445 — slider 45 — and 196,835 bytes; measured against the target by the function the result row uses, that attempt reads "3.9% smaller". Notice the two phases: while nothing has fit, each probe halves the lowest overshooting quality toward the floor; once one fits, every later probe is the midpoint of the bracket. The accepted result is the largest attempt that fit, not the last one made.

When the target cannot be reached

The same invented curve against a target of 61,440 bytes (60 KB) never fits, so the planner keeps halving toward the floor:

Attempt Quality (engine) Quality (slider) Invented bytes Against the target
1 0.95 95 612,475 overshoots
2 0.475 48 213,119 overshoots
3 0.237 24 113,140 overshoots
4 0.118 12 88,215 overshoots
5 0.059 6 82,054 overshoots

After 5 attempts the lowest overshoot sat at engine quality 0.059, and the bracket left between it and the floor of 0.05 was too narrow for the planner to split, so it returned unreachable and named the smallest attempt: 82,054 bytes. The tool page reports the smallest attempt and offers that file. The lever that remains is dimensions, the subject of Resizing math.

When the first encode already fits

Against a target of 1,048,576 bytes (1024 KB) the first probe, at engine quality 0.95, produced 612,475 invented bytes and already fit. The planner returned done after 1 attempt rather than searching above the ceiling of its range, because there is nothing above it to search. A generous target is a one-encode job, and the row reports the top-of-range quality.

Which lanes offer the search

The search is a property of a lane. The canvas-encoded Image Compressor offers it for JPEG and WebP output. The MozJPEG lane declares targetSizeSearch as available, so Compress JPEG offers it too. The AVIF lane declares it unavailable, so JPG to AVIF and PNG to AVIF offer the quality slider only. Wherever the search is offered, every probe is a full encode in your browser, and none is transmitted. Every one of those encodes, slider or search, is a re-encode from the canvas's decoded pixels, which strips all embedded metadata — EXIF (including GPS location, camera model and timestamps), colour-profile tags, and text chunks — so keep your original; orientation is applied during decoding, before the metadata is discarded. The metadata guide lists what goes and what stays.

PNG inputs are converted, and labelled

The methodology page is blunt: PNG inputs are never "PNG-compressed", because a canvas cannot honestly do that. The capability table is where the rule comes from — PNG is lossless, its quality is null, and there is no parameter for a search to move. So the Image Compressor converts a PNG to the lossy format you choose and labels the conversion on the row. The plan for PNG to JPEG sets needsBackgroundFlatten to true with a default background of #ffffff, because JPEG cannot carry transparency; the plan for PNG to WebP sets it to false. The filename follows the target — on invented filenames, logo.png becomes logo.jpg or logo.webp — while a JPEG compressed back to JPEG gains a suffix so the download cannot shadow the original. The engine's outputFilename takes that suffix as an argument, and both compressor clients pass -compressed: holiday.jpg becomes holiday-compressed.jpg. The flattening rule has its own guide, Transparency and flattening; the directional page PNG to JPG puts the background control beside the quality slider, while PNG to WebP has no colour picker because its plan sets needsBackgroundFlatten to false and never flattens.

Reading the result row

Whatever mode produced the file, the row reports the input blob's true byte count, the output blob's true byte count, and a percent change computed from those two numbers by describeSizeChange. On invented byte counts, and only as arithmetic: an original of 745,000 bytes against the 196,835-byte result of the worked search reads "74% smaller"; 150,000 bytes growing to 158,400 reads "5.6% larger — keep your original"; 1,000,000 bytes falling to 999,700 reads "less than 0.1% smaller"; an unchanged count reads "same size". The growth case matters most: a result can come out larger, and when it does the row says so and tells you to keep your original. The site publishes no blanket compression percentages anywhere, because no percentage is true for every image — the figures in this paragraph are the function's formatting rules applied to numbers this page made up, not a forecast.

Common misreadings

  • "Quality 92 keeps 92% of the image." It keeps whatever the encoder's decisions at parameter 92 keep; the number is an input, not a measurement of the output.
  • "The search found the best quality." It found the largest fitting encode by byte count — the attempt with the most bytes that still fit under the target — within an attempt budget. The planner does label that attempt best, but the word means "most bytes under the target", not a judgement about how the image looks.
  • "Target mode compresses harder." It encodes at whatever quality the bracket lands on — higher than the slider default when the target is generous; the one-attempt case above ended at the top of the range.
  • "Unreachable means the tool failed." The file cannot get that small by quality alone; the smallest attempt is offered, labelled, and the remaining lever is pixel dimensions.

Frequently asked questions

Is the quality number a percentage of the original file size?

No. It is an encoder parameter on the 0–100 scale that the engine derives from its own zero-to-one scale by scaling and rounding. It says nothing about how many bytes the result will have; the only size figures the site shows are the measured byte counts of your own input and output.

Why do the lanes start at different quality values?

The canvas lanes draw their default from the capability table, which is the quality the planner records when no override is passed: 92 for canvas JPEG and 85 for canvas WebP, and 50 for AVIF because that is libavif’s own default. The Compress JPEG lane is separate: its 75 is the MozJPEG lane’s own constant, which the planner does not consult. The directional converter pages start their sliders at the table default; the Image Resizer passes it because it has no slider; the Image Compressor and Image to PDF start their sliders at their own position and always pass the slider’s reading. None of them is a judgement about your image.

How does the target-size mode decide which quality to try next?

It keeps a list of the encodes made so far, each with its quality and its measured bytes. It brackets between the highest quality known to fit under the target and the lowest known to overshoot, tries the midpoint once something has fit — until then it halves the lowest overshooting quality, never below its floor — and stops when an attempt lands close enough under the target, when the bracket collapses, or when the attempt budget runs out. The methodology page states the bound: the search converges within eight encodes.

What happens if the target is smaller than the file can get?

The planner returns an “unreachable” verdict when nothing has fit and either an attempt at its minimum quality overshoots, the bracket above that minimum is too narrow to split, or the attempt budget runs out — the worked 60 KB search above ends by the second route. The tool then reports the smallest size it actually produced and offers that file, instead of handing you a file that misses the target or claiming success. Reducing dimensions with the Image Resizer is the lever that remains.

Why does a PNG I drop on the compressor come back as a JPG or WebP?

Because PNG is lossless and has no quality parameter — asking the planner for one is an error, not a slider. The compressor converts the PNG to the lossy format you choose and labels the conversion on the row. JPEG output flattens transparency onto the background color you pick (the planner sets that flag for PNG to JPEG); WebP output keeps it.

Can the tool tell me how the result will look?

No, and this guide does not either. The planner sees formats, numbers and byte counts, never pixels, so the page makes no visual-quality claims. What the tool can do is verify: the output is sniffed with the same format detector used on inputs and re-decoded to confirm its dimensions before the download button appears.

Local processing: every quality encode and every probe of a target-size search runs inside your browser. Files are decoded, converted, and verified entirely in your browser and never transmitted — see the methodology page for the search algorithm and how to verify the no-upload claim yourself.