使用 libjpeg 写入内存缓冲区而不是文件?

发布于 2024-10-09 19:55:25 字数 1585 浏览 0 评论 0原文

我发现这个函数使用 libjpeg 写入文件:

int write_jpeg_file( char *filename )
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    /* this is a pointer to one row of image data */
    JSAMPROW row_pointer[1];
    FILE *outfile = fopen( filename, "wb" );

    if ( !outfile )
    {
        printf("Error opening output jpeg file %s\n!", filename );
        return -1;
    }
    cinfo.err = jpeg_std_error( &jerr );
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    /* Setting the parameters of the output file here */
    cinfo.image_width = width;  
    cinfo.image_height = height;
    cinfo.input_components = bytes_per_pixel;
    cinfo.in_color_space = color_space;
    /* default compression parameters, we shouldn't be worried about these */
    jpeg_set_defaults( &cinfo );
    /* Now do the compression .. */
    jpeg_start_compress( &cinfo, TRUE );
    /* like reading a file, this time write one row at a time */
    while( cinfo.next_scanline < cinfo.image_height )
    {
        row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width *  cinfo.input_components];
        jpeg_write_scanlines( &cinfo, row_pointer, 1 );
    }
    /* similar to read file, clean up after we're done compressing */
    jpeg_finish_compress( &cinfo );
    jpeg_destroy_compress( &cinfo );
    fclose( outfile );
    /* success code is 1! */
    return 1;
}

实际上,我需要将 jpeg 压缩图像写入内存缓冲区,而不将其保存到文件中,以节省时间。有人可以给我一个例子如何做到这一点吗?

我已经在网上搜索了一段时间,但文档非常少(如果有的话),并且示例也很难获得。

I have found this function which uses libjpeg to write to a file:

int write_jpeg_file( char *filename )
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    /* this is a pointer to one row of image data */
    JSAMPROW row_pointer[1];
    FILE *outfile = fopen( filename, "wb" );

    if ( !outfile )
    {
        printf("Error opening output jpeg file %s\n!", filename );
        return -1;
    }
    cinfo.err = jpeg_std_error( &jerr );
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    /* Setting the parameters of the output file here */
    cinfo.image_width = width;  
    cinfo.image_height = height;
    cinfo.input_components = bytes_per_pixel;
    cinfo.in_color_space = color_space;
    /* default compression parameters, we shouldn't be worried about these */
    jpeg_set_defaults( &cinfo );
    /* Now do the compression .. */
    jpeg_start_compress( &cinfo, TRUE );
    /* like reading a file, this time write one row at a time */
    while( cinfo.next_scanline < cinfo.image_height )
    {
        row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width *  cinfo.input_components];
        jpeg_write_scanlines( &cinfo, row_pointer, 1 );
    }
    /* similar to read file, clean up after we're done compressing */
    jpeg_finish_compress( &cinfo );
    jpeg_destroy_compress( &cinfo );
    fclose( outfile );
    /* success code is 1! */
    return 1;
}

I would actually need to write the jpeg compressed image just to memory buffer, without saving it to a file, to save time. Could somebody give me an example how to do it?

I have been searching the web for a while but the documentation is very rare if any and examples are also difficult to come by.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

漆黑的白昼 2024-10-16 19:55:25

您可以非常轻松地定义自己的目的地管理器。 jpeg_compress_struct 包含一个指向 jpeg_destination_mgr 的指针,其中包含一个指向缓冲区的指针、缓冲区中剩余空间的计数以及 3 个指向函数的指针:

init_destination (j_compress_ptr cinfo)
empty_output_buffer (j_compress_ptr cinfo)
term_destination (j_compress_ptr cinfo)

您需要填充在第一次调用 jpeg 库之前在函数指针中,并让这些函数处理缓冲区。如果您创建的缓冲区大于您期望的最大可能输出,那么这将变得微不足道; init_destination 只是填充缓冲区指针和计数,而 empty_output_bufferterm_destination 不执行任何操作。

这是一些示例代码:

std::vector<JOCTET> my_buffer;
#define BLOCK_SIZE 16384

void my_init_destination(j_compress_ptr cinfo)
{
    my_buffer.resize(BLOCK_SIZE);
    cinfo->dest->next_output_byte = &my_buffer[0];
    cinfo->dest->free_in_buffer = my_buffer.size();
}

boolean my_empty_output_buffer(j_compress_ptr cinfo)
{
    size_t oldsize = my_buffer.size();
    my_buffer.resize(oldsize + BLOCK_SIZE);
    cinfo->dest->next_output_byte = &my_buffer[oldsize];
    cinfo->dest->free_in_buffer = my_buffer.size() - oldsize;
    return true;
}

void my_term_destination(j_compress_ptr cinfo)
{
    my_buffer.resize(my_buffer.size() - cinfo->dest->free_in_buffer);
}

cinfo->dest->init_destination = &my_init_destination;
cinfo->dest->empty_output_buffer = &my_empty_output_buffer;
cinfo->dest->term_destination = &my_term_destination;

You can define your own destination manager quite easily. The jpeg_compress_struct contains a pointer to a jpeg_destination_mgr, which contains a pointer to a buffer, a count of space left in the buffer, and 3 pointers to functions:

