libjpeg-turbo 是一个专门为 x86 和 x86-64 处理器优化的高速 libjpeg 的改进版本。上一篇文章讲了如何编译libjpeg-turbo 库,这篇文章主要演示如何使用 libjpeg-turbo 无损转换和压缩jpeg图片。

这篇文章使用的 libjpeg-turbo 版本是1.4,不同版本可能代码略有差异,请注意!

Losslessly transform a JPEG image

无损转换一个 JPEG 图像到另一个 JPEG 图像。无损转换通过移动 raw DCT 系数从一个 JPEG 图像结构到另一个图像,而不改变系数的值。

使用 libjpeg-turbo 无损转换图片的代码如下:

#include "turbojpeg.h"

// Create a new TurboJPEG transformer instance
tjhandle h = tjInitCompress();
if (h !=  nullptr) 
{
    // 读取jpeg图像
    unsigned char *jpegBuf = nullptr;
    unsigned long jpegSize = 0;
    __readfile(&jpegBuf, jpegSize);

    // 分配目的buffer
    unsigned long dstSizes = 0;
    unsigned char* dstBufs = nullptr;  // dstBufs 为 nullptr, tjTransform()会自动内存

    // tjtransform struct
    tjtransform transform;
    transform.op = TJXOP_NONE; // TJXOP_NONE TJXOP_ROT270;
    transform.options = TJXOPT_TRIM;
    transform.data = 0;
    transform.customFilter = 0;
    
    // 无损转换
    int rel = tjTransform(h, jpegBuf, jpegSize, 1, &dstBufs, &dstSizes, &transform, TJFLAG_ACCURATEDCT);
    if (rel != 0)
    {
        char* err = tjGetErrorStr();
    }
    
    // 保存图片
    __writeFile(...)

    // 释放dstBufs
    if (dstSizes != 0)
        tjFree(dstBufs);
    // 释放jpegBuf
    free(jpegBuf);

    // Destroy a TurboJPEG transformer instance
    tjDestroy(h);
}

压缩jpeg图片

相对于无损转换,压缩图片就要麻烦一些。开始本想要获取源文件图像尺寸和 RGB buffer,再使用 tjCompress2() 压缩,结果找了好久都没找到将 jpeg 图片转换为 RGB buffer 的接口和方法。最后只能通过tjDecompressToYUV2() 将 jpeg 图片转换为 YUV buffer,再通过 tjCompressFromYUV() 压缩图片。

使用 libjpeg-turbo 压缩 jpeg 图片的代码如下,其中 quality 参数是压缩比,对于 “jpeg” 格式 quality 的取值范围是0(low visual quality, high compression)到100((high visual quality, low compression)。

#include "turbojpeg.h"

// Create a TurboJPEG compressor instance
tjhandle h = tjInitCompress();
if (h != nullptr)
{
    // 读取jpeg图像
    unsigned char *jpegBuf = nullptr;
    unsigned long jpegSize = 0;
    __readfile(&jpegBuf, jpegSize);

    int _width = 0;
    int _height = 0;
    int jpegSubsamp;
    int jpegColorspace;
    int pad = 2;
    unsigned char* rgbbuf = nullptr;

    // 获取jpeg文件信息
    tjhandle dh = tjInitDecompress();
    int rel = tjDecompressHeader3(dh, jpegBuf, jpegSize, &_width, &_height, &jpegSubsamp, &jpegColorspace);

    // 计算YUV buffer大小
    unsigned long yuvBufSize = tjBufSizeYUV2(_width, pad, _height, jpegSubsamp);
    rgbbuf = tjAlloc(yuvBufSize);

    // 获取YUV buffer
    rel = tjDecompressToYUV2(dh, jpegBuf, jpegSize, rgbbuf, _width, pad, _height, 0);
    if (rel != 0)
    {
        char* err = tjGetErrorStr();
    }
    rel = tjDestroy(dh);

    // 分配目的buffer
    unsigned long dstSizes = 0;
    unsigned char* dstBufs = 0;
    const int quality = 75;

    // 压缩
    rel = tjCompressFromYUV(h, rgbbuf, _width, pad, _height, jpegSubsamp, &dstBufs, &dstSizes, quality, 0);
  
   // 保存图片
   __writeFile(...)

   // 释放buffer
   if (dstSizes != 0)
       tjFree(dstBufs);
   tjFree(rgbbuf);
   free(jpegBuf);

    // Destroy a TurboJPEG compressor instance
    tjDestroy(h);
}

压缩bmp格式的图像

对于 bmp 格式的图像,可以在 libjpeg-turbo 源码中找到 “bmp.h” 和 “bmp.c” 并在项目中包含它们,使用loadbmp() 函数读取 RGB buffer 即可。

使用QImageWriter压缩图片

对于 Qt 程序,可以使用 QImageWriter 压缩图片。QImageWriter 支持“BMP”、“JPG”、“PNG”等主流图像格式的压缩,使用起来非常简单。

QImage image("C:/Users/Administrator/Desktop/s.jpg");       // 源文件
QImageWriter imageWriter(QString("C:/Users/Administrator/Desktop/s1.jpg")); // 目的文件
// 设置压缩质量
imageWriter.setQuality(75);
qDebug() << imageWriter.write(image);

参考链接:
http://sourceforge.net/p/libjpeg-turbo/feature-requests/21/
http://stackoverflow.com/questions/9094691/examples-or-tutorials-of-using-libjpeg-turbos-turbojpeg
http://stackoverflow.com/questions/5616216/need-help-in-reading-jpeg-file-using-libjpeg

标签: libjpeg-turbo, libjpeg, 图片压缩, 图像压缩, jpeg压缩

添加新评论