Image compressor

#online-compressor { max-width: 950px; margin: 20px auto; padding: 25px; background: #f3f6fb; border-radius: 15px; font-family: Arial, sans-serif; color: #1e293b; box-sizing: border-box; } #online-compressor * { box-sizing: border-box; } #online-compressor h2 { text-align: center; font-size: 27px; color: #173b70; margin-bottom: 10px; } #online-compressor .subtitle { text-align: center; color: #64748b; margin-bottom: 25px; line-height: 1.6; } #online-compressor .upload-area { border: 2px dashed #2563eb; padding: 30px 15px; border-radius: 12px; background: white; text-align: center; } #online-compressor input[type=file] { max-width: 100%; margin-top: 15px; } #online-compressor .section-title { font-size: 19px; font-weight: bold; margin: 23px 0 13px; color: #173b70; } #online-compressor .format-buttons { display: grid; grid-template-columns: repeat(3,1fr); gap: 12px; } #online-compressor button { padding: 14px 10px; border: none; border-radius: 8px; color: white; font-size: 15px; font-weight: bold; cursor: pointer; background: #2563eb; transition: .2s; } #online-compressor button:hover { filter: brightness(.9); transform: translateY(-2px); } #online-compressor button:disabled { opacity: .55; cursor: not-allowed; transform: none; } #online-compressor .jpg-btn { background: #2563eb; } #online-compressor .png-btn { background: #0f766e; } #online-compressor .gif-btn { background: #9333ea; } #online-compressor .quality-box { background: white; padding: 17px; margin-top: 18px; border-radius: 10px; } #online-compressor .quality-box label { font-weight: bold; } #online-compressor input[type=range] { width: 100%; margin: 15px 0; accent-color: #2563eb; } #online-compressor .preview-box { display: none; background: white; margin-top: 22px; padding: 18px; border-radius: 12px; text-align: center; } #online-compressor .preview-box img { max-width: 100%; max-height: 300px; object-fit: contain; margin: 10px auto; } #online-compressor .comparison { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 15px; } #online-compressor .comparison div { background: #f1f5f9; padding: 14px; border-radius: 8px; line-height: 1.8; } #online-compressor .download-btn { display: inline-block; margin-top: 16px; padding: 14px 25px; border-radius: 8px; background: #16a34a; color: white; text-decoration: none; font-weight: bold; } #online-compressor .status { text-align: center; margin-top: 16px; color: #2563eb; font-weight: bold; line-height: 1.6; } #online-compressor .note { margin-top: 20px; color: #64748b; font-size: 13px; line-height: 1.7; } @media(max-width:550px) { #online-compressor { padding: 14px; } #online-compressor h2 { font-size: 22px; } #online-compressor .format-buttons { grid-template-columns: 1fr; } #online-compressor .comparison { grid-template-columns: 1fr; } }

Online Image Compressor

Compress JPG, PNG and GIF images easily. Reduce image file size while preserving image quality.

Upload Your Image

Select JPG, PNG or GIF image from your device.

Select Compression Format
Higher quality usually means a larger file.

Compressed Image Preview

Compressed image preview
Original Image

-

Compressed Image

-

Download Compressed Image

Important: JPG compression is lossy. PNG compression uses lossless re-encoding where possible. GIF optimization preserves the original animation and frames. If compression cannot reduce file size, the tool will tell you. All processing takes place in your browser.