init_destination (j_compress_ptr cinfo)
empty_output_buffer (j_compress_ptr cinfo)
term_destination (j_compress_ptr cinfo)

You need to fill in the function pointers before you make the first call into the jpeg library, and let those functions handle the buffer. If you create a buffer that is larger than the largest possible output that you expect, this becomes trivial; init_destination just fills in the buffer pointer and count, and empty_output_buffer and term_destination do nothing.

Here's some sample code:

std::vector<JOCTET> my_buffer;
#define BLOCK_SIZE 16384

void my_init_destination(j_compress_ptr cinfo)
{
    my_buffer.resize(BLOCK_SIZE);
    cinfo->dest->next_output_byte = &my_buffer[0];
    cinfo->dest->free_in_buffer = my_buffer.size();
}

boolean my_empty_output_buffer(j_compress_ptr cinfo)
{
    size_t oldsize = my_buffer.size();
    my_buffer.resize(oldsize + BLOCK_SIZE);
    cinfo->dest->next_output_byte = &my_buffer[oldsize];
    cinfo->dest->free_in_buffer = my_buffer.size() - oldsize;
    return true;
}

void my_term_destination(j_compress_ptr cinfo)
{
    my_buffer.resize(my_buffer.size() - cinfo->dest->free_in_buffer);
}

cinfo->dest->init_destination = &my_init_destination;
cinfo->dest->empty_output_buffer = &my_empty_output_buffer;
cinfo->dest->term_destination = &my_term_destination;
我不吻晚风 2024-10-16 19:55:25

jdatasrc.c 中定义了一个预定义函数 jpeg_mem_src。最简单的使用示例:

unsigned char *mem = NULL;
unsigned long mem_size = 0;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &mem, &mem_size);

// do compression

// use mem buffer

不要忘记释放缓冲区。

There is a predefined function jpeg_mem_src defined in jdatasrc.c. The simplest usage example:

unsigned char *mem = NULL;
unsigned long mem_size = 0;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, &mem, &mem_size);

// do compression

// use mem buffer

Do not forget to deallocate your buffer.

再可℃爱ぅ一点好了 2024-10-16 19:55:25

我已经尝试过马克的解决方案,在我的平台上执行时它总是给出 SEGMENTATION FALUT 错误

cinfo->dest->term_destination = &my_term_destination;

我转向 jpeglib 源代码(jdatadst.c)并发现了这个:

jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize)

就在方法 jpeg_stdio_dest() 的下面,我已经尝试过只需填写缓冲区的地址(char*)和缓冲区大小的地址(int)。目标管理器自动为缓冲区分配内存,程序在使用后需要释放内存。

它在我的平台 Beaglebone Black 上成功运行,并预装了 Angstrom Linux。我的 libjpeg 版本是 8d。

I have tried Mark's solution and on my platform it always gives SEGMENTATION FALUT error when it executes

cinfo->dest->term_destination = &my_term_destination;

And I turned to the jpeglib source codes (jdatadst.c) and found this:

jpeg_mem_dest (j_compress_ptr cinfo, unsigned char ** outbuffer, unsigned long * outsize)

just below the method jpeg_stdio_dest(), and I've tried it by simply fill in the address of the buffer(char*) and the address of the buffer size(int). The destination manager automatically allocates memory for the buffer and the program need to free the memory after use.

It successfully runs on my platform, Beaglebone Black with the pre-installed Angstrom Linux. My libjpeg version is 8d.

转角预定愛 2024-10-16 19:55:25

您所需要做的就是将类似 FILE 的对象传递给 jpeg_stdio_dest()

All you need to do is pass a FILE-like object to jpeg_stdio_dest().

_畞蕅 2024-10-16 19:55:25
unsigned char ***image_ptr    
unsigned char* ptr;
unsigned char** image_buf;

for(int i=0;i<h;i++){
image_buf[i] = new unsigned char[w*o];
}

ptr = image_buf[0];

     while (info.output_scanline < info.image_height) {

    jpeg_read_scanlines(&info,&ptr,1);

    ptr = image_buf[c]; 

    c++;


    }

    *image_ptr = image_buf;

这就是您需要阅读的全部内容。

JSAMPROW row_pointer; 

       while (info.next_scanline < info.image_height) {

        row_pointer = &image_buf[info.next_scanline][0];

           (void) jpeg_write_scanlines(&info, &row_pointer, 1);



                                }

这就是您需要写的全部内容。

unsigned char ***image_ptr    
unsigned char* ptr;
unsigned char** image_buf;

for(int i=0;i<h;i++){
image_buf[i] = new unsigned char[w*o];
}

ptr = image_buf[0];

     while (info.output_scanline < info.image_height) {

    jpeg_read_scanlines(&info,&ptr,1);

    ptr = image_buf[c]; 

    c++;


    }

    *image_ptr = image_buf;

This is all you need to read.

JSAMPROW row_pointer; 

       while (info.next_scanline < info.image_height) {

        row_pointer = &image_buf[info.next_scanline][0];

           (void) jpeg_write_scanlines(&info, &row_pointer, 1);



                                }

And this is all you need to write.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文