# How Our Chrome Extension Compresses a Photo to a Target KB With Zero Permissions

**TL;DR:** Our Chrome extension [Compress Image to KB by editpdf.tools](https://chromewebstore.google.com/detail/compress-image-to-kb-by-e/komomnoldmjjidnobbmomnpmnhjelfdp) turns a JPG, PNG or WebP photo into a JPG under a target size, such as 50 KB. It runs a binary search over JPG quality with `canvas.toBlob`, and only shrinks the dimensions when quality alone cannot reach the target. It is Manifest V3, popup only, and asks for zero permissions, so the photo never leaves the user's computer. In our test, a 4.6 MB photo came out at 49.8 KB for a 50 KB target.

## What problem does the extension solve?

Online application forms often set a maximum file size for photos and signatures, for example 20 KB, 50 KB or 100 KB. A phone photo is usually several MB. The user does not care about quality settings or pixel sizes. They care about one number: the KB limit on the form.

So the input is a target size, and the job is to return the clearest JPG that fits under it. That gives a clear order of preference:

1. If the file is already a JPG under the target, return it untouched.
2. Otherwise keep the full dimensions and lower the JPG quality only as far as needed.
3. If quality alone cannot get there, shrink the dimensions and repeat.

## How do you compress an image to a target size in JavaScript?

Everything runs on an HTML canvas in the extension popup. We decode the image, draw it on a canvas, and encode it with `canvas.toBlob` using the `image/jpeg` type and a quality value between 0 and 1. The size of the returned `Blob` tells us whether the file fits.

PNG input needs one extra step. JPG has no transparency, so we fill the canvas with white before drawing. Transparent areas become a white background, which is also what most forms expect.

```js
function drawOnWhite(img, w, h) {
  const canvas = document.createElement('canvas');
  canvas.width = w;
  canvas.height = h;
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = '#ffffff';
  ctx.fillRect(0, 0, w, h);
  ctx.drawImage(img, 0, 0, w, h);
  return canvas;
}

function toJpeg(canvas, quality) {
  return new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', quality));
}
```

## Why use a binary search over JPG quality?

JPG file size grows with the quality value, so there is no need to try every value. We run a binary search between 0.05 and 0.95 for 7 steps. Each step encodes once, checks the size, and moves the lower or upper bound. We keep the highest quality that fits.

Seven encodes per dimension size is a small, fixed amount of work, and it lands close to the target.

```js
async function fitByQuality(canvas, targetBytes) {
  let lo = 0.05, hi = 0.95, fit = null;
  for (let i = 0; i < 7; i++) {
    const q = (lo + hi) / 2;
    const blob = await toJpeg(canvas, q);
    if (blob.size <= targetBytes) {
      fit = blob;   // fits: try a higher quality
      lo = q;
    } else {
      hi = q;       // too big: go lower
    }
  }
  return fit;       // null if nothing fit at this size
}
```

## What happens when lowering quality is not enough?

For a large photo and a small target, even the lowest quality in the range can be too big. In that case we scale the width and height to 85% of the previous step (a 15% reduction), redraw on white, and run the quality search again. We repeat until a blob fits. The real code also stops once the image gets too small to be useful.

```js
let w = img.naturalWidth, h = img.naturalHeight;
let result = await fitByQuality(drawOnWhite(img, w, h), targetBytes);
while (!result && w > 1 && h > 1) {
  w = Math.round(w * 0.85);
  h = Math.round(h * 0.85);
  result = await fitByQuality(drawOnWhite(img, w, h), targetBytes);
}
```

Trying quality first and dimensions second is a deliberate choice. Forms usually display photos small, and a full-size image at moderate quality tends to look cleaner than a tiny image at high quality. Only when quality cannot carry it do we give up pixels.

Before any of this, we check the input. If it is a JPG that is already under the target, we hand back the original file. Re-encoding would only lose quality for no gain.

## How close does it get to the target?

We ran one 4.6 MB photo through the extension with two targets:

| Input | Target | Output | Under target? |
|---|---|---|---|
| 4.6 MB photo | 50 KB | 49.8 KB | Yes |
| 4.6 MB photo | 20 KB | 18.4 KB | Yes |

Both results stayed under the target, and the 50 KB result landed very close to it, which is what the quality search is meant to do. Results depend on the photo.

## Why does the extension need no permissions?

The extension is Manifest V3 and popup only. The manifest declares no permissions and no host permissions. It does not need `activeTab`, `storage`, `downloads` or any site access:

- The user picks a file with a normal file input inside the popup.
- The canvas does the compression.
- The result is saved through a normal download link.

There is no network code either. We tested the popup and saw no external requests. Nothing is uploaded, nothing is stored, and no data is collected. That made the Chrome Web Store privacy section simple to fill in honestly, and users see no permission warning when they install.

## What are the limits?

- **JPG output only.** If a form needs PNG, this is not the right tool.
- **No HEIC inside the extension.** For iPhone photos, use the web version, [Compress Image to KB on editpdf.tools](https://editpdf.tools/compress-image-to-kb), which opens HEIC and also works in the browser without uploading the photo.
- **Very small targets can force small dimensions.** A few KB from a large photo may need many shrink steps, and the result can be too small to read. Always check the output.
- **PNG transparency becomes white.** That is a JPG limit.

## Frequently asked questions

### Does the extension upload my photo?

No. The photo is read and compressed inside the extension popup on your computer. The extension has no permissions and no network code.

### Which formats does it accept?

JPG, PNG and WebP as input. The output is always JPG.

### Can it compress a photo to exactly 50 KB?

It returns the clearest JPG it can find that is at or under 50 KB. In our test it produced 49.8 KB for a 50 KB target.

### Why not lower the dimensions first?

Small displays on forms make a full-size photo at moderate quality look cleaner than a small photo at high quality, so we only shrink when quality alone cannot reach the target.

### Is there a web version?

Yes. [Compress Image to KB](https://editpdf.tools/compress-image-to-kb) on [editpdf.tools](https://editpdf.tools/) does the same job in the browser and also accepts iPhone HEIC photos.

## Try it

The extension is free, with no signup and no watermark. Install it from the [Chrome Web Store](https://chromewebstore.google.com/detail/compress-image-to-kb-by-e/komomnoldmjjidnobbmomnpmnhjelfdp). If you try it, an honest review on the store helps a lot.

If you have ideas for smarter stopping rules, better quality steps or a cleaner way to handle tiny targets, tell us in the comments.

