图片压缩工具

免费在线图片压缩工具,支持JPG、PNG、WebP等格式。智能压缩算法,保持高画质同时大幅减小文件体积,适用于网站优化、社交媒体分享等场景

上传图片

支持 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);
    }
}