ExactSize

Compress image size: the bytes come off the texture, not evenly

A compressor has exactly one knob for size: a byte target applied to the file as a whole. There is no per-region control, no way to say "leave the faces alone and take it out of the sky". Yet the damage is not spread evenly, because JPEG quantizes every 8 × 8 block of frequency coefficients on its own, and a block holding a smooth ramp has almost nothing to quantize while a block holding fine texture has a great deal. So the question this page answers is not "how small can the file get" — it is which parts of the picture pay for the reduction, and whether that changes as the target tightens. One 3000 × 2000 photograph, cut into 40 tiles, at five budgets from 20 KB to 500 KB, then eight of those tiles compressed on their own at four targets each.

Three numbers worth knowing before you compress an image

  • A quarter of the tiles carry about a third of the damage. The ten most textured of 40 tiles absorbed 40.01% of the total pixel error at 20 KB and 35.73% at 500 KB; the ten flattest absorbed 12.15% and 13.81%. Twenty-five times the byte budget — 20,385 to 511,019 bytes — moved the concentration by less than five points.
  • On this photograph, local texture predicted which tile paid — contrast did not. Spearman rank correlation between a tile's mean luma gradient and its error stayed at 0.962–0.981 across all five budgets. Contrast, measured as luma standard deviation, scored only 0.601–0.703, and the highest-contrast quartile had lower error than the third quartile at every budget. That ranking is this one picture's result: it has not been repeated on a second image.
  • The same 30 KB costs different quality on different content. Eight 375 × 400 crops, all 150,000 pixels, all targeted at 30 KB: quality ran from 99.53% on the flattest to 89.22% on the most textured. At 3 KB the flattest still kept every pixel (79.38% quality) while the most textured was down to 178 × 190, which is 33,820 pixels — 22.5% of what it started with.

One 689,299-byte photograph, 40 tiles, five budgets, then eight of those tiles at four targets each — 232 measured cells. Measured 6 November 2026.

How to read these numbers: every row is this site's own compressor driven through its published interface, one run per cell, each budget in a fresh tab. Bytes were read two ways — the tool's own report and a FileReader read of the returned blob — and agreed on all 37 rows; dimensions were read two ways (createImageBitmap and an image element) and agreed on all 37. The error column is the mean absolute per-channel difference on the 0–255 scale, measured against the source at its full 3000 × 2000 frame with each output upscaled back to that frame before comparison, so a tile that was scaled down is charged for the resampling blur as well as the quantization. Two independent decode paths agreed to within 0.047 levels on every tile of every budget. Whatever phrasing brought you here — compress image size, reduce image size, lower image size, shrink the file — the outcome lands in the same place: a byte target, and a map of what it costs.

The map: 40 tiles, five budgets

The source is a 3000 × 2000 night photograph, 689,299 bytes, already JPEG. It is cut into 8 columns × 5 rows of 375 × 400 px, 40 tiles of 150,000 pixels each. Each tile's own texture is measured on the source as the mean absolute luma difference between horizontally and vertically adjacent pixels — a local gradient, in levels per pixel. Then the whole photograph goes through the compressor at one target, and each tile's mean absolute RGB error is measured against the original. The five budgets return 20,385, 61,310, 102,087, 202,286 and 511,019 bytes — the same five values this site has recorded for this photograph in every session since 30 October, which is the cheapest available proof that the encoder is deterministic.

