上传图片
支持 JPG、PNG、WebP 格式,最大 10MB
点击或拖拽图片到此处上传
支持 JPG、PNG、WebP 格式,最大 10MB
什么是图片压缩?
图片压缩是通过特定算法减少图片文件大小的技术,同时尽可能保持图片的视觉质量。图片压缩分为有损压缩和无损压缩两种方式。有损压缩会牺牲一定的图片质量来获得更小的文件体积,如JPG;无损压缩则可以完全还原原始图片,如PNG。
图片压缩的主要类型
- 有损压缩(Lossy Compression):通过删除部分图像数据来减小文件大小,压缩率高,但会损失一定的图像质量。常见格式:JPG、WebP
- 无损压缩(Lossless Compression):不丢失任何图像数据,可以完全还原原始图片,但压缩率相对较低。常见格式:PNG、GIF
- 有损+无损混合:结合两种方法,在保持一定质量的同时获得更好的压缩效果
图片压缩的应用场景
- 网站优化:压缩网站图片可以显著提升页面加载速度,改善用户体验
- 社交媒体:大多数社交平台都有文件大小限制,压缩可以上传更多内容
- 节省存储空间:压缩图片可以节省存储设备和云存储的容量
- 减少带宽成本:传输压缩后的图片可以减少网络流量和带宽成本
- 移动应用:压缩图片可以减少应用安装包大小,提高下载速度
图片格式的比较
| 格式 | 压缩类型 | 特点 | 适用场景 |
|---|---|---|---|
| JPEG/JPG | 有损 | 压缩率高,支持1600万色,不支持透明 | 照片、复杂图像 |
| PNG | 无损 | 支持透明通道,色彩丰富,文件较大 | Logo、图标、需要透明的图片 |
| WebP | 有损/无损 | 新一代格式,压缩率更高,支持透明和动画 | 现代Web应用,追求最佳压缩效果 |
| GIF | 无损 | 支持动画,最多256色 | 简单动画、图标 |
常见问题(FAQ)
Q: 图片压缩会影响画质吗?
A: 有损压缩会影响画质,但影响程度取决于压缩质量设置。较高的质量设置(80-90%)可以在显著减小文件体积的同时保持人眼难以察觉的差异。无损压缩则不会影响画质,但压缩率较低。
Q: 应该选择什么压缩质量?
A: 一般建议:
- 照片类图片:75-85%质量
- Logo/图标:85-95%质量(建议使用PNG)
- 网页图片:70-80%质量
- 打印用图片:90%以上质量
Q: JPG和PNG有什么区别?
A: JPG适用于照片和复杂图像,压缩率高但可能有质量损失,不支持透明背景;PNG适用于Logo、图标和需要透明背景的图片,无损压缩但文件较大。照片类建议用JPG,图标类建议用PNG。
Q: WebP格式有什么优势?
A: WebP是Google推出的新一代图片格式,相比JPG可减少25-35%的文件大小,相比PNG可减少26-80%的文件大小,同时保持相似的视觉质量。现代浏览器都支持WebP,推荐用于Web应用。
代码示例
JavaScript Canvas 图片压缩
// 使用 Canvas 压缩图片
function compressImage(file, quality = 0.8, format = 'image/jpeg') {
return new Promise((resolve, reject) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
canvas.toBlob((blob) => {
resolve({
blob: blob,
originalSize: file.size,
compressedSize: blob.size,
compressionRatio: ((1 - blob.size / file.size) * 100).toFixed(2)
});
}, format, quality);
};
img.onerror = reject;
img.src = URL.createObjectURL(file);
});
}
// 使用示例
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
const result = await compressImage(file, 0.7, 'image/jpeg');
console.log('原始大小:', (result.originalSize / 1024).toFixed(2) + ' KB');
console.log('压缩后大小:', (result.compressedSize / 1024).toFixed(2) + ' KB');
console.log('压缩率:', result.compressionRatio + '%');
// 下载压缩后的图片
const url = URL.createObjectURL(result.blob);
const a = document.createElement('a');
a.href = url;
a.download = 'compressed.' + (format === 'image/jpeg' ? 'jpg' : 'png');
a.click();
});
Python Pillow 图片压缩
from PIL import Image
import os
def compress_image(input_path, output_path, quality=85, format='JPEG'):
"""
使用 Pillow 压缩图片
:param input_path: 输入图片路径
:param output_path: 输出图片路径
:param quality: 压缩质量 1-100
:param format: 输出格式 (JPEG, PNG, WEBP)
"""
try:
# 打开图片
img = Image.open(input_path)
# 如果是RGBA且要保存为JPEG,需要转换为RGB
if img.mode == 'RGBA' and format.upper() == 'JPEG':
# 创建白色背景
background = Image.new('RGB', img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3]) # 使用alpha通道作为mask
img = background
# 保存并压缩
save_kwargs = {'optimize': True}
if format.upper() in ['JPEG', 'WEBP']:
save_kwargs['quality'] = quality
img.save(output_path, format=format, **save_kwargs)
# 获取文件大小
original_size = os.path.getsize(input_path)
compressed_size = os.path.getsize(output_path)
compression_ratio = (1 - compressed_size / original_size) * 100
print(f'原始大小: {original_size / 1024:.2f} KB')
print(f'压缩后大小: {compressed_size / 1024:.2f} KB')
print(f'压缩率: {compression_ratio:.2f}%')
return {
'original_size': original_size,
'compressed_size': compressed_size,
'compression_ratio': compression_ratio
}
except Exception as e:
print(f'压缩失败: {e}')
return None
# 使用示例
compress_image('input.jpg', 'output.jpg', quality=75, format='JPEG')
compress_image('input.png', 'output.png', format='PNG')
Node.js Sharp 图片压缩
const sharp = require('sharp');
const fs = require('fs');
async function compressImage(inputPath, outputPath, quality = 80) {
try {
// 获取原始文件大小
const stats = fs.statSync(inputPath);
const originalSize = stats.size;
// 使用 sharp 压缩图片
await sharp(inputPath)
.jpeg({
quality: quality,
progressive: true,
mozjpeg: true // 使用mozjpeg编码器获得更好的压缩率
})
.toFile(outputPath);
// 获取压缩后的文件大小
const compressedStats = fs.statSync(outputPath);
const compressedSize = compressedStats.size;
const compressionRatio = (1 - compressedSize / originalSize) * 100;
console.log('原始大小:', (originalSize / 1024).toFixed(2), 'KB');
console.log('压缩后大小:', (compressedSize / 1024).toFixed(2), 'KB');
console.log('压缩率:', compressionRatio.toFixed(2), '%');
return {
originalSize,
compressedSize,
compressionRatio
};
} catch (error) {
console.error('压缩失败:', error);
}
}
// 使用示例
compressImage('input.jpg', 'output.jpg', 75);
// PNG 压缩示例
async function compressPNG(inputPath, outputPath) {
await sharp(inputPath)
.png({
quality: 80,
compressionLevel: 9, // 0-9,9为最高压缩
adaptiveFiltering: true,
palette: true
})
.toFile(outputPath);
}
// WebP 压缩示例
async function compressWebP(inputPath, outputPath, quality = 80) {
await sharp(inputPath)
.webp({
quality: quality,
lossless: false,
nearLossless: false,
smartSubsample: true
})
.toFile(outputPath);
}
Java Thumbnails 图片压缩
import net.coobird.thumbnailator.Thumbnails;
import java.io.File;
import java.io.IOException;
public class ImageCompressor {
public static CompressionResult compressImage(
String inputPath,
String outputPath,
float quality
) throws IOException {
File inputFile = new File(inputPath);
File outputFile = new File(outputPath);
long originalSize = inputFile.length();
// 使用 Thumbnails 压缩图片
Thumbnails.of(inputPath)
.scale(1.0) // 保持原始尺寸
.outputQuality(quality) // 压缩质量 0.0-1.0
.outputFormat("jpg")
.toFile(outputPath);
long compressedSize = outputFile.length();
double compressionRatio = (1 - (double)compressedSize / originalSize) * 100;
System.out.println("原始大小: " + (originalSize / 1024.0) + " KB");
System.out.println("压缩后大小: " + (compressedSize / 1024.0) + " KB");
System.out.println("压缩率: " + String.format("%.2f", compressionRatio) + "%");
return new CompressionResult(originalSize, compressedSize, compressionRatio);
}
// 保持尺寸压缩
public static void compressKeepSize(String inputPath, String outputPath, float quality)
throws IOException {
Thumbnails.of(inputPath)
.scale(1.0f)
.outputQuality(quality)
.toFile(outputPath);
}
// 缩放尺寸并压缩
public static void resizeAndCompress(
String inputPath,
String outputPath,
int maxWidth,
float quality
) throws IOException {
Thumbnails.of(inputPath)
.width(maxWidth)
.outputQuality(quality)
.toFile(outputPath);
}
public static class CompressionResult {
public long originalSize;
public long compressedSize;
public double compressionRatio;
public CompressionResult(long originalSize, long compressedSize, double compressionRatio) {
this.originalSize = originalSize;
this.compressedSize = compressedSize;
this.compressionRatio = compressionRatio;
}
}
public static void main(String[] args) throws IOException {
compressImage("input.jpg", "output.jpg", 0.75f);
}
}