JPEG格式研究——(2)JPEG文件格式
JPEG文件除了图像数据之外,还保存了与图片相关的各种信息,这些信息通过不同类型的TAG存储在文件中。
TAG
JPEG通过TAG标记压缩书记之外的信息。所有的TAG都包含一个TAG类型,TAG类型大小为两个字节,位于一个TAG的最前面。TAG类型的第一个字节一定为0xFF
以下是部分常见的TAG类型
| TAG类型 | 数值 | 备注 |
|---|---|---|
| SOF0 ~ SOF3 SOF5 ~ SOF7 SOF8 ~ SOF11 SOF13 ~ SOF15 |
FF C0 ~ FF C3 FF C5 ~ FF C7 FF C8 ~ FF CB FF CD ~ FF CF |
不同的编码模式对应不同的SOF,详见JPEG标准Table B.1。本文以常见的SOF0为研究对象 |
| DHT | FF C4 | Define Huffman table(s),定义了解码所需的哈夫曼表 |
| RSTm | FF D0 ~ FF D7 | 遇到时重置DC系数,数字会递增,具体含义不清楚 |
| SOI | FF D8 | Start of Image,表示图像文件的开始 |
| EOI | FF D9 | End of Image,表示图像文件结束 |
| SOS | FF DA | Start of scan,表示这一个TAG后就是压缩的图像数据,记录了DHT、DQT与图像不同部分的对应关系 |
| DQT | FF DB | Define quantization table(s),定义了解码所需的量化表 |
| APP0 ~ APP15 | FF E0 ~ FF EF | 应用保存的图片相关信息(如相机信息等) |

压缩数据中也是存在TAG的,虽然大部分TAG都在文件开头,但是也有少部分是例外。如EOI就在文件的末尾,RSTm会出现在压缩数据当中。
那么问题来了,如果压缩数据中有一个字节本身就是0xFF怎么办?JPEG的做法是在0xFF后面再加一个字节0x00,用于表示这不是一个TAG。
因为不知道解码需要哪些TAG,我在尝试写JPEG解码器的时候耗费了大量的时间在研究TAG上。总结出对于常见的JPEG图片解码需要的TAG:
1.SOI和EOI:用于确定文件的开头和结尾
2.DQT和DHT:保存了解码时需要用到的哈夫曼表和量化表
3.SOS:保存了图片不同部分的需要用哪个哈夫曼表
4.SOF:图片的长和宽、采样精度等、使用哪个量化表都保存在SOF中
5.RST:部分图片存在RST,遇到RST时要重置DC系数才能得到正确的图像
哈夫曼表与量化表
这里有个小坑,我原先一直以为DQT和DHT都是一个TAG对应一个表,后来发现一个TAG可以不只一个表
哈夫曼表
哈夫曼表的存储格式如下:

| 名称 | 长度(bit) | 备注 |
|---|---|---|
| \(Lh\) | 16 | 表示这一个TAG的长度(包括TAG类型的两个字节) |
| \(Tc\) | 4 | Table class,0=DC表,1=AC表 |
| \(Th\) | 4 | Huffman table destination identifier,表示该哈夫曼表的id |
| \(L_i\) | 8 | 表示这一长度的编码个数 |
| \(V_{i,j}\) | 8 | 表示编码前的原始数据 |
一个DHT中的哈夫曼表个数可以通过长度Lh算出:
\]
其中
\]
除了TAG类型和Lh一个TAG只有一个外,其余的都是每个哈夫曼表都有的。
Th之后是一个长度为16字节的数组,分别对应长度从1bit到16bit的编码个数。
再之后存的是各个编码对应的原始数据(以字节为单位)。JPEG采用的范式哈夫曼编码,可以这些信息推导出数据编码前后的对应关系。
量化表
DQT的结构与DHT结构相似,比DHT还稍微简单一些

