• JPEG图像密写研究(一) JPEG图像文件结构


    【转载】转载自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 FormatJFIF)。而JPEG文件大体上可以分成两个部分:标记码(Tag)和压缩数据。

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

    常用的标记有SOIAPP0DQTSOF0DHTDRISOSEOI

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

    SOIStart of Image,图像开始

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

    APP0Application,应用程序保留标记0

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

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

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

    APPnApplication,应用程序保留标记n,其中n=115(任选)

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

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

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

     

    DQTDefine Quantization Table,定义量化表

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

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

    a)精度及量化表ID   1字节            4位:精度,只有两个可选值
                                                                  08位;116
                                                    4位:量化表ID,取值范围为03

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

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

    SOF0Start of Frame,帧图像开始

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

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

    a)颜色分量ID                 1字节    

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

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

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

    DHTDifine Huffman Table,定义哈夫曼表

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

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

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

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

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

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

    DRIDefine Restart Interval定义差分编码累计复位的间隔

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

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

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

    SOSStart of Scan,扫描开始 12字节

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

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

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

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

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

     

    EOIEnd of Image,图像结束 2字节

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

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

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

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

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

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

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

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

     1 typedef struct APP0                            //应用程序保留标记0
     2 {
     3     //char    value[2];                        //标记代码
     4     unsigned char    d_length[2];                    //数据长度
     5     unsigned char    symbol[5];                        //标识符
     6     unsigned char    version[2];                        //版本号
     7     unsigned char    density;                        //X和Y的密度单位
     8     unsigned char    x_density[2];                    //X方向像素密度
     9     unsigned char    y_density[2];                    //Y方向像素密度
    10     unsigned char    x_num;                            //缩略图水平像素数目
    11     unsigned char    y_num;                            //缩略图垂直像素数目
    12     unsigned char*    RGB_bitmap;                        //缩略图RGB位图 
    13 }APP0; APP0 app0;
    14 
    15 typedef struct APPn                            //应用程序保留标记n,其中n=1~15(任选)
    16 {
    17     //char    value[2];                                //标记代码
    18     unsigned char    d_length[2];                    //数据长度
    19     unsigned char*    info;                            //详细信息,数据长度-2字节
    20 }APPn; APPn appn;
    21 
    22 typedef struct DQT                                    //定义量化表
    23 {
    24     //char    value[2];                                //标记代码
    25     unsigned char    d_length[2];                    //数据长度
    26     unsigned char*    table;                            //量化表,数据长度-2字节
    27                                                     //a.精度及量化表ID   1字节            
    28                                                     //高4位:精度,只有两个可选值,0:8位;1:16位
    29                                                     //低4位:量化表ID,取值范围为0~3
    30                                                     //b.表项(64×(精度 + 1))字节
    31                                                     //例如8位精度的量化表,其表项长度为64×(0 + 1) = 64字节
    32 }DQT; DQT dqt;
    33 
    34 typedef struct SOF0                                    //帧图像开始
    35 {
    36     //char    value[2];                                //标记代码
    37     unsigned char    d_length[2];                    //数据长度
    38     unsigned char    accuracy;                        //精度
    39     unsigned char    height[2];                        //图像高度
    40     unsigned char    width[2];                        //图像宽度
    41     unsigned char    color;                            //颜色分量数
    42     unsigned char*    color_info;                        //颜色分量信息
    43 }SOF0; SOF0 sof0;
    44 
    45 typedef struct DHT                                    //定义哈夫曼表
    46 {
    47     //char    value[2];                                //标记代码
    48     unsigned char    d_length[2];                    //数据长度
    49     unsigned char*    H_table;                        //哈夫曼表,数据长度-2字节
    50                                                     //a.表ID和表类型,1字节,
    51                                                     //高4位:0:DC直流;1:AC交流
    52                                                     //低4位:哈夫曼表ID,注意,DC表和AC表分开编码
    53                                                     //b.不同位数的码字数量,16字节
    54                                                     //c.编码内容,16个不同位数的码字数量之和(字节)
    55 }DHT; DHT dht;
    56 
    57 typedef struct DRI                                    //定义差分编码累计复位的间隔
    58 {
    59     //char    value[2];                                //标记代码
    60     unsigned char    d_length[2];                    //数据长度
    61     unsigned char    interval[2];                    //MCU块的单元中的重新开始间隔
    62                                                     //设其值为n,则表示每n个MCU块就有一个RSTn标记。
    63 }DRI; DRI dri;
    64 
    65 typedef struct SOS                                    //扫描开始,12字节
    66 {
    67     //char    value[2];                                //标记代码
    68     unsigned char    d_length[2];                    //数据长度
    69     unsigned char    color;                            //颜色分量数
    70     unsigned char*    color_info;                        //颜色分量信息
    71     unsigned char    image_data[3];                    //压缩图像数据
    72 }SOS; SOS sos;
  • 相关阅读:
    解决maven托管项目中pom.xml存在坐标标红的问题
    Jquery取form表单中的所有参数
    解决IntelliJ IDEA控制台输出中文乱码问题
    Maven项目打包及jar包与war包的区别
    IDEA创建Maven web项目(项目结构组织、文件编译及运行明细)
    http学习笔记--报文构成
    http报文结构
    mount: unknown filesystem type 'vboxsf'
    使用shell做过时处理以及发送邮件的事例
    fuelphp 日志文件保存路径以及日志文件名变更中遇到的问题总结
  • 原文地址:https://www.cnblogs.com/gungnir2011/p/3615273.html
Copyright © 2020-2023  润新知