原文地址: https://blog.csdn.net/u012837895/article/details/84434047
概念释义
不保证正确,只是个人的理解
- 一样的意思,都是表示Joint Photographic Experts Group开发的这套JPEG标准所描述的图片,只是早期DOS系统只支持3位扩展名,而Apple支持多位扩展名才有所区别。后面即使Windows同样支持多位扩展名也没有改变这个习惯。因为Windows用户更多,所以主流为jpg,但是像是.jpeg、.JPG和.JPEG都是可以的。
- 早期的JPEG格式只说明了图片如何压缩为字节流以及重新解码为图片的过程,但是没有说明这些字节是如何在任何特定的存储媒体上封存起来的。因此建立了相关的额外标准JFIF(JPEG File Interchange Format)。后来这个标准变为主流,现在所使用的JPEG文件基本都是符合JFIF标准的。
关于0xFF
从上面这句话可以看出,0xFF在JPEG文件中是十分重要。如果读取中出现了0xFF,根据后面的值有多种可能。
- 后面的值为0xFF,这时候视为一个0xFF看待,继续读取。
- 后面的值为0x00,这时候表示这个FF在数据流中,跳过。
- 其他能够表示marker的值,将其视为marker开头处理。
- 其他值,跳过。
整体格式
JPEG格式的大致顺序为:(不一定按这个顺序)
- SOI
- COM(为所欲为的区域,你要开多大开多大,要放什么就放什么)
- APP0
- [APPn]可选
- DQT
- SOF0
- DHT
- SOS
- 压缩数据
- EOI
JPEG中SOI和EOI中间为Frame
Frame的头包含了像素的位数,图像的宽和高等信息。Frame下有Scan
Scan的头包含每个扫描的分量数,分量ID,哈夫曼表等。Scan下有Segment和Restart,即压缩数据的基本单位。
在JPEG文件格式中使用Motorola格式而不是Intel格式,也就是说大端模式,高字节低地址,低字节高地址。
标签表
总表
缩写 | 字节码 | 名称 | 注释 |
---|---|---|---|
SOI | 0xFFD8 | Start of image | Baseline DCT-based JPEG所用的开头 |
SOF0 | 0xFFC0 | Start of Frame0 | Progressive DCT-based JPEG |
SOF2 | 0xFFC4 | Define Huffman Tables | 指定一个或多个哈夫曼表 |
DHT | 0xFFDB | Define Quantization Table | 指定量化表 |
DRI | 0xFFDD | Define Restart Interval | RST中的marker |
SOS | 0xFFDA | Start of Scan | Scan的开头 |
RSTn | 0xFFDn | Restart | DRImarker中插入r个块 |
APPn | 0xFFEn | Application-specific | Exif JPEG使用APP1,JFIF JPEG使用APP0 |
COM | 0xFFFE | Comment | 注释内容 (为所欲为的区域!!!) |
EOI | 0xFFD9 | End of Image | 图像的结束 |
表2 JPEG Start of Frame结构
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFC0 |
数据长度 | 2 bytes | SOF marker的长度,包含自身但不包含标记代码 |
精度 | 1 byte | 每个样本数据的位数,通常是8位 |
图像高度 | 2 bytes | 图像高度,单位是像素 |
图像宽度 | 2 bytes | 图像宽度,单位是像素 |
颜色分量数 | 1 bytes | 灰度级1,YCbCr或YIQ是3,CMYK是4 |
颜色分量信息 | 颜色分量数*3 | 每个颜色分量:1 byte分量ID; 1byte水平垂直采样因子(前4位为水平采样因子,后4位为垂直采样因子); 1byte当前分量使用的量化表ID |
表3 JPEG Start of Scan结构
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFDA |
数据长度 | 2 bytes | SOS marker的长度,包含自身但不包含标记代码 |
颜色分量数 | 1 byte | 灰度级1,YCbCr或YIQ是3,CMYK是4 |
颜色分量信息 | 颜色分量数*3 | 1byte的颜色分量id,1byte的直流/交流系数表号(高4位:直流分量所使用的哈夫曼树编号,低4位:交流分量使用的哈夫曼树的编号) |
压缩图像信息 | 3 bytes | |
1 bytes | 谱选择开始 固定为0x00 | |
1 byte | 谱选择结束 固定为0x3f | |
1 byte | 谱选择 在basic JPEG中固定为00 |
SOS紧跟着就是压缩图像信息
表4 JPEG APP0 应用保留标记0
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFE0 |
数据长度 | 2 bytes | APP0的长度,包含自身但不包含标记代码 |
标识符 identifier | 5 bytes | 固定的字符串"JFIF\0" |
版本号 | 2 bytes | 一般为0x0101或0x0102,表示1.1或1.2 |
像素单位 unit | 1 byte | 坐标单位,0为没有单位; 1 pixel/inch; 2pixel/inch |
水平像素数目 | 2 bytes | |
垂直像素数目 | 2 bytes | |
缩略图水平像素数目 | 1 byte | 如果为0则没有缩略图 |
缩略图垂直像素数目 | 1 byte | 同上 |
缩略图RGB位图 | 3n bytes | n = 缩略图水平像素数目*缩略图垂直像素数目,这是一个24bits/pixel的RGB位图 |
表5 APPn应用程序保留标记
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFE1-0xFFEF,n=1~15 |
数据长度 | 2 bytes | APPn的长度,包含自身但不包含标记代码 |
详细信息 | (length-2) bytes | 内容是应用特定的,比如Exif使用APP1来存放图片的metadata,Adobe Photoshop用APP1和APP13两个标记段分别存储了一副图像的副本。 |
表6 DQT 定义量化表
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFDB |
数据长度 | 2 bytes | DQT的长度,包含自身但不包含标记代码 |
量化表 | (length-2)bytes | 下面为子字段 |
精度及量化表ID | 1 byte | 高4位为精度,只有两个可选值:0表示8bits,1表示16bits;低4位为量化表ID,取值范围为0~3 |
表项 | 64*(精度+1)byte |
表7 DHT 定义哈夫曼表
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFC4 |
数据长度 | 2 bytes | DHT的长度,包含自身但不包含标记代码 |
哈夫曼表 | (length-2)bytes | 以下为哈夫曼表子字段 |
表ID和表类型 | 1 byte | 高4位:类型,只有两个值可选,0为DC直流,1为AC交流;低4位:哈夫曼表ID,注意DC表和AC表是分开编码的 |
不同位数的码字数量 | 16 byte | |
编码内容 | 上述16个不同位数的码字的数量和 |
哈夫曼表可以重复出现(一般出现4次)
表8 COM 定义注释表
字段名称 | 长度 | 注释 |
---|---|---|
标记代码 | 2 bytes | 固定值0xFFFE |
数据长度 | 2 bytes | COM的长度,包含自身但不包含标记代码 |
数据长度接着是自己分配的空间,你要在这里写什么都可以,,保存车牌号,车牌坐标,车坐标都行
我在一张普通的JPEG图片读入内存,添加了COM注释消息 128 bytes(0x80)