Как сжать в память с помощью libjpeg-turbo, используя jpeg_mem_dest
Я пытался следовать другому ответу, но просто не могу понять это правильно. У меня есть около 8 МБ растрового изображения RBGX для преобразования в формат JPEG в памяти с помощью libjpeg-turbo. Если я использую jpeg_stdio_dest
Я могу записать все это в файл, затем прочитать файл обратно, и все в порядке. Тем не менее, пытаясь использовать jpeg_mem_dest
был загадкой Я все равно настроил как jpeg_stdio_dest
, но используя mem
кажется, только сделать одно выделение 4 КБ, а затем никогда не выделять больше места.
Я не могу найти документы с дальнейшими инструкциями по использованию jpeg_mem_dest
и действительно мог бы использовать какое-то направление.
void compress(std::vector<unsigned char>& input) {
jpeg_compress_struct cinfo{};
jpeg_error_mgr err{};
cinfo.err = jpeg_std_error(&err);
jpeg_create_compress(&cinfo);
#if 0 // using this with an open FILE* out works
jpeg_stdio_dest(&cinfo, out);
#endif
cinfo.image_width = kWidth; // constants defined somewhere
cinfo.image_height = kHeight;
cinfo.input_components = 4;
cinfo.in_color_space = JCS_EXT_RGBX;
// what's wrong with this?
unsigned char* buf{};
unsigned long buf_sz{};
jpeg_mem_dest(&cinfo, &buf, &buf_sz);
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 70, true);
jpeg_start_compress(&cinfo, true);
while (cinfo.next_scanline < cinfo.image_height) {
auto row = static_cast<JSAMPROW>(&input[cinfo.next_scanline * 4 * kWidth]);
jpeg_write_scanlines(&cinfo, &row, 1);
// Always prints 4096, and buf never changes
std::cout << "buf_sz: " << buf_sz
<< " buf: " << static_cast<void*>(buf) << '\n';
}
jpeg_finish_compress(&cinfo);
// ...
// in reality, return the compressed data
}
1 ответ
Да, это совсем не интуитивно понятно. Программист, предложивший твик jpeg_mem_dest(), не имел большого выбора, расширять существующий API-интерфейс не так просто, когда он изначально не предназначен для поддержки функции. Что совершенно неочевидно, так это то, что ваши переменные не обновляются до тех пор, пока не будет вызван jpeg_finish_compress(). Соответствующий код в библиотеке:
METHODDEF(void)
term_mem_destination (j_compress_ptr cinfo)
{
my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
*dest->outbuffer = dest->buffer;
*dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);
}
Обратите внимание на слово "термин". Эта функция вызывается косвенно через указатель на функцию:
GLOBAL(void)
jpeg_finish_compress (j_compress_ptr cinfo)
{
//...
/* Write EOI, do final cleanup */
(*cinfo->marker->write_file_trailer) (cinfo);
(*cinfo->dest->term_destination) (cinfo);
//...
}
Вы ничего не можете с этим поделать. Просто настройте код std::cout, переместите его после цикла, чтобы приспособить работу библиотеки.
Остерегайтесь других мелких деталей этой функции, также не очевидных. Вы должны освободить () буфер, который он создал. Видно в предоставленном примере программы cjpeg.c, конец main().