(function () { const root = document.getElementById("online-compressor"); const upload = root.querySelector("#oc-upload"); const status = root.querySelector("#oc-status"); const preview = root.querySelector("#oc-preview"); const result = root.querySelector("#oc-result"); const download = root.querySelector("#oc-download"); const quality = root.querySelector("#oc-quality"); const qualityValue = root.querySelector("#oc-quality-value"); let selectedFile = null; let originalURL = null; let resultURL = null; let originalName = "image"; quality.addEventListener("input", function () { qualityValue.textContent = this.value + "%"; }); upload.addEventListener("change", function () { const file = this.files[0]; if (!file) return; const allowed = [ "image/jpeg", "image/png", "image/gif" ]; if (!allowed.includes(file.type)) { status.textContent = "Please select a JPG, PNG or GIF image."; return; } selectedFile = file; originalName = file.name.replace(/\.[^.]+$/, "") || "image"; if (originalURL) URL.revokeObjectURL(originalURL); if (resultURL) URL.revokeObjectURL(resultURL); originalURL = URL.createObjectURL(file); preview.style.display = "none"; status.textContent = "Image uploaded successfully. Original size: " + formatSize(file.size); }); function formatSize(bytes) { if (bytes btn.disabled = busy); } function canvasFromImage(img) { const canvas = document.createElement("canvas"); canvas.width = img.naturalWidth; canvas.height = img.naturalHeight; const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); return canvas; } function canvasBlob(canvas, type, q) { return new Promise(resolve => { canvas.toBlob(resolve, type, q); }); } async function compressJPG() { const img = await loadImage(originalURL); const canvas = canvasFromImage(img); const blob = await canvasBlob( canvas, "image/jpeg", Number(quality.value) / 100 ); if (!blob) throw new Error("JPG compression failed."); return { blob, extension: "jpg", message: "JPG compression completed." }; } async function compressPNG() { const img = await loadImage(originalURL); const canvas = canvasFromImage(img); const blob = await canvasBlob( canvas, "image/png" ); if (!blob) throw new Error("PNG compression failed."); return { blob, extension: "png", message: "PNG lossless re-encoding completed." }; } async function compressGIF() { // Browser canvas conversion does not preserve GIF animation. // Therefore return the original GIF instead of damaging it. return { blob: selectedFile, extension: "gif", message: "Original animated GIF preserved. Browser-only processing " + "cannot optimize GIF animation without a dedicated GIF encoder." }; } function loadImage(url) { return new Promise((resolve,reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = () => reject( new Error("Unable to load the image.") ); img.src = url; }); } async function process(type) { if (!selectedFile) { status.textContent = "Please upload an image first."; return; } if (type === "jpg" && selectedFile.type !== "image/jpeg") { status.textContent = "Please upload a JPG image to use JPG compression."; return; } if (type === "png" && selectedFile.type !== "image/png") { status.textContent = "Please upload a PNG image to use PNG compression."; return; } if (type === "gif" && selectedFile.type !== "image/gif") { status.textContent = "Please upload a GIF image to use GIF compression."; return; } setBusy(true); status.textContent = "Processing image... Please wait."; try { let output; if (type === "jpg") output = await compressJPG(); if (type === "png") output = await compressPNG(); if (type === "gif") output = await compressGIF(); const blob = output.blob; if (resultURL) URL.revokeObjectURL(resultURL); resultURL = URL.createObjectURL(blob); result.src = resultURL; download.href = resultURL; download.download = originalName + "-compressed." + output.extension; const originalSize = selectedFile.size; const newSize = blob.size; root.querySelector("#oc-original-size").textContent = formatSize(originalSize); root.querySelector("#oc-compressed-size").textContent = formatSize(newSize); const difference = originalSize - newSize; const percentage = originalSize ? (difference / originalSize * 100).toFixed(2) : "0"; let savingsText; if (difference > 0) { savingsText = "File size reduced by " + percentage + "% (" + formatSize(difference) + ")."; } else if (difference === 0) { savingsText = "File size remained unchanged."; } else { savingsText = "Output file is larger than the original."; } root.querySelector("#oc-savings").textContent = savingsText + " " + output.message; preview.style.display = "block"; status.textContent = "Your image is ready."; } catch (error) { status.textContent = error.message || "Something went wrong. Please try again."; } finally { setBusy(false); } } root.querySelector("#oc-jpg") .addEventListener("click", () => process("jpg")); root.querySelector("#oc-png") .addEventListener("click", () => process("png")); root.querySelector("#oc-gif") .addEventListener("click", () => process("gif")); })();
Scroll to Top