Tile (row, col) Texture
(mean |∇Y|)
Contrast
(std dev)
Error
20 KB
Error
60 KB
Error
100 KB
Error
200 KB
Error
500 KB
r4c05.79714.134.9813.6803.1062.4051.643
r4c15.65016.474.9043.5212.9962.3341.577
r2c65.26816.554.4473.3802.8622.2041.480
r2c75.26311.254.4043.3462.8562.2121.495
r1c44.87321.494.3733.2912.7932.0941.398
r2c14.78814.794.0112.9952.5311.9671.277
r2c24.65826.174.0503.0582.5861.9671.292
r3c14.48116.774.0343.0242.6232.0861.388
r1c64.47524.954.1753.1852.7332.0141.308
r2c54.39620.183.7582.9402.5551.9621.315
r4c24.10912.553.7882.8462.4801.9751.349
r3c04.02115.813.7422.8052.4731.9421.295
r1c73.93724.003.8392.8962.4881.9881.269
r2c43.90118.753.6502.8002.4221.8851.286
r1c53.31425.353.3732.5512.2411.6741.107
r2c33.10426.343.0922.3872.0961.5761.026
r3c22.98014.993.0232.3472.0681.5721.034
r4c42.6517.202.7452.1841.9981.6011.100
r1c32.53422.442.6562.1181.9091.5680.938
r4c32.2286.072.3461.9651.8081.4561.015
r1c22.08323.432.3041.9391.7821.4590.921
r1c02.05026.892.4281.9481.7921.3900.949
r4c51.9635.982.1581.8641.7721.4280.960
r1c11.92715.032.2501.8881.7561.3280.906
r2c01.7465.891.8791.6471.5801.2680.837
r3c71.68611.961.9511.7291.6361.3730.927
r4c71.6683.921.7461.6111.5881.3910.951
r4c61.5974.681.7451.6331.5781.2880.879
r3c61.34410.531.4631.3121.2931.0380.753
r3c51.2679.731.3801.2761.2651.0330.692
r3c41.2309.531.3561.2771.2511.0220.676
r3c31.2129.791.3361.2541.2451.0180.656
r0c71.1684.351.3321.3131.3111.0980.624
r0c11.04315.611.4721.3921.3271.0520.526
r0c61.0393.971.2231.2381.2321.1760.574
r0c41.0073.801.3961.3361.3231.1100.521
r0c50.9553.441.2701.2761.2681.1220.520
r0c00.92710.251.5701.4391.3950.9630.521
r0c30.8092.611.1821.2131.2131.0430.455
r0c20.7322.461.1901.2061.1980.9980.433

All 40 tiles, sorted by source texture. Error is mean absolute RGB difference on the 0–255 scale against the original at full frame. Texture is the mean absolute luma gradient of the source tile; contrast is its luma standard deviation. Same five output files in every column.

Read down the texture column and then across: the rows that start high stay high at every budget. Tile r4c0 has the most texture of the forty (5.797 levels per pixel) and the largest error at all five targets — 4.981, 3.680, 3.106, 2.405, 1.643. Tile r0c2 has the least (0.732) and sits near the bottom of every column — 1.190, 1.206, 1.198, 0.998, 0.433. Nothing in the middle of the table crosses over. That is what a rank correlation of 0.96–0.98 looks like when you print it as forty rows instead of a coefficient.

Two ways to measure detail, and only one of them ranked this damage

Standard deviation of luma is the obvious way to describe how busy a region is. On this photograph it was also the wrong one for this purpose. It scores a smooth sky gradient high, because the tone genuinely changes a lot from the top of the tile to the bottom — but a smooth ramp is nearly free for a DCT-based encoder, since its energy sits in a couple of low-frequency coefficients that survive coarse quantization. Local gradient scores the same ramp low, because adjacent pixels differ by a level or two.

The quartile split shows the gap directly. Grouping these 40 tiles into four groups of ten by source contrast puts the highest-contrast group fourth — and that group has lower error than the third group at every one of the five budgets. Grouping by texture puts the groups in the order this picture's error column actually has.

Quartile by contrast Contrast range Mean texture Error 20 KB Error 100 KB Error 500 KB Identical px at 500 KB
1 (flattest) 2.46–5.98 1.268 1.512 1.406 0.675 41.32%
2 6.07–12.55 2.192 2.234 1.723 0.918 28.76%
3 14.13–18.75 3.986 3.651 2.416 1.241 19.00%
4 (highest contrast) 20.18–26.89 3.542 3.405 2.298 1.152 23.54%

Tiles grouped into four groups of ten by source luma standard deviation. The fourth group has the highest contrast but not the highest error — the third group does, at every budget, because its mean local gradient (3.986) is higher than the fourth group's (3.542).

Everything in this section is one photograph, measured once. The texture ranking is what this picture's error column looks like; whether a second picture would rank its own tiles by gradient at the same 0.96–0.98 has not been tested here, and this page does not claim it. What the measurement does support is narrower: on a night photograph with a smooth sky at the top and fine detail along the bottom, contrast ranked these 40 tiles worse than local gradient did. A sunset over water or a gravel path would be a separate experiment — a reasonable next one, not a result.

The concentration is a property of the picture, not the budget

The obvious expectation is that a tighter budget hurts everything and therefore flattens the map, and that a generous budget lets the encoder be gentle everywhere and flattens it the other way. Neither happens. The ten most-textured tiles hold 40.01% of the total error at 20 KB, 37.22% at 60 KB, 35.24% at 100 KB, 34.28% at 200 KB and 35.73% at 500 KB. The ten flattest hold 12.15%, 14.58%, 16.06%, 16.71% and 13.81%. Both series drift by a few points and neither trends to uniformity.

