【转载】转载自http://www.cnblogs.com/leaven/archive/2010/04/06/1705846.html

JPEG压缩编码算法的主要计算步骤如下:

(0) 8*8分块。

(1) 正向离散余弦变换(FDCT)。

(2) 量化(quantization)。

(3) Z字形编码(zigzag scan)。

(4) 使用差分脉冲编码调制(DPCM)对直流系数(DC)进行编码。

(5) 使用行程长度编码(RLE)对交流系数(AC)进行编码。

(6) 熵编码。

一、JPEG文件格式介绍

JPEG文件使用的数据存储方式有多种。最常用的格式称为JPEG文件交换格式(JPEG File Interchange Format,JFIF)。而JPEG文件大体上可以分成两个部分:标记码(Tag)和压缩数据。

标记码由两个字节构成,其前一个字节是固定值0xFF,后一个字节则根据不同意义有不同数值。在每个标记码之前还可以添加数目不限的无意义的0xFF填充,也就说连续的多个0xFF可以被理解为一个0xFF,并表示一个标记码的开始。而在一个完整的两字节的标记码后,就是该标记码对应的压缩数据流,记录了关于文件的诸种信息。

常用的标记有SOIAPP0DQTSOF0DHTDRISOSEOI

注意,SOI等都是标记的名称。在文件中,标记码是以标记代码形式出现。例如SOI的标记代码为0xFFD8,即在JPEG文件中的如果出现数据0xFFD8,则表示此处为一个SOI标记。

SOI,Start of Image,图像开始

标记代码                                 2字节     固定值0xFFD8

APP0,Application,应用程序保留标记0

标记代码                                 2字节     固定值0xFFE0

包含9个具体字段:
 ① 数据长度                         2字节     ①~⑨9个字段的总长度
                                                            即不包括标记代码,但包括本字段
 ② 标识符                             5字节    固定值0x4A46494600,即字符串“JFIF0”
  ③ 版本号                             2字节    一般是0x0102,表示JFIF的版本号1.2
                                                            可能会有其他数值代表其他版本
 ④ X和Y的密度单位           1字节     只有三个值可选
                                                            0:无单位;1:点数/英寸;2:点数/厘米
 ⑤ X方向像素密度               2字节     取值范围未知
 ⑥ Y方向像素密度               2字节     取值范围未知   
  ⑦ 缩略图水平像素数目        1字节     取值范围未知
 ⑧ 缩略图垂直像素数目        1字节     取值范围未知
 ⑨ 缩略图RGB位图             长度可能是3的倍数           缩略图RGB位图数据

本标记段可以包含图像的一个微缩版本,存为24位的RGB像素。如果没有微缩图像(这种情况更常见),则字段⑦“缩略图水平像素数目”和字段⑧“缩略图垂直像素数目”的值均为0。

APPn,Application,应用程序保留标记n,其中n=1~15(任选)

标记代码                                 2字节     固定值0xFFE1~0xFFF

包含2个具体字段:
 ① 数据长度                         2字节     ①~②2个字段的总长度
                                                            即不包括标记代码,但包括本字段
 ② 详细信息            数据长度-2字节   内容不定

例如,Adobe Photoshop生成的JPEG图像中就用了APP1和APP13两个标记段分别存储了一幅图像的副本。

DQT,Define Quantization Table,定义量化表

标记代码                          2字节            固定值0xFFDB

包含9个具体字段:
 ① 数据长度                  2字节            字段①和多个字段②的总长度
                                                            即不包括标记代码,但包括本字段
 ② 量化表        数据长度-2字节

a)精度及量化表ID   1字节            高4位:精度,只有两个可选值
                                                              0:8位;1:16位
                                                低4位:量化表ID,取值范围为0~3

b)表项       (64×(精度+1))字节              例如8位精度的量化表
                                                其表项长度为64×(0+1)=64字节

本标记段中,字段②可以重复出现,表示多个量化表,但最多只能出现4次。

SOF0,Start of Frame,帧图像开始

标记代码                   2字节     固定值0xFFC0

