【问题标题】:How to properly use jpeg_mem_dest with and without a std::vector如何在有和没有 std::vector 的情况下正确使用 jpeg_mem_dest
【发布时间】:2016-08-27 11:13:48
【问题描述】:

我在搜索如何写入缓冲区而不是文件时遇到了这个问题,我找不到一个好的例子。

这是 jpeglib.h 所说的,但我不确定如何使用它。

/* Data source and destination managers: memory buffers. */
EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
                   unsigned char ** outbuffer,
                   unsigned long * outsize));

example.c 中,我们将数据目标设置在 Step 2 那么如何使用它如果我们已经有一个保存 RGB 值的std::vector<unsigned char> buffer,则在这里。

/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
    jpeg_mem_dest(&cinfo, /*WHAT GOES HERE*/, /*WHAT GOES HERE*/);

完成后,我们对Step 5进行哪些更改,以便我们写在相同 解压后的 RGB 值所在的缓冲区?

/* Step 5: while (scan lines remain to be written) */
/*           jpeg_write_scanlines(...); */

我错过了什么吗?非常感谢您的帮助,在此先感谢您。

【问题讨论】:

    标签: c++ c c++11 jpeg libjpeg


    【解决方案1】:

    假设您已继续前进,但以下内容适用于其他人。

    struct Result{
      unsigned char* buf;
      unsigned long size;
    }
    Result result;
    // ..Here allocate the buffer and initialize the size
    // before using in jpeg_mem_dest.  Or it will allocate for you
    // and you have to clean up.
    jpeg_mem_dest(&cinfo, &result->buf, &result->size);
    // use buffer
    free(result->buf); // <- of course depending on the way the buffer was allocated 
    

    如果您正在使用 std::vector ,则您可以使用类似 &myVec[0] 或 myVec.data() 之类的东西从 c++11 开始传递原始缓冲区(但认为我可能遇到了麻烦) )。一种解决方法是使用原始缓冲区,如果性能不重要,只需复制/插入即可。

    // Copy based.  Could also just buffer.insert if not preallocated using resize.
    std::vector<unsigned char> buffer;
    budder.resize(result->size())
    std::copy(result->buf
            , result->buf + result->size
            , buffer.begin());
    

    【讨论】:

      【解决方案2】:

      您不能使用jpeg_mem_dest 直接写入std::vector,因为它分配/管理自己的内存。之后您可以将该内存复制到std::vector,但这当然很昂贵。

      如果您想直接写信给std::vector,您必须通过在jpeg_compress_struct 中设置jpeg_destination_mgr *dest 结构来自行管理它。

      struct jpeg_destination_mgr {
        JOCTET *next_output_byte;     /* => next byte to write in buffer */
        size_t free_in_buffer;        /* # of byte spaces remaining in buffer */
      
        void (*init_destination) (j_compress_ptr cinfo);
        boolean (*empty_output_buffer) (j_compress_ptr cinfo);
        void (*term_destination) (j_compress_ptr cinfo);
      };
      

      您需要设置init_destinationempty_output_bufferterm_destination回调,并根据情况设置next_output_bytefree_in_buffer

      • init_destination 用于初始化,写信给std::vector 时不需要做任何特别的事情
      • empty_output_buffer 在提供的缓冲区已满时调用(即free_in_buffer==0);当写入std::vector 时,您可以通过设置next_output_bytefree_in_buffer 来增大缓冲区并返回新的空闲内存
      • term_destination 在压缩完成时被调用,但有可能(实际上,很可能)最后一个缓冲区没有完全填满(即free_in_buffer&gt;0);当写入std::vector 时,这可用于将矢量调整为最终大小
      struct stdvector_destination_mgr
      {
          struct jpeg_destination_mgr pub;        // public fields
          std::vector< uint8_t >* vec = nullptr;  // destination vector
      };
      
      void init_stdvector_destination( j_compress_ptr /*cinfo*/ )
      {
          // Nothing to do
      }
      
      boolean
      empty_stdvector_output_buffer( j_compress_ptr cinfo )
      {
          auto* dest = reinterpret_cast< stdvector_destination_mgr* >( cinfo->dest );
      
          // Double vector capacity
          const auto currentSize = dest->vec->size( );
          dest->vec->resize( currentSize * 2 );
      
          // Point to newly allocated data
          dest->pub.next_output_byte = dest->vec->data( ) + currentSize;
          dest->pub.free_in_buffer = currentSize;
      
          return TRUE;
      }
      
      void
      term_stdvector_destination( j_compress_ptr cinfo )
      {
          auto* dest = reinterpret_cast< stdvector_destination_mgr* >( cinfo->dest );
      
          // Resize vector to number of bytes actually used
          const auto used_bytes = dest->vec->capacity( ) - dest->pub.free_in_buffer;
          dest->vec->resize( used_bytes );
      }
      
      void
      jpeg_stdvector_dest( j_compress_ptr cinfo, std::vector< uint8_t >& vec )
      {
          if ( cinfo->dest == NULL )
          {
              cinfo->dest = (struct jpeg_destination_mgr*)( *cinfo->mem->alloc_small )( (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof( stdvector_destination_mgr ) );
          }
      
          auto* dest = reinterpret_cast< stdvector_destination_mgr* >( cinfo->dest );
          dest->pub.init_destination = init_stdvector_destination;
          dest->pub.empty_output_buffer = empty_stdvector_output_buffer;
          dest->pub.term_destination = term_stdvector_destination;
      
          // Set output buffer and initial size
          dest->vec = &vec;
          dest->vec->resize( 4096 );
      
          // Initialize public buffer ptr and size
          dest->pub.next_output_byte = dest->vec->data( );
          dest->pub.free_in_buffer = dest->vec->size( );
      }
      

      【讨论】:

        【解决方案3】:

        您必须查看文档。 但是 outbuffer 是一个无符号字符 **。所以几乎可以肯定的功能 将调用 malloc,然后将 outbuffer 设置为结果。

        /*
           skeleton code - it won't be this exactly but will
           look like this.
        */ 
        EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
                           unsigned char ** outbuffer,
                           unsigned long * outsize))
        {
           int width, height;
           unsigned char *rgba;
        
           getimagesize(cinfo, &width, & height);
           rgba = malloc(width * height * 4);
        
           decompress(cinfo, rgba);
        
           *outbuffer = rgba;
           *outsize = width * height *4;
        }
        

        所以打电话

        unsigned char *rgba;
        unsigned long size;
        std::vector<unsigned char> buffer.
        jpeg_mem_dest(jpegdata, &rgba, &size);
        if(size > 0)
        {
           buffer.resize(size);
           for(i=0;i<size;i++)
             buffer[i] = rgba[i];
           free(rgba);
        }
        

        【讨论】:

        • 我无法让它工作。要么出现写访问冲突,要么出现没有描述的奇怪崩溃。您能否提供一个工作示例?将不胜感激。还有一种方法可以绕过 rgba 数组并直接写入我的std::vector
        • 我没有库。我无法编译一个工作示例。它是在调用中崩溃还是访问缓冲区?也许您只需要将 rgba 初始化为零。查找函数接口规范。
        • 没有意义。
        猜你喜欢
        • 1970-01-01
        • 2015-12-05
        • 1970-01-01
        • 2015-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-11
        • 2015-11-21
        相关资源
        最近更新 更多