The ratio between the worst and best tile tells the same story with less arithmetic: 4.21× at 20 KB, 3.05× at 60 KB, 2.59× at 100 KB, 2.50× at 200 KB, 3.79× at 500 KB. The order of the tiles never changes; only the multiplier breathes. And the overall error falls hard — 2.701 to 0.997 mean levels, a 63.1% reduction for 25.07× the bytes — while the shape of where that error sits stays put.

That is worth stating plainly, because it inverts the usual advice. "Compress harder and quality drops everywhere" is not what the map shows. Compressing harder drops quality mostly in the same places it was already dropping, which means the visible result of a tight target is not uniform mush but a picture whose busy regions have gone soft while its quiet regions still look untouched. On this photograph, if a viewer complains that one part of the image looks bad after compression, the tile table is a fair reconstruction of why.

Same target, same pixel count, different content

The tile map measures the damage a shared budget does. The second experiment asks the question a person actually has: if I hand this tool a piece of a picture and ask for 30 KB, what do I get? Eight of the forty tiles were cut out losslessly as PNG — 375 × 400, 150,000 pixels each, no generation loss — and each was compressed on its own at 3, 6, 12 and 30 KB.

Tile (row, col) Texture Quality @ 3 KB Size @ 3 KB Quality @ 6 KB Size @ 6 KB Quality @ 12 KB Size @ 12 KB Quality @ 30 KB Size @ 30 KB
0,20.73279.38%full88.28%full94.38%full99.53%full
0,61.03976.09%full85.47%full93.44%full99.06%full
3,61.34468.12%full81.25%full91.09%full98.13%full
4,51.96343.28%full73.28%full87.34%full96.25%full
3,22.98040.47%272 × 29056.41%full81.25%full95.31%full
4,24.10940.47%214 × 22840.47%360 × 38472.34%full93.44%full
2,14.78840.47%214 × 22840.47%352 × 37672.34%full93.44%full
4,05.79740.47%178 × 19040.47%288 × 30757.34%full89.22%full

Eight 375 × 400 crops, each 150,000 pixels, each cut losslessly from the same photograph and compressed separately at four targets. "Full" means the output kept all 375 × 400 pixels; any other entry is the scaled output size. Quality is the tool's own quality setting for the winning encode.

The 30 KB column is the cleanest single result on this page: identical target, identical pixel count, and a quality range of 10.31 points, ordered exactly by texture. The flattest crop came back at 99.53% quality with an error of 0.049 levels — visually indistinguishable from the source, and it used 30,190 of its 30,720-byte allowance to do it. The most textured crop, same 150,000 pixels, same 30 KB, landed at 89.22%.

The 3 KB column shows the floor arriving at different places. Four crops still kept every pixel at 3 KB, with quality from 79.38% down to 43.28%. From the fifth crop onward the tool ran out of quality room and started cutting pixels instead: 272 × 290, then 214 × 228 twice, then 178 × 190. Same instruction, same input size, four different outcomes, because the instruction is a byte count and the content is not the same.

Where each content type stops keeping its pixels

The tool has a hard quality floor at 40.47%. Below that it stops paying quality and starts paying pixels, which is the same boundary the 200 KB page found for the whole photograph and the JPEG size reducer page found from the channel side. What the crop sweep adds is the per-content arrival time:

  • Texture 0.732 and 1.039: never reached the floor, not even at 3 KB — 79.38% and 76.09% quality with all 150,000 pixels intact.
  • Texture 1.344: never reached the floor either; 68.12% quality at 3 KB, full frame.
  • Texture 1.963: hit the floor exactly at 3 KB — 43.28%, still full frame.
  • Texture 2.980: crossed between 3 KB and 6 KB. At 3 KB it held the floor at 272 × 290 (78,880 pixels, 52.6% of the original count); at 6 KB it was back to full frame at 56.41%.
  • Texture 4.109 and 4.788: crossed at 6 KB — 360 × 384 (92.2%) and 352 × 376 (88.2%), both at the floor.
  • Texture 5.797: crossed at 6 KB, down to 288 × 307 (58.9%), and at 3 KB down to 178 × 190 (22.5%). Full frame only returned at 12 KB, and then at 57.34% quality.

In allowance per pixel, a 3 KB target on 150,000 pixels is 0.0205 B/px and a 30 KB target is 0.2048 B/px — a tenfold spread in budget for the same pixel count. The whole photograph, at its five budgets, runs 0.00340 to 0.08517 B/px, a wider range because scaling a 6-megapixel frame down buys far more than scaling a small crop down.

Nothing comes back untouched

