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. 待补 重要思考:求给无向图定向使得其变为DAG的方案数

    今天比赛考到了,不会,丢了 100 分. rk2,380 -> rk15,280 别问为什么 T4 没过,因为不会 T2. 方法一 \(O(3^n)\) 令 \(f_S\) 为子集 \(S\) ...

  2. echarts实现pie自定义标签

    echarts实现pie自定义标签 一.环境 vue + echarts 实现饼图的自定义标签 二.实现效果 三.实现方式 import * as echarts from 'echarts'; ex ...

  3. HTML & CSS – Styling Scrollbar

    前言 Scrollbar 能 styling 的东西不多 (尤其是 IOS 基本上只能 display:none 而已),但有时候我们不得不 styling. 这里记入我自己在项目中修改过的 scro ...

  4. TypeScript 高级教程 – TypeScript 类型体操 (第三篇)

    前言 在 第一部 – 把 TypeScript 当强类型语言使用 和 第二部 – 把 TypeScript 当编程语言使用 后, 我们几乎已经把 TypeScript 的招数学完了. 第三部就要开始做 ...

  5. SQL Server – Concurrency 并发控制

    前言 以前写过相关的, 但这篇主要讲一下概念. 帮助理解 Entity Framework with MySQL 学习笔记一(乐观并发) Asp.net core 学习笔记 ( ef core tra ...

  6. MyBatis——案例——修改(修改全部字段,修改动态字段)

    修改-修改全部字段   1.编写接口方法:Mapper接口     参数:所有数据     结果:void(通过异常捕获判断成功修改与否)        int (表示sql语句影响的行数) /** ...

  7. Spring —— AOP(面向切面编程)

    AOP(Aspect Oriented Programming)简介 面向切面编程,一种编程范式,指导开发者如何组织程序结构 作用:在不惊动原始设计的基础上为其进行功能增强 Spring理念:无入侵式 ...

  8. Unreal Engine4 GPU崩溃或3D设备丢失的解决方案

    起因: Unreal Engine4 在渲染时报错GPU崩溃或3D设备丢失 解决办法: regedit  打开注册表 在以下2个路径下 新建 DWORD(32-bit) Value 命名为  TdrD ...

  9. P9118 [春季测试 2023] 幂次

    二诊前愉快的一次测试,关键是还有奶茶喝 第二题,本来直接暴力去重枚举可以的六十分的,但是.......花了30分钟优化剪纸,优化空间后,惨变35分. [春季测试 2023] 幂次 题目描述 小 Ω 在 ...

  10. vuex 基本代码规范 js 文件

    import Vue from "vue"; import Vuex from "vuex"; import { setItem, getItem } from ...