前言
为什么同一张图片:
- 用JPEG保存只有200KB,PNG却要2MB?
- PNG支持透明背景,JPEG却不行?
- WebP比JPEG小30%,但老浏览器不支持?
今天从压缩原理 到实际选型,彻底搞懂各种图片格式。
一、图片格式分类
┌─────────────────────────────────────────────────────────────────────────────┐
│ 图片格式分类 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 图片格式 │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ 光栅图 │ │ 矢量图 │ │ RAW格式 │ │
│ │ (位图) │ │ │ │ (原始) │ │
│ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │ │
│ 由像素点组成 由数学公式描述 传感器原始数据 │
│ 放大会模糊 无限放大不失真 需后期处理 │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ JPEG PNG │ │ SVG EPS │ │ CR2 NEF │ │
│ │ GIF BMP │ │ AI PDF │ │ ARW DNG │ │
│ │ WebP AVIF │ │ │ │ │ │
│ │ HEIF TIFF │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ 【光栅图 vs 矢量图 - 放大效果】 │
│ ───────────────────────────────────────── │
│ │
│ 光栅图 (放大4倍): 矢量图 (放大4倍): │
│ │
│ 原图 放大后 原图 放大后 │
│ ┌──┐ ┌────────┐ ┌──┐ ┌────────┐ │
│ │●│ → │██░░ │ │◯│ → │ ◯ │ │
│ └──┘ │██░░ │ └──┘ │ │ │
│ │░░░░ │ │ ◯ │ │
│ │░░░░ │ │ │ │
│ └────────┘ └────────┘ │
│ 出现马赛克 依然清晰 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
二、压缩原理
┌─────────────────────────────────────────────────────────────────────────────┐
│ 有损压缩 vs 无损压缩 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 原始图片数据 │
│ │ │
│ ┌───────────────┴───────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ │
│ │ 无损压缩 │ │ 有损压缩 │ │
│ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │
│ 100%保留原始数据 丢弃人眼不敏感的信息 │
│ 解压后完全还原 解压后有质量损失 │
│ │ │ │
│ ▼ ▼ │
│ PNG, GIF, BMP JPEG, WebP, HEIF, AVIF │
│ TIFF(LZW) │
│ │ │ │
│ 文件较大 文件很小 │
│ 适合图标/截图 适合照片 │
│ │
│ 【人眼视觉特性 - 有损压缩的理论基础】 │
│ ───────────────────────────────────────── │
│ │
│ 1. 对亮度敏感,对色度不敏感 │
│ → JPEG: YCbCr色度下采样 (4:2:0) │
│ │
│ 2. 对低频信息敏感,对高频不敏感 │
│ → JPEG: DCT量化丢弃高频 │
│ │
│ 3. 对相对变化敏感,对绝对值不敏感 │
│ → 各种差分/预测编码 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
三、主流格式详解
1. JPEG
┌─────────────────────────────────────────────────────────────────────────────┐
│ JPEG 格式 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 扩展名: .jpg, .jpeg 诞生: 1992年 │
│ 类型: 有损压缩 颜色: 24位真彩色 │
│ 透明: ❌ 不支持 动画: ❌ 不支持 │
│ │
│ 【压缩流程】 │
│ ───────────────────────────────────────── │
│ │
│ RGB图像 → 色彩空间转换(YCbCr) → 色度下采样(4:2:0) │
│ → 分块(8×8) → DCT变换 → 量化(⭐信息丢失) → 熵编码 │
│ │
│ 【DCT变换示意】 │
│ ───────────────────────────────────────── │
│ │
│ 8×8像素块 → DCT → 频率系数矩阵 │
│ ┌─────────────────┐ │
│ │ DC 低频 ... │ 左上角: 平均亮度 │
│ │ 低频 中频 ... │ 往右下: 越高频 │
│ │ ... ... 高频 │ 高频: 细节/噪声 │
│ └─────────────────┘ │
│ ↓ 量化 │
│ 高频系数变为0 (丢弃!) │
│ │
│ 【质量参数影响】 │
│ ───────────────────────────────────────── │
│ │
│ ┌────────────┬────────────┬────────────┬────────────────────────────┐ │
│ │ 质量 │ 文件大小 │ 视觉质量 │ 适用场景 │ │
│ ├────────────┼────────────┼────────────┼────────────────────────────┤ │
│ │ 90-100 │ 大 │ 极好 │ 印刷、存档 │ │
│ │ 75-85 │ 中 │ 好 │ 网页高质量 │ │
│ │ 60-75 │ 较小 │ 可接受 │ 网页一般 ⭐ │ │
│ │ <50 │ 很小 │ 明显失真 │ 缩略图 │ │
│ └────────────┴────────────┴────────────┴────────────────────────────┘ │
│ │
│ 【JPEG缺陷】块效应、蚊式噪声、不适合文字/线条、不透明 │
│ 【适用】✅照片 ❌Logo ❌图标 ❌需要透明 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
2. PNG
┌─────────────────────────────────────────────────────────────────────────────┐
│ PNG 格式 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 扩展名: .png 诞生: 1996年 (替代GIF专利问题) │
│ 类型: 无损压缩 颜色: 最高48位+16位Alpha │
│ 透明: ✅ 支持(8位Alpha) 动画: ❌ (APNG支持) │
│ │
│ 【PNG类型】 │
│ ───────────────────────────────────────── │
│ │
│ PNG-8: 8位索引色 (256色),类似GIF,文件小 │
│ PNG-24: 24位真彩色 (RGB各8位),无透明 │
│ PNG-32: 32位 (RGB+8位Alpha),支持半透明 ⭐最常用 │
│ │
│ 【压缩原理】 │
│ ───────────────────────────────────────── │
│ │
│ 原始像素 → 滤波预测 → Deflate压缩 (LZ77+Huffman) │
│ │
│ 5种滤波器 (每行独立选择最优): │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ None: 不处理 │ │
│ │ Sub: 当前像素 - 左边像素 │ │
│ │ Up: 当前像素 - 上边像素 │ │
│ │ Avg: 当前像素 - (左+上)/2 │ │
│ │ Paeth: 当前像素 - 最近邻预测 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 预测后存储差值,差值往往接近0,压缩效率高 │
│ │
│ 【PNG vs JPEG 大小对比】 │
│ ───────────────────────────────────────── │
│ │
│ 照片类: PNG ≈ 5-10倍 JPEG │
│ 纯色/渐变: PNG ≈ JPEG 或更小 │
│ 文字/线条: PNG 质量更好,体积可能更小 │
│ │
│ 【适用】✅Logo ✅图标 ✅截图 ✅透明图 ❌大尺寸照片 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
3. GIF
┌─────────────────────────────────────────────────────────────────────────────┐
│ GIF 格式 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 扩展名: .gif 诞生: 1987年 │
│ 类型: 无损 (但限256色) 颜色: 8位索引色 (最多256色) │
│ 透明: ✅ (1位,全透明/不透明) 动画: ✅ 支持多帧 │
│ │
│ 【压缩: LZW算法】 │
│ ───────────────────────────────────────── │
│ │
│ 构建字典,用短码代替重复模式 │
│ "ABABABA..." → 字典{A=0,B=1,AB=2,BA=3,ABA=4...} │
│ 编码: 0,1,2,4... (越来越短) │
│ │
│ 【GIF动画结构】 │
│ ───────────────────────────────────────── │
│ │
│ Header → 全局调色板 → [帧1控制块+图像] → [帧2...] → 结束符 │
│ ↑ │
│ 延迟时间、透明色 │
│ │
│ 【GIF问题】 │
│ ───────────────────────────────────────── │
│ - 只有256色: 渐变出现色带 │
│ - 透明只有1位: 边缘锯齿,无半透明 │
│ - 动画文件大: 每帧独立存储 │
│ │
│ 【适用】✅简单动画 ✅表情包 ❌照片 ❌高质量动画(推荐WebP/视频) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
4. WebP (Google)
┌─────────────────────────────────────────────────────────────────────────────┐
│ WebP 格式 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 扩展名: .webp 诞生: 2010年 (Google) │
│ 类型: 有损/无损皆可 颜色: 24位RGB + 8位Alpha │
│ 透明: ✅ 支持 动画: ✅ 支持 │
│ │
│ 【技术来源】VP8视频编码的关键帧压缩 │
│ │
│ 【压缩效果】 │
│ ───────────────────────────────────────── │
│ │
│ vs JPEG: 有损模式小 25-34%,同等质量 │
│ vs PNG: 无损模式小 26% │
│ vs GIF: 动画小得多 (帧间压缩) │
│ │
│ 【WebP vs JPEG 技术差异】 │
│ ───────────────────────────────────────── │
│ │
│ JPEG: WebP: │
│ 固定8×8分块 自适应分块 (4×4到16×16) │
│ DCT变换 DCT + WHT变换 │
│ Huffman编码 算术编码 (更高效) │
│ 无帧间预测 有帧间预测 (动画) │
│ │
│ 【浏览器支持】2023年后基本可放心使用 │
│ ✅ Chrome, Firefox, Edge, Safari 14+, Opera │
│ ❌ IE (已停止维护) │
│ │
│ 【适用】✅网页图片(替代JPEG/PNG) ✅透明+高压缩 ✅替代GIF动画 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
5. AVIF
┌─────────────────────────────────────────────────────────────────────────────┐
│ AVIF 格式 (目前压缩率最高) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 扩展名: .avif 诞生: 2019年 │
│ 类型: 有损/无损 颜色: 最高12位HDR │
│ 透明: ✅ 支持 动画: ✅ 支持 │
│ │
│ 【技术来源】AV1视频编码的图像版本 │
│ 开放媒体联盟开发,Netflix/Google/Amazon/Apple参与,免版税 │
│ │
│ 【压缩效果】 │
│ ───────────────────────────────────────── │
│ │
│ vs JPEG: 小 50%+ │
│ vs WebP: 小 20-30% │
│ vs HEIF: 相当或更小 │
│ │
│ 【优势】压缩率最高、支持HDR、免版税、透明+动画 │
│ 【劣势】编码慢(比JPEG慢10-100倍)、浏览器支持较新、尺寸限制 │
│ │
│ 【浏览器支持】 │
│ ✅ Chrome 85+, Firefox 93+, Safari 16+, Edge │
│ │
│ 【适用】✅带宽敏感网站 ✅HDR图片 ✅新项目/移动端 ⚠️需JPEG降级 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
6. SVG (矢量图)
┌─────────────────────────────────────────────────────────────────────────────┐
│ SVG 格式 (矢量图) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 扩展名: .svg 类型: 矢量图 (XML文本) │
│ 缩放: 无限放大不失真 动画: ✅ (SMIL/CSS/JS) │
│ 交互: ✅ (DOM操作) │
│ │
│ 【SVG是数学描述,不是像素】 │
│ ───────────────────────────────────────── │
│ │
│ <svg width="100" height="100"> │
│ <circle cx="50" cy="50" r="40" fill="red"/> │
│ <rect x="10" y="10" width="30" height="30" fill="blue"/> │
│ <path d="M10 80 Q 95 10 180 80" stroke="black"/> │
│ <text x="50" y="50">Hello</text> │
│ </svg> │
│ │
│ 【文件大小对比】 │
│ ───────────────────────────────────────── │
│ │
│ 简单图标(32×32): PNG≈2KB, SVG≈500B ← SVG更小 │
│ 复杂插图: PNG≈50KB, SVG≈200KB ← PNG更小 │
│ 照片: 不适合用SVG │
│ │
│ 【适用】✅图标/Logo ✅数据图表 ✅响应式图形 ❌照片 ❌复杂艺术插图 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
7. 其他格式
┌─────────────────────────────────────────────────────────────────────────────┐
│ 其他图片格式 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ BMP: 无压缩,文件巨大,Windows系统内部使用 │
│ TIFF: 支持多种压缩/多页/高位深,印刷/医学/GIS专业领域 │
│ HEIF: 基于HEVC(H.265),iPhone默认格式,有专利问题 │
│ ICO: 可包含多尺寸,网站favicon/Windows图标 │
│ RAW: 相机原始数据(CR2/NEF/ARW/DNG),专业摄影后期 │
│ PSD: Photoshop文档,保留图层/蒙版/效果 │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
四、格式对比总表
┌─────────────────────────────────────────────────────────────────────────────┐
│ 图片格式对比总表 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────┬────────┬────────┬────────┬────────┬────────┬──────────────────┐ │
│ │ 格式 │ 压缩 │ 透明 │ 动画 │ 颜色 │ 大小 │ 最佳用途 │ │
│ ├────────┼────────┼────────┼────────┼────────┼────────┼──────────────────┤ │
│ │ JPEG │ 有损 │ ❌ │ ❌ │ 24bit │ 小 │ 照片 │ │
│ │ PNG │ 无损 │ ✅ │ ❌ │ 32bit │ 大 │ 图标/透明图 │ │
│ │ GIF │ 无损 │ ✅1bit │ ✅ │ 8bit │ 中 │ 简单动画 │ │
│ │ WebP │ 都有 │ ✅ │ ✅ │ 32bit │ 较小 │ 网页通用 ⭐ │ │
│ │ AVIF │ 都有 │ ✅ │ ✅ │ 36bit │ 最小 │ 高压缩/HDR ⭐ │ │
│ │ SVG │ 矢量 │ ✅ │ ✅ │ 无限 │ 视内容 │ 图标/图表 │ │
│ │ HEIF │ 有损 │ ✅ │ ✅ │ 30bit │ 小 │ 苹果设备 │ │
│ └────────┴────────┴────────┴────────┴────────┴────────┴──────────────────┘ │
│ │
│ 【压缩率排名】同质量下: AVIF < WebP < HEIF < JPEG << PNG(照片) │
│ 【兼容性排名】JPEG=PNG=GIF > SVG > WebP > AVIF > HEIF │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
五、选型决策树
┌─────────────────────────────────────────────────────────────────────────────┐
│ 图片格式选型指南 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 需要什么类型的图片? │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 是照片? 是图标? 是动画? │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ 需要透明? 是简单几何? 需要高质量? │
│ ┌──┴──┐ ┌──┴──┐ ┌──┴──┐ │
│ Yes No Yes No Yes No │
│ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ │
│ WebP JPEG SVG PNG-8 WebP GIF │
│ AVIF (Q75) PNG-32 动画 视频 │
│ PNG-32 │
│ │
│ 【具体场景推荐】 │
│ ───────────────────────────────────────── │
│ │
│ 网站照片 → WebP优先,JPEG降级 │
│ 电商商品图 → WebP/AVIF (节省带宽) │
│ 网站Logo → SVG (可缩放) 或 PNG │
│ 网站图标 → SVG 或 PNG-8 │
│ App启动图 → WebP │
│ 社交分享图 → JPEG/PNG (兼容性) │
│ 表情包 → GIF 或 WebP动画 │
│ 截图 → PNG (无损) │
│ 数据图表 → SVG (可交互) │
│ 印刷品 → TIFF/PNG (高分辨率) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
六、代码实现
格式检测 (Magic Number)
python
"""
图片格式检测 - 通过魔数识别
"""
from enum import Enum
class ImageFormat(Enum):
JPEG = "jpeg"
PNG = "png"
GIF = "gif"
BMP = "bmp"
WEBP = "webp"
AVIF = "avif"
HEIF = "heif"
SVG = "svg"
UNKNOWN = "unknown"
def detect_format(file_path: str) -> ImageFormat:
"""通过魔数检测图片格式"""
with open(file_path, 'rb') as f:
header = f.read(32)
# PNG: 89 50 4E 47 0D 0A 1A 0A
if header[:8] == b'\x89PNG\r\n\x1a\n':
return ImageFormat.PNG
# JPEG: FF D8 FF
if header[:3] == b'\xff\xd8\xff':
return ImageFormat.JPEG
# GIF: GIF87a 或 GIF89a
if header[:6] in (b'GIF87a', b'GIF89a'):
return ImageFormat.GIF
# BMP: BM
if header[:2] == b'BM':
return ImageFormat.BMP
# WebP: RIFF????WEBP
if header[:4] == b'RIFF' and header[8:12] == b'WEBP':
return ImageFormat.WEBP
# AVIF/HEIF: ftyp box
if header[4:8] == b'ftyp':
brand = header[8:12]
if brand in (b'avif', b'avis'):
return ImageFormat.AVIF
elif brand in (b'heic', b'heix', b'hevc', b'mif1'):
return ImageFormat.HEIF
# SVG (XML文本)
try:
text = header.decode('utf-8', errors='ignore').lower()
if '<svg' in text or '<?xml' in text:
return ImageFormat.SVG
except:
pass
return ImageFormat.UNKNOWN
# 魔数速查表
MAGIC_NUMBERS = """
格式 魔数 (十六进制) 说明
────────────────────────────────────────────────────
JPEG FF D8 FF 照片标准
PNG 89 50 4E 47 0D 0A 1A 0A 便携网络图形
GIF 47 49 46 38 39/37 61 动图格式
BMP 42 4D Windows位图
WebP 52 49 46 46 ... 57 45 42 50 Google格式
AVIF ... 66 74 79 70 61 76 69 66 AV1图像
"""
Web最佳实践
html
<!-- 现代Web图片最佳实践 -->
<!-- 1. 渐进增强: AVIF → WebP → JPEG -->
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="描述" loading="lazy">
</picture>
<!-- 2. 响应式图片 -->
<img
srcset="
small.jpg 480w,
medium.jpg 800w,
large.jpg 1200w"
sizes="
(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
800px"
src="medium.jpg"
alt="描述"
loading="lazy"
decoding="async">
<!-- 3. 高DPI屏幕 -->
<img
srcset="image.jpg 1x, image@2x.jpg 2x, image@3x.jpg 3x"
src="image.jpg"
alt="描述">
七、总结
┌─────────────────────────────────────────────────────────────────────────────┐
│ 图片格式选择总结 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 【核心原则】 │
│ ───────────────────────────────────────── │
│ │
│ 照片 → 有损压缩 (JPEG/WebP/AVIF) │
│ 图标 → 矢量或无损 (SVG/PNG) │
│ 透明 → PNG/WebP │
│ 新项目 → 优先WebP/AVIF │
│ │
│ 【快速选型】 │
│ ───────────────────────────────────────── │
│ │
│ 照片/风景/人像 → WebP > JPEG │
│ Logo/图标 → SVG > PNG-8 │
│ 需要透明 → WebP > PNG-32 │
│ 动画 → WebP动画 > GIF │
│ 截图/文字图 → PNG │
│ 印刷/存档 → TIFF / PNG │
│ 极致压缩 → AVIF │
│ │
│ 【Web最佳实践】 │
│ ───────────────────────────────────────── │
│ │
│ <picture> │
│ <source srcset="image.avif" type="image/avif"> │
│ <source srcset="image.webp" type="image/webp"> │
│ <img src="image.jpg" loading="lazy"> │
│ </picture> │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
一句话总结:
JPEG用于照片(有损但小),PNG用于图标/透明(无损但大),WebP是现代Web的最佳选择(兼顾压缩和特性),AVIF是未来(压缩最强),SVG用于可缩放矢量图。核心原则:照片选有损,图标选无损/矢量,透明选PNG/WebP,追求极致选AVIF。
参考资料:
- W3C PNG/SVG规范
- ITU-T JPEG标准
- Google WebP文档
- AOMedia AVIF规范
- MDN Web图片指南