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算出:

\[Lh = 2 + \sum_{t=1}^{n} (17+m_t)
\]

其中

\[m_t=\sum_{1}^{16} L_i
\]

除了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长度与量化表个数也有类似的关系:

\[Pq = 2 + \sum_{t=1}^n (65 + 64 \times Pq(t))
\]

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文件格式的更多相关文章

  1. JPEG格式

    Jpg文件格式[参考] 微处理机中的存放顺序有正序(big endian)和逆序(little endian)之分.正序存放就是高字节存放在前低字节在后,而逆序存放就是低字节在前高字节在后.例如,十六 ...

  2. JPEG格式 介绍

    JPEG格式 jpeg是有损压缩格式, 将像素信息用jpeg保存成文件再读取出来,其中某些像素值会有少许变化.在保存时有个质量参数可在[0,100]之间选择,参数越大图片就越保真,但图片的体积也就越大 ...

  3. 图像JPEG格式介绍

    1 JPG格式介绍 JPEG (Joint PhotographicExperts GROUP)是由国际标准组织和国际电话电报咨询委员会为静态图像所建立的第一个国际数字图像压缩标准,也是至今一直在使用 ...

  4. 让阿里云的Centos,PHP组件 ImageMagick支持png和jpeg格式

    我们在Centos安装ImageMagick教程中讲述了如何安装ImageMagick,安装完毕之后发现程序并不支持png和jpeg格式的图片,但是这两种图片又是我们平时所常见的,所以我们还要进一步地 ...

  5. ecshop图片上传JPEG格式失败问题

    在根目录下找到includes文件目录,在其目录中找到cls_image.php打开并找到: $allow_file_types = '|GIF|JPG|JEPG|PNG|BMP|SWF|'; 此处J ...

  6. 嵌入式Linux基于framebuffer的jpeg格式本地LCD屏显示

    在基于Linux的视频监控采集系统中,摄像头采集到的一帧视频图像数据一般都是经过硬件自动压缩成jpeg格式的,然后再保存到摄像头设备的缓冲区.如果要把采集到的jpeg格式显示在本地LCD屏上,由于我们 ...

  7. 超图不支持JPEG格式的WMTS服务

    就目前面而言,超图不支持JPEG格式的WMTS服务,只支持PNG格式的. <本篇完>

  8. 一般源码安装添加的GD库 是不支持 jpeg 格式的图片的

    一般源码安装添加的GD库 是不支持 jpeg 格式的图片的,只支持如下格式 GD Support enabled GD Version bundled (2.0.34 compatible) GIF ...

  9. linux下将jpg,jpeg格式转为PDF

    1.安装imagemagick(用其中的convert)和gthumb     sudo apt-get install imagemagick gthumb 2.将tiff图片转换为png或jpeg ...

  10. Call to undefined function imagecreatefromjpeg() 让GD支持JPEG格式的图片扩展

    安装扩展支持jpeg格式: 第一步:首先下载文件: 版本v8: wget http://www.ijg.org/files/jpegsrc.v8b.tar.gz 版本v9: wget http://w ...

随机推荐

  1. 鸿蒙(HarmonyOS)常见的三种弹窗方式

    最近有一个想法,做一个针对鸿蒙官方API的工具箱项目,介绍常用的控件,以及在项目中如何使用,今天介绍Harmony中如何实现弹窗功能. 警告弹窗 警告弹窗是一个App中非常常用的弹窗,例如: 删除一条 ...

  2. SQL Server 语句日期格式查找方法

    1. SQL Server中,处理日期格式和查找特定日期格式方法示例 在SQL Server中,处理日期格式和查找特定日期格式的记录是一个常见的需求.SQL Server提供了多种函数和格式选项来处理 ...

  3. 借助 Flutter 顺畅地开发多平台应用

    Flutter 已于近期发布了 Flutter 2,Flutter 和 Dart 的产品总监 Tim Sneath 在 2021 年三月上旬举办的 Flutter Engage 活动中表示,Flutt ...

  4. 系统编程-进程-ps命令、进程调度、优先级翻转、进程状态

    1.    ps详解 ps  : 只列出当前用户的进程 ps -ef : e表示有效, f 表示全面, 所以是列出后台的所有有效进程. ps -ef | more :   列出后台所有的有效进程,并且 ...

  5. 音视频入门-8-ffmpeg小实验-v4l2 ubuntu取图、格式转换、编码成H264,ffplay观看

    1. getpic_transform_encode2h264.c #include <stdio.h> #include <string.h> #include <st ...

  6. SpringBoot 实现文件上传

    参考:Java springboot进阶教程 文件上传功能实现 后端代码编写 常见错误分析与解决 在 Service 业务层接口中增加一个上传文件的方法 因为文件并不是上传至数据库中,所以不需要编写 ...

  7. WebBrowser中打开新页面

    要求新打开的网页受控于WebBrowser 解决办法很简单,分两情况,一是在当前WebBrowser中打开新页面,二是在新Form中的WebBrowser中打开新页面: public Form1() ...

  8. Android 12 关机重启流程

    1. 关机流程 Android上层触发关机的入口很多,但最终几乎都是调用ShutdownThread.shutdown来实现.如下是一些常见的调用关机的点: StatusBarManagerServi ...

  9. amfe-flexible 包设置rem的基本值 vue 移动端适配方案

    下载 安装 :npm i -S amfe-flexible gw:GitHub - amfe/lib-flexible: 可伸缩布局方案 下载 2 个第三方包即可实现移动端适配 amfe-flexib ...

  10. 4. 说一下ts

    TypeScript 是微软基于JavaScript开发的开源编程语言,是js的超集,扩展了js语法并添加了静态类型,可以兼容js所有的运行平台: js 是弱类型语言 , ts 是强类型语言 : js ...