C++ 使用 libjpeg-turbo 的 TurboJPEG 的示例或教程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9094691/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:17:35  来源:igfitidea点击:

Examples or tutorials of using libjpeg-turbo's TurboJPEG

c++cjpeglibjpeg-turboturbojpeg

提问by occulus

The instructions for libjpeg-turbo heredescribes the TurboJPEG API thus: "This API wraps libjpeg-turbo and provides an easy-to-use interface for compressing and decompressing JPEG images in memory". Great, but are there some solid examples of using this API available? Just looking to decompress a fairly vanilla jpeg in memory.

此处的libjpeg-turbo 说明描述了 TurboJPEG API,因此:“该 API 包装了 libjpeg-turbo 并提供了一个易于使用的界面,用于在内存中压缩和解压缩 JPEG 图像”。很好,但是否有一些使用此 API 的可靠示例?只是想在内存中解压一个相当普通的 jpeg。

I've found a few bits such as https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c, which appears to be using the TurboJPEG API, but are there any more solid/varied examples?

我发现了一些诸如https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c 之类的内容,它似乎在使用 TurboJPEG API,但是还有更多可靠/多样的示例吗?

The source for libjpeg-turbo is well documented, so that does help.

libjpeg-turbo 的源代码有很好的文档记录,因此确实有帮助。

采纳答案by occulus

In the end I used a combination of random code found on the internet (e.g. https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c) and the .c and header files for libjeg-turbo, which are well documented. Thisofficial API is a good information source aswell.

最后,我使用了在互联网上找到的随机代码(例如https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c)和 libjeg-turbo 的 .c 和头文件的组合,这是有据可查的。 这个官方 API 也是一个很好的信息来源。

回答by Theolodis

Ok, I know that you did already solve your problem, but as some people, just like me, could be searching some simple example I will share what I created. It is an example, compressing and decompressing an RGB image. Otherwise I think that the API documentation of TurboJPEGis quite easy to understand!

好的,我知道您确实已经解决了您的问题,但是作为一些人,就像我一样,可能正在搜索一些简单的示例,我将分享我创建的内容。这是一个示例,压缩和解压缩 RGB 图像。不然我觉得TurboJPEG的API文档还是挺容易看懂的!

Compression:

压缩:

#include <turbojpeg.h>

const int JPEG_QUALITY = 75;
const int COLOR_COMPONENTS = 3;
int _width = 1920;
int _height = 1080;
long unsigned int _jpegSize = 0;
unsigned char* _compressedImage = NULL; //!< Memory is allocated by tjCompress2 if _jpegSize == 0
unsigned char buffer[_width*_height*COLOR_COMPONENTS]; //!< Contains the uncompressed image

tjhandle _jpegCompressor = tjInitCompress();

tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
          &_compressedImage, &_jpegSize, TJSAMP_444, JPEG_QUALITY,
          TJFLAG_FASTDCT);

tjDestroy(_jpegCompressor);

//to free the memory allocated by TurboJPEG (either by tjAlloc(), 
//or by the Compress/Decompress) after you are done working on it:
tjFree(&_compressedImage);

After that you have the compressed image in _compressedImage. To decompress you have to do the following:

之后,您在_compressedImage 中有压缩图像。要解压缩,您必须执行以下操作:

Decompression:

减压:

#include <turbojpeg.h>

long unsigned int _jpegSize; //!< _jpegSize from above
unsigned char* _compressedImage; //!< _compressedImage from above

int jpegSubsamp, width, height;
unsigned char buffer[width*height*COLOR_COMPONENTS]; //!< will contain the decompressed image

tjhandle _jpegDecompressor = tjInitDecompress();

tjDecompressHeader2(_jpegDecompressor, _compressedImage, _jpegSize, &width, &height, &jpegSubsamp);

tjDecompress2(_jpegDecompressor, _compressedImage, _jpegSize, buffer, width, 0/*pitch*/, height, TJPF_RGB, TJFLAG_FASTDCT);

tjDestroy(_jpegDecompressor);

Some random thoughts:

一些随意的想法:

I just came back over this as I am writing my bachelor thesis, and I noticed that if you run the compression in a loop it is preferable to store the biggest size of the JPEG buffer to not have to allocate a new one every turn. Basically, instead of doing:

我刚刚在写我的学士论文时回到这个问题,我注意到如果你在循环中运行压缩,最好存储最大大小的 JPEG 缓冲区,而不必每次都分配一个新缓冲区。基本上,而不是做:

long unsigned int _jpegSize = 0;

tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
          &_compressedImage, &_jpegSize, TJSAMP_444, JPEG_QUALITY,
          TJFLAG_FASTDCT);

we would add an object variable, holding the size of the allocated memory long unsigned int _jpegBufferSize = 0;and before every compression round we would set the jpegSize back to that value:

我们将添加一个对象变量,保存已分配内存的大小,long unsigned int _jpegBufferSize = 0;并且在每次压缩之前,我们将 jpegSize 设置回该值:

long unsigned int jpegSize = _jpegBufferSize;

tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
          &_compressedImage, &jpegSize, TJSAMP_444, JPEG_QUALITY,
          TJFLAG_FASTDCT);

_jpegBufferSize = _jpegBufferSize >= jpegSize? _jpegBufferSize : jpegSize;

after the compression one would compare the memory size with the actual jpegSize and set it to the jpegSize if it is higher than the previous memory size.

压缩后,将内存大小与实际 jpegSize 进行比较,如果它大于先前的内存大小,则将其设置为 jpegSize。

回答by Frank Chang

I ended up using below code as a working example for both JPEG encoding and decoding. Best example that I can find, it's self-contained that initializes a dummy image and output the encoded image to a local file.

