DEV Community

harry
harry

Posted on

How I Built a Fast MB KB Image Compressor Using Pure JavaScript (No Backend Needed)

Most image compression tools upload your file to a server, which is slow and not always safe. I wanted something faster, simpler, and privacy-friendly — so I built a client-side MB to KB image compressor using only HTML, JavaScript, and the Canvas API.

This tool runs 100% in the browser, compresses images instantly, and never uploads anything to a server.

Live tool: https://mbtokbconverter.org/

💡 Why I Built This:

Many people struggle when they need to reduce image size — photo too big, website upload limit too small.

I kept hearing:

  • “My photo is 4 MB but I need 200 KB”
  • “Online compressors are slow”
  • “Why does it upload my file to a server?”

*So I created a simple JS tool that:
*

  • Compresses to a target size (KB)
  • Works offline
  • Doesn’t upload your image
  • Converts PNG → JPEG for better compression
  • Lets you resize images for better results

🔧 How It Works (High-Level)

  1. Load the image using FileReader
  2. Convert to a <canvas>
  3. Optionally resize width
  4. Run a binary search on JPEG quality until size ≤ target
  5. Generate a blob
  6. Provide a download link

Everything happens inside the browser.

📌 Core Code Snippets**

Read Image

function readFileAsDataURL(file){
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
Enter fullscreen mode Exit fullscreen mode

Draw to Canvas

function loadImage(src){
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = src;
  });
}
Enter fullscreen mode Exit fullscreen mode

Compression Logic (Binary Search)

async function compress(img, targetKB, maxWidth){
  const canvas = document.createElement("canvas");
  let w = img.width;
  let h = img.height;

  if(maxWidth > 0 && maxWidth < w){
    h = Math.round(h * (maxWidth / w));
    w = maxWidth;
  }

  canvas.width = w;
  canvas.height = h;
  const ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0, w, h);

  let low = 0.05;
  let high = 0.95;
  let best = null;
  const targetBytes = targetKB * 1024;

  for(let i=0; i<10; i++){
    const q = (low + high) / 2;
    const blob = await new Promise(res => canvas.toBlob(res, "image/jpeg", q));

    if(blob.size <= targetBytes){
      best = blob;
      low = q;
    } else {
      high = q;
    }
  }

  return best;
}
Enter fullscreen mode Exit fullscreen mode

🖥 Demo UI (HTML)

<input type="file" id="file" accept="image/*">
<input type="number" id="targetKb" value="100">
<input type="number" id="maxWidth" value="0">
<button id="compressBtn">Compress</button>
<button id="downloadBtn" disabled>Download</button>
Enter fullscreen mode Exit fullscreen mode

✔️ What I Learned

  • PNGs do not compress well → converting to JPEG helps
  • Some images need dimension resizing to reach very small sizes
  • Canvas compression varies between browsers
  • A binary-search approach is the fastest method

🔮 What’s Next?

I’m adding:

  • WebP output
  • Drag & drop support
  • Batch compression
  • Dark mode UI

If you want these features, tell me!

Top comments (0)