c++ c libjpeg

c++ - Escribir en el búfer de memoria en lugar de un archivo con libjpeg?



(5)

Hay una función predefinida jpeg_mem_src definida en jdatasrc.c . El ejemplo de uso más simple:

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

No te olvides de desasignar tu buffer.

He encontrado esta función que usa libjpeg para escribir en un archivo:

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; }

Realmente necesitaría escribir la imagen comprimida jpeg solo en el búfer de memoria, sin guardarla en un archivo, para ahorrar tiempo. ¿Podría alguien darme un ejemplo de cómo hacerlo?

He estado buscando en la web por un tiempo, pero la documentación es muy rara si es que es difícil encontrar ejemplos.


He probado la solución de Mark y en mi plataforma siempre da un error de SEGMENTACIÓN FALUTO cuando se ejecuta

cinfo->dest->term_destination = &my_term_destination;

Y me volví a los códigos fuente de jpeglib (jdatadst.c) y encontré esto:

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

justo debajo del método jpeg_stdio_dest (), y lo he intentado simplemente completando la dirección del búfer (char *) y la dirección del tamaño del búfer (int). El administrador de destino asigna automáticamente la memoria para el búfer y el programa necesita liberar la memoria después de su uso.

Se ejecuta con éxito en mi plataforma, Beaglebone Black con el Angstrom Linux preinstalado. Mi versión libjpeg es 8d.


Puede definir su propio gestor de destinos con bastante facilidad. El jpeg_compress_struct contiene un puntero a un jpeg_destination_mgr , que contiene un puntero a un búfer, un recuento de espacio dejado en el búfer y 3 punteros a las funciones:

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

Debe completar los punteros de función antes de realizar la primera llamada a la biblioteca jpeg y dejar que esas funciones manejen el búfer. Si crea un búfer que es más grande que la salida más grande posible que espera, esto se vuelve trivial; init_destination simplemente llena el puntero del búfer y cuenta, y empty_output_buffer y term_destination no hacen nada.

Aquí hay un código de ejemplo:

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;


Todo lo que necesitas hacer es pasar un objeto similar a FILE a jpeg_stdio_dest() .


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;

Esto es todo lo que necesitas leer.

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

Y esto es todo lo que necesitas escribir.