使用 jpeg-turbo 压缩图片

2021-07-13  本文已影响0人  book_02

1. jpeg-turbo的编译安装

使用标准的cmake的编译安装方式即可。

下面以 windows 平台为例说明编译安装过程,其他平台过程类似。

1.1 先安装NASM

NASM是个汇编工具,后面编译 jpeg-turbo 需要用到,所以先安装

NASM的官网: https://www.nasm.us/index.php

可以从下载页 https://www.nasm.us/pub/nasm/releasebuilds/?C=M;O=D 中选择适合自己系统的版本进行安装

1.2 下载 jpeg-turbo 源码

jpeg-turbo的github仓库网址: https://github.com/libjpeg-turbo/libjpeg-turbo
可以从中下载最新的master版本。

也可以从 https://github.com/libjpeg-turbo/libjpeg-turbo/releases 中下载历史版本

这里下载2.1.0版本得到文件"libjpeg-turbo-2.1.0.zip"

解压到文件夹"D:\test\libjpeg-turbo-2.1.0"
新建文件夹"D:\test\libjpeg-turbo-2.1.0\build",作为后续的编译文件夹
新建文件夹"D:\test\jpeg-turbo_install",作为安装文件夹

1.3 cmake 配置编译工程

这里用 cmake-gui,本质就是cmake,只是方便查看设置的选项。

如下设置源码文件夹、编译文件夹、安装文件夹


image

1.4 打开工程编译安装

依次点击"Generate"和"Open Project",打开编译工程。

如下编译"INSTALL"工程


image

编译完成之后,就在指定安装路径下生成了如下文件,如此便完成了jpeg-turbo的编译安装


image

2. 使用

2.1 通过 cmake 进行 jpeg-turbo 库引用的关键语句

写在CMakeLists.txt的关键语句如下:

set(libjpeg-turbo_DIR "D:/test/jpeg-turbo_install/lib/cmake/libjpeg-turbo")
find_package(libjpeg-turbo REQUIRED)

add_executable(${PROJECT_NAME} main.cpp) 
target_link_libraries(${PROJECT_NAME} libjpeg-turbo::turbojpeg-static)

这里是使用了静态库,使用其他形式可以去更改target_link_libraries的后面部分

2.2 压缩语句

bool Compress(unsigned char *data_uncompressed, unsigned char* &out_compressed, unsigned long *out_size, int width, int height, int pixel_format)
{
    if (nullptr == data_uncompressed) {
        return false;
    }

    tjhandle compressor = tjInitCompress();
    if (nullptr == compressor) {
        return false;
    }

    //pixel_format : TJPF::TJPF_BGR or other
    const int JPEG_QUALITY = 75;
    int pitch = tjPixelSize[pixel_format] * width;
    int status = tjCompress2(compressor, data_uncompressed, width, pitch, height, pixel_format,
        &out_compressed, out_size, TJSAMP_444, JPEG_QUALITY, TJFLAG_FASTDCT);
    if (status != 0) {
        tjDestroy(compressor);
        return false;
    }

    tjDestroy(compressor);
    return true;
}

2.3 解压缩语句

bool Decompress(uint8_t* data_compressed, uint32_t size, uint8_t* &out_uncompressed, int pixel_format) 
{
    if (nullptr == data_compressed || nullptr == out_uncompressed) {
        return false;
    }

    int width = 0, height = 0, jpegsubsamp = 0;
    void* decompressor = tjInitDecompress();
    if (nullptr == decompressor) {
        return false;
    }

    if (tjDecompressHeader2(decompressor, data_compressed, size, &width, &height, &jpegsubsamp) != 0) {
        tjDestroy(decompressor);
        return false;
    }

    // pixel_format : TJPF::TJPF_BGR or other
    int pitch = tjPixelSize[pixel_format] * width;
    uint32_t len = pitch * height;
    int flags = TJFLAG_FASTDCT;
    int status = tjDecompress2(decompressor, data_compressed, len, out_uncompressed, width, pitch, 
        height, pixel_format, flags);
    if ( status != 0) {
        tjDestroy(decompressor);
        return false;
    }

    tjDestroy(decompressor);
    return true;
}

2.4 测试程序

