PDA

View Full Version : Can't use libturbojpeg to load image files



donelron
28th September 2015, 23:29
Dear all,

I am trying to speed up the loading of a JPEG image by replacing the decode step during the loading with some libturbojpeg functions.
So I put together a minimal working example from several pieces which I found in forums etc:


.pro file:

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = Application
TEMPLATE = app


SOURCES += main.cpp\
mainwindow.cpp\
JpegEncoderDecoder/JpegEncoderDecoder.cpp

HEADERS += mainwindow.h\
JpegEncoderDecoder/JpegEncoderDecoder.h

FORMS += mainwindow.ui


LIBS += -L$$PWD/usr/lib/ -ljpeg -lturbojpeg

INCLUDEPATH += $$PWD/usr/include
DEPENDPATH += $$PWD/usr/include



main.cpp:

#include "mainwindow.h"
#include <QApplication>
#include <QImageReader>
#include <QByteArray>
#include <QFile>
#include <QBuffer>
#include <QString>

#include <jpeglib.h>

#include <iostream>
#include <fstream>
#include <string>

#include <JpegEncoderDecoder/JpegEncoderDecoder.h>


int read_jpeg_file(unsigned char *pInputDataStream, std::string file_name)
{
std::ifstream imageStream;
imageStream.open(file_name.c_str(), std::ios_base::binary);

imageStream.seekg (0, std::ios::end);
int n = imageStream.tellg();
imageStream.seekg (0, std::ios::beg);

pInputDataStream = new unsigned char[n];


if (!imageStream.is_open())
{
std::cout << stderr << "Can't open input file !\n";
exit(1);
}
else
{
imageStream.read((char *)pInputDataStream, n);
}
return 0;
}



int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QString qPath("jpeg-100.jpg");

unsigned char *pInputDataStream;
int width = 320;
int height= 240;
int JPEG_QUALITY=75;
int COLOR_COMPONENTS=3;
int in_len = width*height*COLOR_COMPONENTS;
std::string strFileName=qPath.toStdString();

//Step 1: Load .jpeg in memory filebuffer
int iRead = read_jpeg_file(pInputDataStream, strFileName);

//Step 2: Use turbojpeglib to decompress filebuffer to uncompressedbuffer
JpegEncoderDecoder bla(width, height, JPEG_QUALITY, COLOR_COMPONENTS);
unsigned char*buffer = bla.decodeJpeg(pInputDataStream);

//Step 3: Convert to QImage
QImage myDecodedJPEGimage(buffer, width, height, QImage::Format_RGB888) ;

//Step 4: Show in main window
MainWindow w(myDecodedJPEGimage);
w.show();

return a.exec();
}




JpegEncoderDecoder.h:

#ifndef JPEGENCODERDECODER_H
#define JPEGENCODERDECODER_H

class JpegEncoderDecoder
{
public:
JpegEncoderDecoder(int width=1920, int height=1080, int JPEG_QUALITY=75, int COLOR_COMPONENTS=3);

void encodeJpeg(unsigned char * pBuffer);
unsigned char * decodeJpeg(unsigned char * pcompressedImage);

private:
int m_width;
int m_height;
const int m_JPEG_QUALITY ;
const int m_COLOR_COMPONENTS;
};

#endif // JPEGENCODERDECODER_H






// some includes....

JpegEncoderDecoder::JpegEncoderDecoder(int width, int height, int JPEG_QUALITY, int COLOR_COMPONENTS) :
m_width (width)
, m_height(height)
, m_JPEG_QUALITY(JPEG_QUALITY)
, m_COLOR_COMPONENTS(COLOR_COMPONENTS)
{
}

unsigned char * JpegEncoderDecoder::decodeJpeg(unsigned char *pcompressedImage)
{
long unsigned int _jpegSize; //!< _jpegSize from above


int jpegSubsamp;
unsigned char buffer[m_width*m_height*m_COLOR_COMPONENTS]; //!< will contain the decompressed image

tjhandle _jpegDecompressor = tjInitDecompress();

tjDecompressHeader2(_jpegDecompressor, pcompressedImage, _jpegSize, &m_width, &m_height, &jpegSubsamp);

tjDecompress2(_jpegDecompressor, pcompressedImage, _jpegSize, buffer, m_width, 0/*pitch*/, m_height, TJPF_RGB, TJFLAG_FASTDCT);

tjDestroy(_jpegDecompressor);

return buffer;
}

I am omitting the definition of JpegEncoderDecoder::encodeJpeg, as well as mainwindow.h and mainwindow.cpp here.


This is compiling and also running fine, but unfortunately it does not show the image as expected. Instead I just see a black rectangle with some colored pixels in it. What am I doing wrong?

d_stranz
29th September 2015, 01:07
I am omitting the definition of JpegEncoderDecoder::encodeJpeg, as well as mainwindow.h and mainwindow.cpp here.



MainWindow w(myDecodedJPEGimage);

Well, since all the magic associated with actually displaying the image you might have loaded is occurring inside this constructor, don't you think it would be helpful to someone trying to figure out what might be wrong to post that code as well?

Nah, I guess not. We'll just make something up.

anda_skoa
29th September 2015, 11:12
Have you tried saving the QImage to file and see if it is correct there?
I.e. see if displaying the image is the problem or if the image is corrupted already.

A guess could be that the image format passed to the QImage constructor is not actually the format of the data.

Cheers,
_

Infinity
29th September 2015, 13:42
The data buffer points to is freed when your decodeJpeg function returns. Hence the data can not be used outside the function.

Why not using QImage directly? It can decode JPEG with the image format plugin for JPEG.

ChrisW67
29th September 2015, 22:16
JpegEncoderDecoder() also seems to be using _jpegSize unitialised.

donelron
1st October 2015, 02:11
Well, since all the magic associated with actually displaying the image you might have loaded is occurring inside this constructor, don't you think it would be helpful to someone trying to figure out what might be wrong to post that code as well?


No big deal: it's just

MainWindow::MainWindow(QImage qIma, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

m_scene.addPixmap(QPixmap::fromImage(qIma));
ui->graphicsView->setScene(&m_scene);
ui->graphicsView->show();

}


The QImage I pass into the ctor of MainWindow must already be broken, i guess...



Well, since all the magic associated with actually displaying the image you might have loaded is occurring inside this constructor, don't you think it would be helpful to someone trying to figure out what might be wrong to post that code as well?


No big deal: it's just

MainWindow::MainWindow(QImage qIma, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

m_scene.addPixmap(QPixmap::fromImage(qIma));
ui->graphicsView->setScene(&m_scene);
ui->graphicsView->show();

}


The QImage I pass into the ctor of MainWindow must already be broken, i guess...

Added after 7 minutes:


Why not using QImage directly? It can decode JPEG with the image format plugin for JPEG.

I know that this is possible. However, I am trying to speed up the loading of images like it is described here: http://stackoverflow.com/questions/21726338/what-is-the-fastest-way-to-render-a-jpeg-file-on-to-a-qwidget
Apparently this method offers "at least 3x speedup compared to QImage::loadFromData()"

Infinity
1st October 2015, 14:10
The imageformats plugin for JPEG (libqjpeg.so) links against libjpeg.so.8 which is provided by the libjpeg-turbo package of my GNU/Linux distribution. There are also mingw-w64 cross-compiler packages I use to build Windows binaries. These also link against libjpeg-turbo.
So using QImage::loadFromData() with libjpeg-turbo is possible. Hence I think manual usage of libjpeg-turbo is not necessary to speedup decoding.