包含9个具体字段:
 ① 数据长度           2字节     ①~⑥六个字段的总长度
                                              即不包括标记代码,但包括本字段
 ② 精度                 1字节     每个数据样本的位数
                                              通常是8位,一般软件都不支持 12位和16位
 ③ 图像高度           2字节     图像高度(单位:像素),如果不支持 DNL 就必须 >0
  ④ 图像宽度           2字节     图像宽度(单位:像素),如果不支持 DNL 就必须 >0
  ⑤ 颜色分量数        1字节     只有3个数值可选
                                              1:灰度图;3:YCrCb或YIQ;4:CMYK
                                              而JFIF中使用YCrCb,故这里颜色分量数恒为3
  ⑥颜色分量信息      颜色分量数×3字节(通常为9字节)

a)颜色分量ID                 1字节

b)水平/垂直采样因子      1字节            高4位:水平采样因子
                                                       低4位:垂直采样因子
                                                       (曾经看到某资料把这两者调转了)

c) 量化表                         1字节            当前分量使用的量化表的ID

本标记段中,字段⑥应该重复出现,有多少个颜色分量(字段⑤),就出现多少次(一般为3次)。

DHT,Difine Huffman Table,定义哈夫曼表

标记代码                                 2字节            固定值0xFFC4

包含2个具体字段:
 ①数据长度                             2字节            字段①和多个字段②的总长度
                                                                   即不包括标记代码,但包括本字段
 ② 哈夫曼表              数据长度-2字节

a)表ID和表类型            1字节            高4位:类型,只有两个值可选
                                                                     0:DC直流;1:AC交流
                                                        低4位:哈夫曼表ID,
                                                                     注意,DC表和AC表分开编码

b)不同位数的码字数量    16字节

c)编码内容       16个不同位数的码字数量之和(字节)

本标记段中,字段②可以重复出现(一般4次),也可以致出现1次。例如,Adobe Photoshop 生成的JPEG图片文件中只有1个DHT标记段,里边包含了4个哈夫曼表;而Macromedia Fireworks生成的JPEG图片文件则有4个DHT标记段,每个DHT标记段只有一个哈夫曼表。

DRI,Define Restart Interval,定义差分编码累计复位的间隔

标记代码                                 2字节     固定值0xFFDD

包含2个具体字段:
 ①数据长度                             2字节     固定值0x0004,①~②两个字段的总长度
                                                            即不包括标记代码,但包括本字段
 ②MCU块的单元中的重新开始间隔
                                              2字节     设其值为n,则表示每n个MCU块就有一个
                                                           RSTn标记。第一个标记是RST0,第二个是
                                                            RST1等,RST7后再从RST0重复。

如果没有本标记段,或间隔值为0时,就表示不存在重开始间隔和标记RST

SOS,Start of Scan,扫描开始 12字节

标记代码                          2字节     固定值0xFFDA

包含2个具体字段:
 ①数据长度                      2字节     ①~④两个字段的总长度
                                                     即不包括标记代码,但包括本字段
 ②颜色分量数                 1字节     应该和SOF中的字段⑤的值相同,即:
                                                     1:灰度图是;3: YCrCb或YIQ;4:CMYK。

而JFIF中使用YCrCb,故这里颜色分量数恒为3
   ③颜色分量信息
        a) 颜色分量ID           1字节
        b) 直流/交流系数表号 1字节     高4位:直流分量使用的哈夫曼树编号
                                                        低4位:交流分量使用的哈夫曼树编号

④ 压缩图像数据
        a)谱选择开始                     1字节     固定值0x00
        b)谱选择结束                     1字节     固定值0x3F
        c)谱选择                            1字节     在基本JPEG中总为00

本标记段中,字段③应该重复出现,有多少个颜色分量(字段②),就出现多少次(一般为3次)。本段结束后,紧接着就是真正的图像信息了。图像信息直至遇到一个标记代码就自动结束,一般就是以EOI标记表示结束。

EOI,End of Image,图像结束 2字节

标记代码                   2字节     固定值0xFFD9

这里补充说明一下,由于在JPEG文件中0xFF具有标志性的意思,所以在压缩数据流(真正的图像信息)中出现0xFF,就需要作特别处理。具体方法是,在数据0xFF后添加一个没有意义的0x00。换句话说,如果在图像数据流中遇到0xFF,应该检测其紧接着的字符,如果是