我最终使用以下代码作为 JPEG 编码和解码的工作示例。我能找到的最好的例子,它是独立的,可以初始化一个虚拟图像并将编码的图像输出到本地文件。

Below code is NOTmy own, credit goes to https://sourceforge.net/p/libjpeg-turbo/discussion/1086868/thread/e402d36f/#8722. Posting it here again to help anyone finds it's difficult to get libjpeg turbo working.

下面的代码不是我自己的,归功于https://sourceforge.net/p/libjpeg-turbo/discussion/1086868/thread/e402d36f/#8722。再次将它张贴在这里以帮助任何人发现很难让 libjpeg turbo 工作。

#include "turbojpeg.h"
#include <iostream>
#include <string.h>
#include <errno.h>

using namespace std;

int main(void)
{
    unsigned char *srcBuf; //passed in as a param containing pixel data in RGB pixel interleaved format
    tjhandle handle = tjInitCompress();

    if(handle == NULL)
    {
        const char *err = (const char *) tjGetErrorStr();
        cerr << "TJ Error: " << err << " UNABLE TO INIT TJ Compressor Object\n";
        return -1;
    }
    int jpegQual =92;
    int width = 128;
    int height = 128;
    int nbands = 3;
    int flags = 0;
    unsigned char* jpegBuf = NULL;
    int pitch = width * nbands;
    int pixelFormat = TJPF_GRAY;
    int jpegSubsamp = TJSAMP_GRAY;
    if(nbands == 3)
    {
        pixelFormat = TJPF_RGB;
        jpegSubsamp = TJSAMP_411;
    }
    unsigned long jpegSize = 0;

    srcBuf = new unsigned char[width * height * nbands];
    for(int j = 0; j < height; j++)
    {
        for(int i = 0; i < width; i++)
        {
            srcBuf[(j * width + i) * nbands + 0] = (i) % 256;
            srcBuf[(j * width + i) * nbands + 1] = (j) % 256;
            srcBuf[(j * width + i) * nbands + 2] = (j + i) % 256;
        }
    }

    int tj_stat = tjCompress2( handle, srcBuf, width, pitch, height,
        pixelFormat, &(jpegBuf), &jpegSize, jpegSubsamp, jpegQual, flags);
    if(tj_stat != 0)
    {
        const char *err = (const char *) tjGetErrorStr();
        cerr << "TurboJPEG Error: " << err << " UNABLE TO COMPRESS JPEG IMAGE\n";
        tjDestroy(handle);
        handle = NULL;
        return -1;
    }

    FILE *file = fopen("out.jpg", "wb");
    if (!file) {
        cerr << "Could not open JPEG file: " << strerror(errno);
        return -1;
    }
    if (fwrite(jpegBuf, jpegSize, 1, file) < 1) {
        cerr << "Could not write JPEG file: " << strerror(errno);
        return -1;
    }
    fclose(file);

    //write out the compress date to the image file
    //cleanup
    int tjstat = tjDestroy(handle); //should deallocate data buffer
    handle = 0;
}

回答by Mārti?? Mo?eiko

Here's a fragment of code what I use to load jpeg's from memory. Maybe it will require a bit of fixing, because I extracted it from different files in my project. It will load both - grayscale and rgb images (bpp will be set either to 1 or to 3).

这是我用来从内存中加载 jpeg 的代码片段。也许它需要一些修复,因为我从项目中的不同文件中提取了它。它将同时加载 - 灰度和 rgb 图像(bpp 将设置为 1 或 3)。

struct Image
{
    int bpp;
    int width;
    int height;
    unsigned char* data;
};

struct jerror_mgr
{
    jpeg_error_mgr base;
    jmp_buf        jmp;
};

METHODDEF(void) jerror_exit(j_common_ptr jinfo)
{
    jerror_mgr* err = (jerror_mgr*)jinfo->err;
    longjmp(err->jmp, 1);
}

METHODDEF(void) joutput_message(j_common_ptr)
{
}

bool Image_LoadJpeg(Image* image, unsigned char* img_data, unsigned int img_size)
{
    jpeg_decompress_struct jinfo;
    jerror_mgr jerr;

    jinfo.err = jpeg_std_error(&jerr.base);
    jerr.base.error_exit = jerror_exit;
    jerr.base.output_message = joutput_message;
    jpeg_create_decompress(&jinfo);

    image->data = NULL;

    if (setjmp(jerr.jmp)) goto bail;

    jpeg_mem_src(&jinfo, img_data, img_size);

    if (jpeg_read_header(&jinfo, TRUE) != JPEG_HEADER_OK) goto bail;

    jinfo.dct_method = JDCT_FLOAT; // change this to JDCT_ISLOW on Android/iOS

    if (!jpeg_start_decompress(&jinfo)) goto bail;

    if (jinfo.num_components != 1 && jinfo.num_components != 3) goto bail;

    image->data = new (std::nothrow) unsigned char [jinfo.output_width * jinfo.output_height * jinfo.output_components];
    if (!image->data) goto bail;

    {
        JSAMPROW ptr = image->data;
        while (jinfo.output_scanline < jinfo.output_height)
        {
            if (jpeg_read_scanlines(&jinfo, &ptr, 1) != 1) goto bail;

            ptr += jinfo.output_width * jinfo.output_components;
        }
    }

    if (!jpeg_finish_decompress(&jinfo)) goto bail;

    image->bpp = jinfo.output_components;
    image->width = jinfo.output_width;
    image->height = jinfo.output_height;

    jpeg_destroy_decompress(&jinfo);

    return true;

bail:
    jpeg_destroy_decompress(&jinfo);
    if (image->data) delete [] data;

    return false;
}