Examples or tutorials of using libjpeg-turbo's TurboJPEG

前端 未结 4 1881
醉酒成梦
醉酒成梦 2020-12-13 00:49

The instructions for libjpeg-turbo here describes the TurboJPEG API thus: \"This API wraps libjpeg-turbo and provides an easy-to-use interface for compressing and decompress

相关标签:
4条回答
  • 2020-12-13 01:12

    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.

    Below code is NOT my 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.

    #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;
    }
    
    0 讨论(0)
  • 2020-12-13 01:12

    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).

    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;
    }
    
    0 讨论(0)
  • 2020-12-13 01:16

    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. This official API is a good information source aswell.

    0 讨论(0)
  • 2020-12-13 01:23

    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 TurboJPEG is quite easy to understand!

    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:

    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:

    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 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.

    0 讨论(0)
提交回复
热议问题