1)0x00,则表示0xFF是图像流的组成部分,需要进行译码;

2)0xD9,则与0xFF组成标记EOI,则图像流结束,同时图像文件结束;

3)0xD0~0xD7,则组成RSTn标记,则要忽视整个RSTn标记,即不对当前0xFF和紧接的0xDn两个字节进行译码,并按RST标记的规则调整译码变量;

3)0xFF,则忽视当前0xFF,对后一个0xFF再作判断;

4)其他数值,则忽视当前0xFF,并保留紧接的此数值用于译码。

为了造福大众,我把自己定义的文件头结构体给他家参考一下,欢迎讨论~

 typedef struct APP0                            //应用程序保留标记0
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char symbol[]; //标识符
unsigned char version[]; //版本号
unsigned char density; //X和Y的密度单位
unsigned char x_density[]; //X方向像素密度
unsigned char y_density[]; //Y方向像素密度
unsigned char x_num; //缩略图水平像素数目
unsigned char y_num; //缩略图垂直像素数目
unsigned char* RGB_bitmap; //缩略图RGB位图
}APP0; APP0 app0; typedef struct APPn //应用程序保留标记n,其中n=1~15(任选)
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char* info; //详细信息,数据长度-2字节
}APPn; APPn appn; typedef struct DQT //定义量化表
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char* table; //量化表,数据长度-2字节
//a.精度及量化表ID 1字节
//高4位:精度,只有两个可选值,0:8位;1:16位
//低4位:量化表ID,取值范围为0~3
//b.表项(64×(精度 + 1))字节
//例如8位精度的量化表,其表项长度为64×(0 + 1) = 64字节
}DQT; DQT dqt; typedef struct SOF0 //帧图像开始
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char accuracy; //精度
unsigned char height[]; //图像高度
unsigned char width[]; //图像宽度
unsigned char color; //颜色分量数
unsigned char* color_info; //颜色分量信息
}SOF0; SOF0 sof0; typedef struct DHT //定义哈夫曼表
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char* H_table; //哈夫曼表,数据长度-2字节
//a.表ID和表类型,1字节,
//高4位:0:DC直流;1:AC交流
//低4位:哈夫曼表ID,注意,DC表和AC表分开编码
//b.不同位数的码字数量,16字节
//c.编码内容,16个不同位数的码字数量之和(字节)
}DHT; DHT dht; typedef struct DRI //定义差分编码累计复位的间隔
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char interval[]; //MCU块的单元中的重新开始间隔
//设其值为n,则表示每n个MCU块就有一个RSTn标记。
}DRI; DRI dri; typedef struct SOS //扫描开始,12字节
{
//char value[2]; //标记代码
unsigned char d_length[]; //数据长度
unsigned char color; //颜色分量数
unsigned char* color_info; //颜色分量信息
unsigned char image_data[]; //压缩图像数据
}SOS; SOS sos;

