Exemples ou tutoriels d'utilisation de libjpeg-TurboJPEG de turbo
les instructions pour libjpeg-turbo ici décrit ainsi L'API TurboJPEG:"cette API enroule libjpeg-turbo et fournit une interface facile à utiliser pour compresser et décompresser les images JPEG en mémoire". Super, mais y a-t-il de bons exemples d'utilisation de cette API? Je cherche juste à décompresser un jpeg assez vanille en mémoire.
j'ai trouvé quelques morceaux tels que https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c/" class="blnk">c, qui semble être en utilisant L'API TurboJPEG, mais y a-t-il d'autres exemples solides/variés?
la source de libjpeg-turbo est bien documentée, donc cela aide.
4 réponses
Ok, je sais que vous avez déjà résolu votre problème, mais comme certaines personnes, tout comme moi, pourraient être à la recherche d'un exemple simple, je vais partager ce que j'ai créé. Il s'agit d'un exemple de compression et de décompression d'une image RVB. Sinon, je pense que la documentation API de TurboJPEG est assez facile à comprendre!
Compression:
#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);
après cela, vous avez l'image compressée dans _compressedImage. Pour décompresser vous devez faire le suivantes:
Décompression:
#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);
Quelques pensées éparses:
je viens de revenir sur ce que je suis en train d'écrire ma thèse de baccalauréat, et j'ai remarqué que si vous exécutez la compression dans une boucle, il est préférable de stocker la plus grande taille du tampon JPEG pour ne pas avoir à allouer un nouveau à chaque tour. En gros, au lieu de faire:
long unsigned int _jpegSize = 0;
tjCompress2(_jpegCompressor, buffer, _width, 0, _height, TJPF_RGB,
&_compressedImage, &_jpegSize, TJSAMP_444, JPEG_QUALITY,
TJFLAG_FASTDCT);
nous ajouterions une variable objet, en maintenant la taille de l'attribut de mémoire long unsigned int _jpegBufferSize = 0;
et avant chaque round de compression, nous ramenions le jpegSize à cette valeur:
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;
après la compression, on comparera la taille de la mémoire avec la taille réelle jpegSize et on la réglera sur la taille jpegSize si elle est supérieure à la taille de la mémoire précédente.
a la fin j'ai utilisé une combinaison de code aléatoire trouvé sur internet (par exemple https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c) et le .c et les fichiers d'en-tête pour libjeg-turbo, qui sont bien documentés. L'API officielle est également une bonne source d'information.
j'ai fini par utiliser le code ci-dessous comme exemple de travail pour l'encodage JPEG et le décodage. Le meilleur exemple que je puisse trouver, c'est l'Auto-contenu qui initialise une image factice et affiche l'image encodée dans un fichier local.
en dessous du code est perso, crédit va à https://sourceforge.net/p/libjpeg-turbo/discussion/1086868/thread/e402d36f/#8722 . Le poster ici à nouveau pour aider quelqu'un trouve qu'il est difficile d'obtenir libjpeg turbo travailler.
#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;
}
voici un fragment de code que j'utilise pour charger les jpeg de mémoire. Peut-être qu'il faudra un peu de correction, parce que je l'ai extrait de différents fichiers dans mon projet. Il chargera à la fois les images-grayscale et rgb (bpp sera positionné soit à 1 soit à 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;
}