2012-02-01 14 views
20

Las instrucciones para libjpeg-turbo here describen la API TurboJPEG así: "Esta API ajusta libjpeg-turbo y proporciona una interfaz fácil de usar para comprimir y descomprimir imágenes JPEG en la memoria" . Genial, pero ¿hay algunos ejemplos sólidos del uso de esta API disponible? Simplemente buscando descomprimir un jpeg bastante vainilla en la memoria.Ejemplos o tutoriales sobre el uso de libjpeg-turbo TurboJPEG

He encontrado algunos bits como https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c, que parece estar utilizando la API TurboJPEG, pero ¿hay algún otro ejemplo más sólido/variado?

La fuente de libjpeg-turbo está bien documentada, por lo que ayuda.

Respuesta

4

Al final he utilizado una combinación de código aleatorio encontrado en el Internet (por ejemplo https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c) y los archivos .c y de cabecera para libjeg-turbo, que están bien documentados. This API oficial es una buena fuente de información también.

+0

Si el código es pequeño, puede compartirlo aquí para mejorar su respuesta;) –

+0

Voy a buscarlo en algún momento y añadirlo a la respuesta. – occulus

1

Aquí hay un fragmento de código que utilizo para cargar los archivos jpeg de la memoria. Quizás requiera un poco de fijación, porque lo extraje de diferentes archivos en mi proyecto. Cargará ambas imágenes: escala de grises y rgb (bpp se establecerá en 1 o en 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; 
} 
+1

Siento inaceptables desde su respuesta, pero al mirar de cerca ahora estoy realmente la aplicación de este Veo que ni siquiera está llamando a funciones tj en el código que envió (por ejemplo tjDecompress). – occulus

+0

No es obligatorio utilizar la API TurboJpeg para obtener beneficios de velocidad de la biblioteca libjpeg-turbo. En mi ejemplo, estoy usando solo la API libjpeg estándar. ¿Por qué no quieres usar API libjpeg? –

+2

Mi pregunta es muy clara sobre la API de TurboJPEG. Lo estoy usando debido a su simplicidad en comparación con la interfaz libjpeg estándar. – occulus

43

Ok, sé que ya resolvió su problema, pero como algunas personas, como yo, podrían estar buscando un ejemplo simple, compartiré lo que creé. Es un ejemplo, comprime y descomprime una imagen RGB. De lo contrario, creo que la documentación API de TurboJPEG es bastante fácil de entender.

Compresión:

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

Después de que usted tiene la imagen comprimida en _compressedImage. Para descomprimir lo que tiene que hacer lo siguiente:

Descompresión:

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

algunos pensamientos al azar:

yo acabamos de volver sobre esto como estoy escribiendo mi tesis de licenciatura, y Me di cuenta de que si ejecuta la compresión en un bucle, es preferible almacenar el mayor tamaño del búfer JPEG para no tener que asignar uno nuevo cada turno. Básicamente, en lugar de hacerlo:

long unsigned int _jpegSize = 0; 

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

que habría que añadir una variable de objeto, manteniendo el tamaño de la memoria asignada long unsigned int _jpegBufferSize = 0; y antes de cada ronda de compresión queremos establecer el jpegSize de nuevo a ese valor:

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; 

después de la compresión, uno compararía el tamaño de la memoria con el jpegSize real y lo establecería en jpegSize si es más alto que el tamaño de memoria anterior.

+1

¡Esto es maravilloso! ¡Gracias! – mousomer

+0

Lo intentaré. La documentación de turbojpeg dice que esta debería ser la longitud de la fila. No entiendo de salida o entrada. de todos modos, estaba equivocado. Los tamaños son razonables. Por cierto, actualmente estoy cargando (descomprimiendo) jpeg y recortando regiones en archivos. ¿Hay un 2-liner turbojpeg para recortar una imagen y enviar la salida a un archivo? – mousomer

+0

Hice justamente eso: memcpy la región recortada línea por línea en un búfer (2 líneas para el bucle), compresión jpeg (1 línea) y escritura en fstream (4 líneas). Solo pensé que tal vez ya hay una función de biblioteca haciéndolo. – mousomer

1

Terminé usando el código siguiente como ejemplo de trabajo para codificación y decodificación JPEG. El mejor ejemplo que puedo encontrar es autocontenido que inicializa una imagen ficticia y muestra la imagen codificada en un archivo local.

El siguiente código es NO el mío, el crédito va a https://sourceforge.net/p/libjpeg-turbo/discussion/1086868/thread/e402d36f/#8722. Publicarlo aquí de nuevo para ayudar a cualquier persona a encontrar que es difícil hacer funcionar 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; 
} 
Cuestiones relacionadas