JPEG图像密写研究(一) JPEG图像文件结构的更多相关文章

  1. 【原创】JPEG图像密写研究(三) 数据流译码

    [原创]这次更新比较慢,译码过程比想象中复杂一些,更主要是译出来的DCT系数无法确定是否正确,要想验证就需要再进行正向压缩编码,再次形成jpeg图像验证正确,后续工作正在开展,这里就说一说译码的主要思 ...

  2. 【原创】JPEG图像密写研究(二) 哈夫曼树的建立

    [原创]记录自己研究的过程,仅供参考,欢迎讨论... 在根据JPEG图像文件结构读取完文件后,提取出其中DHT段,利用其中内容建立哈夫曼树,便于之后译码工作.这里需要注意的是文件中的哈夫曼表数量不固定 ...

  3. 隐写技巧——利用JPEG文件格式隐藏payload

    0x00 前言 继续对图片隐写技巧的学习,这次是对JPEG文件格式的学习和理解.同PNG文件的格式对比,JPEG文件相对简单,读取其中隐藏payload的方式大同小异,两者区别在于文件格式不同,可供利 ...

  4. C++ Opencv Mat类型使用的几个注意事项及自写函数实现Laplace图像锐化

    为了提升自己对Opencv中Mat数据类型的熟悉和掌握程度,自己尝试着写了一下Laplace图像锐化函数,一路坎坷,踩坑不断.现将代码分享如下: #include <opencv2/opencv ...

  5. python 在图像上写中文字体 (python write Chinese in image)

    本人处理图像的时候经常使用opencv的包,但是 cv2.putText 显示不了中文,所以查找了如何在python在图像上写中文的方法,在伟大的Stack Overflow上面找到一个方法,分享给大 ...

  6. 【图像配准】基于互信息的图像配准算法:MI、EMI、ECC算法

    简单介绍: 基于互信息的图像配准算法以其较高的配准精度和广泛的适用性而成为图像配准领域研究的热点之中的一个.而基于互信息的医学图像配准方法被觉得是最好的配准方法之中的一个.基于此.本文将介绍简单的基于 ...

  7. PHP图像裁剪为任意大小的图像,图像不变形,不留下空白

    <?php /** * 说明:函数功能是把一个图像裁剪为任意大小的图像,图像不变形 * 参数说明:输入 需要处理图片的 文件名,生成新图片的保存文件名,生成新图片的宽,生成新图片的高 */ fu ...

  8. [ActionScript 3.0] AS3.0 将图像的Alpha通道转换为黑白图像(分离ARGB方式)

    import flash.display.BitmapData; import flash.display.Bitmap; /** * 将图像的Alpha通道转换为黑白图像(分离ARGB方式) */ ...

  9. [ActionScript 3.0] AS3.0将图像的Alpha通道转换为黑白图像(复制通道方式)

    import flash.display.BitmapData; /** * 将图像的Alpha通道转换为黑白图像 */ var p:Point = new Point(0,0); var bmpd: ...

随机推荐

  1. 寻求c++解答如下三个题目!

  2. php5.6解决curl扩展不生效的问题

    最近在本机安装PHP环境,遇到一个奇粑问题,本地安装的php5.2.php5.3.php5.4都需要做常规设置,即可正常使用.安装php5.5.php5.6时php_curl按各种方法进行配制,都无法 ...

  3. requireJS到底是什么?

    1.requireJS是让js代码模块化:而且js之间的依赖关系,不再依靠script标签的顺序,可以加载不阻塞 2.requireJS加载js的方法:<script data-main=&qu ...

  4. Flink Program Guide (8) -- Working with State :Fault Tolerance(DataStream API编程指导 -- For Java)

    Working with State 本文翻译自Streaming Guide/ Fault Tolerance / Working with State ---------------------- ...

  5. python2.X和python3.X在同一平台下的切换技巧

    python2.X和python3.X在同一平台下的切换技巧 最近在自己的电脑上同时安装了python2.7.11和python3.5.1 在网上搜了一些答案,主要还是参照<learning p ...

  6. jacob 操作word转pdf

    项目需要对上传的word及pdf进行在线预览,因基于jquery的pdf插件,很方面实现在线预览,而word实现在线预览费劲不少,于是想到在进行上传处理时,直接将word转成pdf,在预览时直接预览p ...

  7. VB MSFlexGrid 用法

    http://blog.itpub.net/15453304/viewspace-445608/ 问题一,MSFlexGrid 点击一行,显示背景颜色,然后得到行号 首先,右键单击Msflexgrid ...

  8. shell基础——变量定义

    快速参考: 变量定义格式: 变量名=值 str1="hello world" # define a string var str2=hello # define a string ...

  9. 转:JavaScript函数式编程(三)

    转:JavaScript函数式编程(三) 作者: Stark伟 这是完结篇了. 在第二篇文章里,我们介绍了 Maybe.Either.IO 等几种常见的 Functor,或许很多看完第二篇文章的人都会 ...

  10. 论山寨手机与Android 【13】SmartPhone AP系统

    在第9章中我们提到,从功能上讲对于智能手机的一个粗略的概括是,智能手机 == 电脑 + 移动网卡,或者更准确地说,智能手机的硬件结构分为应用程序处理器AP,和基带处理器BP两个部分.这里隐含着两个问题 ...