Подтвердить что ты не робот

Примеры или руководства по использованию libjpeg-turbo TurboJPEG

Инструкции для libjpeg-turbo здесь описывают API TurboJPEG таким образом: "Этот API обертывает libjpeg-turbo и обеспечивает простоту использования интерфейс для сжатия и распаковки изображений JPEG в памяти". Отлично, но есть ли веские примеры использования этого API? Просто хочу распаковать довольно ванильный jpeg в памяти.

Я нашел несколько бит, например https://github.com/erlyvideo/jpeg/blob/master/c_src/jpeg.c, который, по-видимому, использует API TurboJPEG, но есть ли какие-либо более прочные/различные примеры?

Источник для libjpeg-turbo хорошо документирован, так что это помогает.

4b9b3361

Ответ 2

Хорошо, я знаю, что вы уже решили свою проблему, но поскольку некоторые люди, как и я, могут найти простой пример, я поделюсь тем, что создал. Это пример, сжимающий и распаковывающий изображение RGB. В противном случае я думаю, что документацию API TurboJPEG довольно легко понять!

Сжатие:

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

После этого у вас есть сжатое изображение в _compressedImage. Для распаковки вам необходимо сделать следующее:

Декомпрессия:

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

Некоторые случайные мысли:

Я только что вернулся к этому, так как я пишу свой диплом бакалавра, и я заметил, что если вы выполняете сжатие в цикле, предпочтительнее хранить самый большой размер буфера JPEG, чтобы не выделять новый очередь. В основном, вместо того, чтобы делать:

long unsigned int _jpegSize = 0;

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

мы добавили бы объектную переменную, содержащую размер выделенной памяти long unsigned int _jpegBufferSize = 0;, и перед каждым раундом сжатия мы вернем значение jpegSize для этого значения:

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;

после сжатия можно сравнить размер памяти с фактическим jpegSize и установить его в jpegSize, если он выше, чем предыдущий размер памяти.

Ответ 3

Здесь фрагмент кода, который я использую для загрузки jpeg из памяти. Возможно, это потребует немного исправления, потому что я извлек его из разных файлов в моем проекте. Он будет загружать изображения в виде серого и rgb (bpp будет установлен как 1 или 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;
}