An unique Monkey

Be what you wanted to be

读取JPEG文件的压缩质量/质量因子参数

JPEG是一种图像压缩算法,而JPEG在做压缩编码的时候往往需要设定一个压缩质量/质量因子的参数(quality)。而在编码完成以后我们有时候希望获取到JPEG压缩文件的这个quality,好在万恶的jpeg编码协议却并没有直接存储这个quality参数,而opencv libjpeg这样的第三方库也没有提供获取JPEG文件质量参数的接口。可是JPEG文件存储了一个量化表的参数(quantize table),这里我们就是运用读取这个JPEG文件的quantize table然后反推这个JPEG文件的quality。

  1. 关于JPEG具体的压缩算法请查看wiki
  2. 需要用到第三方库文件:libjpeg(下载链接)
  3. 安装方法:
    tar xvf jpegsrc.v9.tar.gz
    cd jpeg-9
    mkdir build
    cd build
    ../configure
    make -j
    make install
    
  4. 实现代码

    #include <stdio.h>
    #include <math.h>
    
    #include "jpeglib.h"
    #include <setjmp.h>
    
    //标准明度量化表
    static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
    16,  11,  10,  16,  24,  40,  51,  61,
    12,  12,  14,  19,  26,  58,  60,  55,
    14,  13,  16,  24,  40,  57,  69,  56,
    14,  17,  22,  29,  51,  87,  80,  62,
    18,  22,  37,  56,  68, 109, 103,  77,
    24,  35,  55,  64,  81, 104, 113,  92,
    49,  64,  78,  87, 103, 121, 120, 101,
    72,  92,  95,  98, 112, 100, 103,  99
    };
    //读取JPG文件的质量参数
    int ReadJpegQuality(const char *filename)
    {
      FILE * infile = fopen(filename, "rb");
      fseek(infile,0,SEEK_END);
      size_t sz = ftell(infile);
      fseek(infile,0,SEEK_SET);
      unsigned char* buffer = new unsigned char[sz];
      fread(buffer,1,sz,infile);
      fclose(infile);
      //如果不是JPG格式的文件返回-1
      if(buffer==NULL || sz <= 2 || 
      0xFF != (uint8_t)buffer[0] || 
      0xD8 != (uint8_t)buffer[1])
      {
        return -1;
      }
      struct jpeg_decompress_struct cinfo;
      struct jpeg_error_mgr jerr;
      cinfo.err = jpeg_std_error(&jerr);
      jpeg_create_decompress(&cinfo);
      jpeg_mem_src(&cinfo,(unsigned char*)buffer,sz);
      jpeg_read_header(&cinfo, TRUE);
      int tmp_quality = 0;
      int linear_quality = 0;
      const int aver_times = 3;
      int times = 0;
      int aver_quality = 0;
      //量化表反推3次,取平均值
      for(int i=0;i<DCTSIZE2;i++)
      {
        long temp = cinfo.quant_tbl_ptrs[0]->quantval[i];
        if(temp<32767L&&temp>0)
        {
          linear_quality = ceil((float)(temp*100L - 50L)/std_luminance_quant_tbl[i]);
          if(linear_quality==1) tmp_quality = 1;
          else if(linear_quality==100) tmp_quality = 100;
          else if(linear_quality>100)
          {
            tmp_quality = ceil((float)5000/linear_quality);
          }
        else
        {
          tmp_quality = 100 - ceil((float)linear_quality/2);
        }
        aver_quality += tmp_quality;
        if(aver_times==++times)
        {
          aver_quality /= aver_times;
          break;
        } 
        }
      }
      jpeg_destroy_decompress(&cinfo);
      return aver_quality;
    }
    
    int main(int argc,char** argv)
    {
      printf("quality: %d\n",ReadJpegQuality("test1.jpg"));
      return 0; 
    }
    
  5. 编译链接的方法也很简单了
    g++ main.cpp -I/your_path_to/libjpeg-9b/build/include -L/your_path_to/libjpeg-9b/build/lib/ -ljpeg

HouXin

A designer, developer and entrepreneur. Spends his time travelling the world with a bag of kites. Likes journalism and publishing platforms.

Comments

<% if(config.disqus_shortname) { %>
<% } %>