One assumption worth killing: that flat areas are free. Not one of the 40 tiles came back with every pixel identical, at any of the five budgets — 0 out of 40, including the flattest tile at 500 KB. What is true is that flat areas are mostly free at pixel level rather than tile level: at 500 KB, 28.15% of all pixels in the frame were bit-identical to the source, and inside the flattest quartile 41.32% were. At 20 KB that global share collapses to 4.02%, and inside the flattest quartile to 7.18%.

So the honest version of "flat regions survive compression" is: about two in five pixels of a flat region come back exactly, not the whole region. The rest move by a level or two, which is invisible but measurable, and it is why the error column never reaches zero anywhere on the map.

What this means when you reduce image size

The practical consequence for anyone trying to reduce image size is that the target you pick is not a quality setting — it is a budget, and in this photograph the content decides the exchange rate. A 30 KB target on a screenshot of text and a 30 KB target on a photograph of foliage would not be the same instruction, though this page measured one photograph and not that comparison. The measured spread here is 10.31 quality points between the flattest and busiest eighth of one image; what a second subject would do has not been run.

The second consequence is that the compressor has no way to protect a region you care about. A portrait with a busy background would, on the pattern this photograph shows, lose more absolute detail from the background than from the face — but that is an expectation drawn from one landscape, not something measured here: this page ran one photograph and it contains no face. If the face is what matters, the lever that does not depend on that open question is a crop — remove the busy region and the budget stops being spent on it. That is a content decision, not an encoder setting, and the encoder cannot make it for you.

How to lower image size without guessing

Because on this photograph the map was set by the picture rather than by the budget, the procedure that does not depend on guessing is: pick a target, run it, look at the result, adjust once. Guessing a quality percentage is strictly worse than guessing a byte target, since the byte target is the thing your upload form actually enforces. Two measured rules shorten the loop.

First, above 40.47% quality the tool pays quality and keeps pixels; below it, pixels start going. For a 6-megapixel frame that switch sits at 200 KB, which is the number the KB ladder and the 200 KB page both land on. Second, a file that comes back without scaling and with the tool's verdict reading "quality 100%" has essentially not been degraded — the flattest crop at 30 KB did exactly that, its internal quality setting 99.53%, so if the verdict says the target was met without scaling, there is nothing further to tune.

A photo size reducer is a budget allocator

Calling the tool a photo size reducer describes what it does to the file, not what it does to the picture. What it does to the picture is allocate a byte budget across 8 × 8 blocks, and the allocation is not negotiable from outside. The 40-tile table is that allocation made visible: 34–40% of the total damage in a quarter of the frame, and the same quarter every time, whatever the budget.

If you want a smaller file with no allocation at all — no block gets more or fewer bytes, no pixel changes — the lossless route is a different mechanism entirely, and the PNG size reducer page measures it at 18–36% smaller with every pixel identical by hash. If the file must stay JPEG, allocation is unavoidable and the only choice is how big the budget is.

An image quality reducer, read from the other side

Read the tile table backwards and it becomes a guide to spending bytes where they buy something. Going from 500 KB to 200 KB on the whole photograph costs 308,733 bytes and moves global error from 0.997 to 1.552 levels; the tiles that absorb that change are the textured ones, and the flat ones barely register it — their quartile error moves from 0.675 to 1.192 while the third quartile moves from 1.241 to 1.878. If you are choosing between two targets and the picture is mostly smooth, the cheaper target is genuinely close to the expensive one. If the picture is mostly texture, it is not.

Compress image size online, in the tab

This is an online compressor in the literal sense — it runs in a browser tab — but nothing is uploaded. The photograph is decoded, re-encoded and returned inside the page. That is also why the numbers reproduce: the five whole-frame budgets returned 20,385, 61,310, 102,087, 202,286 and 511,019 bytes, byte-identical to this site's runs on the same photograph in October and early November, and the 30 KB crop runs repeated exactly (30,190 bytes, error 0.049) when the sweep was re-executed. A compressor you can re-run is a compressor you can check, and every cell above is one run deep in a browser anyone can open.

How to compress an image with the map in mind

  1. Decide whether the target is a limit or a preference. If a form enforces 100 KB, the target is fixed and the only variable is how the loss distributes. If you are choosing freely, the 40.47% floor is where quality stops buying anything and pixels start going instead.
  2. Look at where the texture is before you look at the number. A mostly smooth image will hit a small target with most pixels untouched — the flattest crop here kept all 150,000 pixels at 3 KB. A textured image will not, and no target setting changes that.
  3. If one region matters more, crop first. The encoder spends its budget in proportion to local detail, so removing a busy background is the only way to stop paying for it. Cropping is a content decision the tool cannot make.
  4. Run once at the final target and stop. The tool is deterministic — the same input at the same target returns the same bytes — so a second pass at the same target returns the identical file, which the second-pass page measured at 0 ms of encoder time.
  5. If the output must be smaller and stay JPEG, accept the pixel regime. Below the floor the tool scales, and the scaling is uniform: at 20 KB the whole 6-megapixel frame became 968 × 646, which is 625,328 pixels, or 10.4% of the original pixel count.