| 名称 | 长度(bit) | 备注 |
|---|---|---|
| Lq | 16 | 与Lh意义相同,表示这一TAG的长度 |
| Pq | 4 | 量化表的精度,0=8bit,1=16bit |
| Pq | 4 | 量化表的id |
| Qk | 8 | 量化表中的数据 |
量化表大小固定为8x8,也就是一个表有64个数,DQT长度与量化表个数也有类似的关系:
\]
SOF
SOF(Start of Frame) TAG的结构如下:

| 名称 | 长度(bit) | 备注 |
|---|---|---|
| Lf | 16 | 这一TAG的长度 |
| P | 8 | 采样精度 |
| Y | 16 | 图片的高度 |
| X | 16 | 图片的宽度 |
| Nf | 4 | Component的个数 |
Component的结构如下:
| 名称 | 长度(bit) | 备注 |
|---|---|---|
| Ci | 8 | Compoenent的id |
| Hi | 4 | 水平缩放因子 |
| Vi | 4 | 垂直缩放因子 |
| Tqi | 8 | 对应的量化表id |
根据我的理解,这里的Component个数相当于色度分量的个数,比如RGB和YUV都是3,灰度图像则是1.
SOS

| 名称 | 长度(bit) | 备注 |
|---|---|---|
| Ls | 16 | 这一TAG的长度 |
| Ns | 8 | 一个scan内的component数量 |
| Ss | 8 | 没用 |
| Se | 8 | 没用 |
| Ah | 4 | 没用 |
| Al | 4 | 没用 |
Scan中还描述了这一Scan内不同Component中哈夫曼表和量化表的对应关系:
| 名称 | 长度(bit) | 备注 |
|---|---|---|
| Csi | 8 | 通过id选择Component |
| Tdi | 4 | 通过id选择DC哈夫曼表 |
| Tai | 4 | 通过id选择AC哈夫曼表 |
到这里JPEG解码所需要的几个重要TAG的结构就介绍完了,接下来就做好准备工作就可以开始解码了。
参考资料
JPEG解码系列博客:多媒体-编解码 - 随笔分类 - OnlyTime_唯有时光 - 博客园 (cnblogs.com)
JPEG标准:Microsoft Word - T081E.DOC (w3.org)
一个Rust写的JPEG解码器:MROS/jpeg_tutorial: 跟我寫 JPEG 解碼器 (Write a JPEG decoder with me) (github.com)
友情链接
我学习过程中写的JPEG图片查看器:Ryan1202/my-tiny-jpeg-viewer: A Tiny Jpeg Viewer (github.com)
JPEG格式研究——(2)JPEG文件格式的更多相关文章
- JPEG格式
Jpg文件格式[参考] 微处理机中的存放顺序有正序(big endian)和逆序(little endian)之分.正序存放就是高字节存放在前低字节在后,而逆序存放就是低字节在前高字节在后.例如,十六 ...
- JPEG格式 介绍
JPEG格式 jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化.在保存时有个质量参数可在[0,100]之间选择,参数越大图片就越保真,但图片的体积也就越大 ...
- 图像JPEG格式介绍
1 JPG格式介绍 JPEG (Joint PhotographicExperts GROUP)是由国际标准组织和国际电话电报咨询委员会为静态图像所建立的第一个国际数字图像压缩标准,也是至今一直在使用 ...
- 让阿里云的Centos,PHP组件 ImageMagick支持png和jpeg格式
我们在Centos安装ImageMagick教程中讲述了如何安装ImageMagick,安装完毕之后发现程序并不支持png和jpeg格式的图片,但是这两种图片又是我们平时所常见的,所以我们还要进一步地 ...
- ecshop图片上传JPEG格式失败问题
在根目录下找到includes文件目录,在其目录中找到cls_image.php打开并找到: $allow_file_types = '|GIF|JPG|JEPG|PNG|BMP|SWF|'; 此处J ...
- 嵌入式Linux基于framebuffer的jpeg格式本地LCD屏显示
在基于Linux的视频监控采集系统中,摄像头采集到的一帧视频图像数据一般都是经过硬件自动压缩成jpeg格式的,然后再保存到摄像头设备的缓冲区.如果要把采集到的jpeg格式显示在本地LCD屏上,由于我们 ...
- 超图不支持JPEG格式的WMTS服务
就目前面而言,超图不支持JPEG格式的WMTS服务,只支持PNG格式的. <本篇完>
- 一般源码安装添加的GD库 是不支持 jpeg 格式的图片的
一般源码安装添加的GD库 是不支持 jpeg 格式的图片的,只支持如下格式 GD Support enabled GD Version bundled (2.0.34 compatible) GIF ...
- linux下将jpg,jpeg格式转为PDF
1.安装imagemagick(用其中的convert)和gthumb sudo apt-get install imagemagick gthumb 2.将tiff图片转换为png或jpeg ...
- Call to undefined function imagecreatefromjpeg() 让GD支持JPEG格式的图片扩展
安装扩展支持jpeg格式: 第一步:首先下载文件: 版本v8: wget http://www.ijg.org/files/jpegsrc.v8b.tar.gz 版本v9: wget http://w ...
随机推荐
- 在 windows 上部署 django
环境 Django 4.1.7 python 3.11.2 Apache 2.4.46 1:安装配置 Apache 1.1:下载 Apache Apache官方下载链接 按照系统版本选择对应的,以下是 ...
- tarjan—算法的神(一)
本篇包含 tarjan 求强连通分量.边双连通分量.割点 部分, tarjan 求点双连通分量.桥(割边)在下一篇. 伟大的 Robert Tarjan 创造了众多被人们所熟知的算法及数据结构,最著名 ...
- Angular 18+ 高级教程 – 学以致用
前言 读这么多原理,到底为了什么?真实项目中真的会用得到吗? 你正在疑惑 "知识的力量" 吗? 本篇会给一个非常非常好的案例,让你感悟 -- 知识如何用于实战. 记住,我的目的是让 ...
- vue-i18n 8.28.2(完成)
https://kazupon.github.io/vue-i18n/zh/introduction.html 开始 如果使用模块系统 (例如通过 vue-cli),则需要导入 Vue 和 VueI1 ...
- 第6天:基础入门-抓包技术&HTTPS协议&APP&小程序&PC应用&WEB&转发联动
安装charles 到Windows本地: 安卓模拟器安装: 如果抓模拟器就要使用从远程主机,如果不是,则从所有进程 访问 谷歌浏览器安装证书: PC微信小程序代理抓取: 41:43 :如何将char ...
- 【问题解决】remote: parse error: Invalid numeric literal at line 1, column 20,解决思路
问题现象 某同事出现过同样的推送到git仓库报错的问题,报错信息详情如下: Delta compresion using up to 20 threads Compressing objects: 1 ...
- linux tracepoint增加
引入tracepoint的背景 当需要获取内核的debug信息时,通常你会通过以下printk的方式打印信息: void trace_func() { //-- printk("输出信息&q ...
- 2022年2月国产数据库排行榜:冠军宝座面临挑战,OceanBase 重返 TOP3
大家好!文章开始本是用"新春快乐!虎年吉祥!"和大家打个招呼,无奈时间过得太快而文章整理得很慢,眼看崭新的三月还有几天就到来,那就在这里祝屏幕前的你在三月比二月更优秀! 月初,20 ...
- C# webapi 跨域
#region 启用跨域访问 app.UseCors(builder => builder .AllowAnyMethod() .SetIsOriginAllowed(_ => true) ...
- 在 Kubernetes 中基于 StatefulSet 部署 MySQL(上)
大家好,我是老 Z! 本文实现了 MySQL 数据库在基于 KubeSphere 部署的 K8s 集群上的安装部署,部署方式采用了图形化这种形式.下一篇文章将会涉及 GitOps 的基础操作,部署过程 ...