【问题标题】:Examples or tutorials of using libjpeg-turbo's TurboJPEG使用 libjpeg-turbo 的 TurboJPEG 的示例或教程
【发布时间】:2012-02-24 01:35:32
【问题描述】:

libjpeg-turbo here 的说明这样描述 TurboJPEG API:“这个 API 封装了 libjpeg-turbo 并提供了一个易于使用的接口,用于在内存中压缩和解压缩 JPEG 图像”。太好了,但是有一些使用此 API 的可靠示例吗?只是想在内存中解压缩一个相当普通的 jpeg。

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

libjpeg-turbo 的源代码有据可查,这确实有帮助。

【问题讨论】:

    标签: c++ c jpeg libjpeg-turbo turbojpeg


    【解决方案1】:

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

    压缩:

    #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);
    

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

    解压:

    #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);
    

    一些随意的想法:

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

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

    我们将添加一个对象变量,保存分配内存的大小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;
    

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

    【讨论】:

    • 致那些投反对票的人:我仍然坚持这个答案,我很高兴知道,你认为什么不好。所以,请给我留言!
    • 新 tj 版本 (1.4) 已解压缩到 YUV 平面:tjDecompressToYUVPlanes(c_jpegDecompressor, c_jpeg_buffer, _jpegSize, m_planesYUV, 0, NULL, 0, m_accuracy);
    • Turbojpeg 上面的文档链接失效了,试试libjpeg-turbo.org/Documentation/Documentation
    • @jean-loup cdn.rawgit.com/libjpeg-turbo/libjpeg-turbo/master/doc/html/… 您是否正在考虑更快地实现 jpeg 库?因为 libjpeg-turbo != Turbojpeg.
    • @Theolodis 存在一些混淆,因为 libjpeg-turbo 的标头是 turbojpeg.h 而 ubuntu 中的 libjpeg-turbo 不是这个 lib.. 但从 git repo 安装它运行良好。
    【解决方案2】:

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

    下面的代码不是我自己的,归功于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;
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 如果代码很小,您可以在此处分享以改进您的答案;)
      【解决方案4】:

      这是我用来从内存中加载 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;
      }
      

      【讨论】:

      • 很抱歉不接受您的回答,但现在仔细观察我实际上正在实现这个,我可以看到您甚至没有在您发布的代码中调用 tj 函数(例如 tjDecompress)。
      • 不强制使用 TurboJpeg API 从 libjpeg-turbo 库中获得速度优势。在我的示例中,我只使用标准的 libjpeg API。为什么你不想使用 libjpeg API?
      • 我的问题非常明确地询问 TurboJPEG API。与标准的 libjpeg 接口相比,我使用它是因为它的简单性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多