Questions this page gets

Does compressing an image take bytes evenly from the whole picture?

No. The ten most textured of 40 tiles absorbed 40.01% of the total pixel error at a 20 KB target and 35.73% at 500 KB; the ten flattest absorbed 12.15% and 13.81%. Twenty-five times the byte budget barely moved the concentration, because the encoder quantizes each 8 × 8 block on its own and a smooth block has little to quantize.

Why does the same target size give different quality on different pictures?

Because the target is a byte count, not a quality level. Eight 375 × 400 crops, all 150,000 pixels, all compressed to 30 KB, came back at quality settings from 89.22% to 99.53% — a 10.31-point spread set by how much texture each crop held. At 3 KB the flat crops still kept all 150,000 pixels while the most textured one was cut to 178 × 190, or 33,820 pixels.

Which measure of detail ranked where the damage landed on this photograph?

Local gradient, not contrast — on this one image. Spearman rank correlation between a tile's mean absolute luma gradient and its measured error was 0.981 at 20 KB, 0.977 at 60 KB, 0.974 at 100 KB, 0.962 at 200 KB and 0.980 at 500 KB. Contrast measured as luma standard deviation scored 0.703, 0.688, 0.681, 0.601 and 0.610 — and the highest-contrast quartile had lower error than the third quartile at every budget, because a smooth tonal ramp has high contrast and almost no texture. The ranking is a result for this photograph only; a second image has not been run.

At what file size does the compressor stop lowering quality and start shrinking the picture?

At the 40.47% quality floor, and the byte target where that floor is reached depends on content. For the whole 6-megapixel photograph the floor arrived at 100 KB and below — 2482 × 1655 at 100 KB, 968 × 646 at 20 KB. For single 150,000-pixel crops it arrived anywhere from below 3 KB (flat content, 79.38% quality still) to 12 KB (the most textured crop, 57.34% quality at full frame).

Is the image uploaded to a server when I compress it?

No. Decoding, re-encoding and the byte-target search all happen inside the tab. Every number on this page came from the same in-browser compressor you can run yourself, and no request carrying image data leaves the machine.

Can I compress an image to an exact size like 30 KB?

You can set an exact target and the tool returns a file at or under it — the 30 KB runs here returned 30,190, 30,575 and 29,922 bytes on different content. What it cannot promise is that the same target costs the same quality everywhere: the same 30 KB cost 99.53% on a flat crop and 89.22% on the most textured one.

Where the numbers come from. All figures measured on 6 November 2026 with Chrome 157.0.8103.38 (headless, driven over the DevTools protocol) on Windows 11, using this site's compressor through its published interface. Experiment one: one 3000 × 2000 photograph, 689,299 bytes, cut into 8 × 5 tiles of 375 × 400 px, five targets (20, 60, 100, 200, 500 KB), one run per target in a fresh tab, per-tile error measured against the source at full frame with each output upscaled back to 3000 × 2000. Experiment two: eight of those tiles re-cut losslessly as PNG and compressed separately at 3, 6, 12 and 30 KB — 32 cells. Output bytes agreed between the tool's report and a FileReader read on all 37 rows; dimensions agreed between the report and createImageBitmap on all 37; two decode paths agreed to within 0.047 levels per tile. One of the 32 crop cells returned "Compression failed in this browser" on its first attempt and produced a normal result on the immediate retry, so that message is treated as transient rather than as a content limit — it is not reported as a finding. One photograph and one photograph only: every correlation and every concentration figure on this page is a property of this single picture's texture distribution. The 0.96–0.98 rank correlation has not been re-measured on a second image, so it is reported as what happened here, not as a rule about image compression in general; a subject with a different mix of smooth and busy regions would move both the correlations and the concentration figures, and this page does not say by how much.

Read these alongside: the KB ladder puts six single-pass budgets in one page; 200 KB is where quality stops and pixels start for a 6-megapixel frame; the JPEG size reducer splits the same damage by channel; the second-pass page measures what one extra encode costs; the image quality reducer measures the marginal cost of each quality step from q=0.95 to q=0.05; WebP is what the same bytes buy in another format; and the PNG size reducer removes bytes without touching a pixel.