int main()
{
    cv::Mat image = cv::imread("../lena.jpg");

    unsigned char *data_uncompressed = image.data;
    unsigned char* out_compressed = nullptr;
    unsigned long out_size = 0;
    int pixel_format = TJPF::TJPF_BGR;
    int width = image.cols;
    int height = image.rows;
    int channels = image.channels();
    bool status = Compress(data_uncompressed, out_compressed, &out_size, width, height, pixel_format);
    if (false == status) {
        std::cout << "Compress failed" << std::endl;
    }

    uint8_t* out_uncompressed = new uint8_t[width*height*channels];

    status = Decompress(out_compressed, out_size, out_uncompressed, pixel_format);
    if (false == status) {
        std::cout << "Decompress failed" << std::endl;
    }

    cv::Mat image_decompress(height, width, CV_8UC3, out_uncompressed);
    cv::imshow("out_uncompressed", image_decompress);
    cv::waitKey(0);

    delete[] out_compressed;
    delete[] out_uncompressed;

    return 0;
}

上面的程序压缩了lena.jpg图片,然后再解压。
可以调试查看是否压缩成功和是否解压成原图。

2.5 以上程序汇总

2.5.1 CMakeLists.txt

cmake_minimum_required(VERSION 3.6) 
project(demo_jpeg-turbo)

#---------------------------------------------------------------------------------------
# jpeg turbo
#---------------------------------------------------------------------------------------
set(libjpeg-turbo_DIR "D:/test/jpeg-turbo_install/lib/cmake/libjpeg-turbo")
find_package(libjpeg-turbo REQUIRED)

#---------------------------------------------------------------------------------------
# OpenCV
#---------------------------------------------------------------------------------------
find_package( OpenCV REQUIRED )

#---------------------------------------------------------------------------------------
# ${PROJECT_NAME}
#---------------------------------------------------------------------------------------
add_executable(${PROJECT_NAME} main.cpp) 
target_link_libraries(${PROJECT_NAME} libjpeg-turbo::turbojpeg-static)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} )


## set ${PROJECT_NAME} as startup project
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})

2.5.2 main.cpp


#include <iostream>
#include "opencv2/opencv.hpp"
#include <turbojpeg.h>


bool Compress(unsigned char *data_uncompressed, unsigned char* &out_compressed, unsigned long *out_size, int width, int height, int pixel_format)
{
    if (nullptr == data_uncompressed) {
        return false;
    }

    tjhandle compressor = tjInitCompress();
    if (nullptr == compressor) {
        return false;
    }

    //pixel_format : TJPF::TJPF_BGR or other
    const int JPEG_QUALITY = 75;
    int pitch = tjPixelSize[pixel_format] * width;
    int status = tjCompress2(compressor, data_uncompressed, width, pitch, height, pixel_format,
        &out_compressed, out_size, TJSAMP_444, JPEG_QUALITY, TJFLAG_FASTDCT);
    if (status != 0) {
        tjDestroy(compressor);
        return false;
    }

    tjDestroy(compressor);
    return true;
}

bool Decompress(uint8_t* data_compressed, uint32_t size, uint8_t* &out_uncompressed, int pixel_format) 
{
    if (nullptr == data_compressed || nullptr == out_uncompressed) {
        return false;
    }

    int width = 0, height = 0, jpegsubsamp = 0;
    void* decompressor = tjInitDecompress();
    if (nullptr == decompressor) {
        return false;
    }

    if (tjDecompressHeader2(decompressor, data_compressed, size, &width, &height, &jpegsubsamp) != 0) {
        tjDestroy(decompressor);
        return false;
    }

    // pixel_format : TJPF::TJPF_BGR or other
    int pitch = tjPixelSize[pixel_format] * width;
    uint32_t len = pitch * height;
    int flags = TJFLAG_FASTDCT;
    int status = tjDecompress2(decompressor, data_compressed, len, out_uncompressed, width, pitch, 
        height, pixel_format, flags);
    if ( status != 0) {
        tjDestroy(decompressor);
        return false;
    }

    tjDestroy(decompressor);
    return true;
}

int main()
{
    cv::Mat image = cv::imread("../lena.jpg");

    unsigned char *data_uncompressed = image.data;
    unsigned char* out_compressed = nullptr;
    unsigned long out_size = 0;
    int pixel_format = TJPF::TJPF_BGR;
    int width = image.cols;
    int height = image.rows;
    int channels = image.channels();
    bool status = Compress(data_uncompressed, out_compressed, &out_size, width, height, pixel_format);
    if (false == status) {
        std::cout << "Compress failed" << std::endl;
    }

    uint8_t* out_uncompressed = new uint8_t[width*height*channels];

    status = Decompress(out_compressed, out_size, out_uncompressed, pixel_format);
    if (false == status) {
        std::cout << "Decompress failed" << std::endl;
    }

    cv::Mat image_decompress(height, width, CV_8UC3, out_uncompressed);
    cv::imshow("out_uncompressed", image_decompress);
    cv::waitKey(0);

    delete[] out_compressed;
    delete[] out_uncompressed;

    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读