Image Compressor - Compress PNG, JPG & WebP Online
Compress images while maintaining quality. Reduce PNG, JPG, and WebP file sizes with before/after comparison — no upload, 100% in your browser.
Frequently Asked Questions
What is image compression and why do I need it?
Image compression reduces the file size of images by removing unnecessary data or applying mathematical algorithms that encode the image more efficiently. For web development, compressed images lead to faster page load times, lower bandwidth consumption, better Core Web Vitals scores, and improved SEO rankings. A typical 5MB DSLR photo can be compressed to under 500KB with minimal visual quality loss.
How do I use this image compressor tool?
1. Drag and drop your images onto the upload area (or click to browse files). 2. Adjust the quality slider (default is 80%, which is a good balance). 3. Optionally set max width/height to resize images. 4. Click "Compress" on individual images or "Compress All" for batch processing. 5. Preview the before/after comparison in the Compare tab. 6. Download individual images or use "Download All (ZIP)" for a ZIP archive.
Is my image data safe? Are images uploaded to a server?
Your images are 100% safe and never leave your browser. All compression is performed client-side using the HTML5 Canvas API and OffscreenCanvas. No image data is transmitted to any server, making this tool completely private. You can even use it offline after the page loads. This differentiates us from server-based tools like TinyPNG.
What is the difference between lossy and lossless compression?
Lossy compression (JPEG, WebP) permanently removes some image data to achieve smaller file sizes. At quality settings of 70-90%, the visual difference is typically imperceptible. Lossless compression (PNG) preserves all image data exactly, resulting in larger files but perfect quality. JPEG and WebP use lossy compression by default; PNG is always lossless when using the Canvas API.
Which image format should I use: JPEG, PNG, or WebP?
JPEG is best for photographs and complex images with many colors and gradients (does not support transparency). PNG is best for graphics, icons, screenshots, and images with text or sharp edges (supports transparency, larger file sizes). WebP is a modern format that is generally 25-35% smaller than JPEG at equivalent quality, supports both lossy and lossless compression and transparency, and is recommended for web use with 95%+ global browser support.
Why did my PNG file get larger after compression?
The Canvas API produces lossless PNG output, which may differ from optimized PNG encoders (like OptiPNG or pngquant). If the original PNG was already well-optimized, re-encoding through Canvas may produce a slightly larger file. To reduce PNG size, try resizing the image to smaller dimensions.
What is the maximum file size and resolution supported?
This tool supports images up to 50MB per file and resolutions up to 16384 x 16384 pixels (the Canvas API limit in most browsers). For very high-resolution images, consider using the resize option to reduce dimensions first, which will also speed up compression. On mobile devices, the maximum resolution may be lower due to memory constraints.
Can I compress multiple images at once?
Yes, batch processing supports up to 20 images simultaneously. You can set a global quality level for all images. After compression, use "Download All (ZIP)" to download all compressed images in a single ZIP file.
Code Examples
// Client-side image compression using Canvas API
async function compressImage(file, quality = 0.8) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// Determine output type (use WebP if supported, fallback to JPEG)
const outputType = file.type === 'image/png' ? 'image/png' : 'image/webp';
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error('Compression failed'));
return;
}
resolve({
blob,
originalSize: file.size,
compressedSize: blob.size,
reductionPercent: Math.round((1 - blob.size / file.size) * 100),
});
},
outputType,
outputType === 'image/png' ? undefined : quality
);
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error('Failed to load image'));
};
img.src = url;
});
}
// Compress with resize
async function compressAndResize(file, maxWidth, maxHeight, quality = 0.8) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
let { width, height } = img;
// Calculate new dimensions maintaining aspect ratio
if (maxWidth && width > maxWidth) {
height = Math.round((height * maxWidth) / width);
width = maxWidth;
}
if (maxHeight && height > maxHeight) {
width = Math.round((width * maxHeight) / height);
height = maxHeight;
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error('Compression failed'));
return;
}
resolve({
blob,
originalSize: file.size,
compressedSize: blob.size,
width,
height,
reductionPercent: Math.round((1 - blob.size / file.size) * 100),
});
},
'image/jpeg',
quality
);
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error('Failed to load image'));
};
img.src = url;
});
}
// Batch compression
async function compressBatch(files, quality = 0.8) {
const results = [];
for (const file of files) {
try {
const result = await compressImage(file, quality);
results.push({ filename: file.name, ...result });
} catch (error) {
results.push({ filename: file.name, error: error.message });
}
}
return results;
}
// Usage
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const files = Array.from(e.target.files);
const results = await compressBatch(files, 0.8);
results.forEach((result) => {
if (result.error) {
console.error(`${result.filename}: ${result.error}`);
} else {
console.log(
`${result.filename}: ${result.originalSize} -> ${result.compressedSize} (${result.reductionPercent}% reduction)`
);
}
});
});