PDA

View Full Version : Storage and View -> imageViewer



C167
5th January 2008, 17:01
Hi,
I'm developing an Qt4 (ATM 4.4) app that will be started from a CD on Windows Hosts. It contains an image viewer and some other stuff.
Now, i use a QLabel to display the image via QPixmap (exactly like in the examples). A SQLite3-DB is attached storing some information to the images.
Is a QLabel already the best way for displaying images? I saw the use of QGraphicsScene and QGraphicsView in an other post in this forum.

ATM, the images are JPG-files laying in an directory (using subfolders as albums). Do I have to take care of anything if i want to store the images completly in the DB? Images are in an binary format, SQLite only offers text and some numerical types, so do i have to use base64-algorythms for that?
C167

jacek
5th January 2008, 17:12
Is a QLabel already the best way for displaying images?
It depends on what you need. QLabel is perfect if you just want to display an image, but if you need more features, QGV might be better.


Do I have to take care of anything if i want to store the images completly in the DB?
Qt should handle this for you. Just try passing images as QVariants to QSqlQuery.

You can also consider using Qt's binary resource files and put every album in a separate .rcc file. See: http://doc.trolltech.com/4.3/resources.html

C167
5th January 2008, 17:46
hm... the app has a minimal size, but no maximum. so the image should be scaled. AFAIR the example does that.

I haven't used QVariant so far...
QFile *file("./image1.jpg");
QPixmap *map(QPixmap::fromImage(file));
QByteArray bytes;
QBuffer buffer(&bytes);
buffer.open(QIODevice::WriteOnly);
map->save(&buffer, "JPG");
QVariant variant(bytes);and then put it via "INSERT INTO ....." into the DB?

If i put some hundrets of Images in the rcc's, i'll have a binary which is about 500MBs at size, am i right?

Edit: Oh, i forgot, another guy wants to write a single imageviewer in Java, so he should at least know if there is an easy way to read the data in a Qt-Free Java environment

jacek
5th January 2008, 17:57
hm... the app has a minimal size, but no maximum. so the image should be scaled.
If all you need is an ability to show a single, scaled image, then QLabel will be enough.


I haven't used QVariant so far...
QFile *file("./image1.jpg");
QPixmap *map(QPixmap::fromImage(file));
QByteArray bytes;
QBuffer buffer(&bytes);
buffer.open(QIODevice::WriteOnly);
map->save(&buffer, "JPG");
QVariant variant(bytes);
All you need is:
QVariant variant = QPixmap( "./image1.jpg" );


and then put it via "INSERT INTO ....." into the DB?
Yes, but you have to use placeholder and QSqlQuery::bindValue().



If i put some hundrets of Images in the rcc's, i'll have a binary which is about 500MBs at size, am i right?
Yes, but you can have several rcc files. If you store all of the images in the database, you'll get even bigger file.

C167
5th January 2008, 19:52
If all you need is an ability to show a single, scaled image, then QLabel will be enough.Hm, one after another, so yes, single file. But for a newbee in Qt it sounds a bit strange to use a Label for that...

All you need is:
QVariant variant = QPixmap( "./image1.jpg" );Oh, thx very much! :)

Yes, but you have to use placeholder and QSqlQuery::bindValue().Yea, thats clear

Yes, but you can have several rcc files. If you store all of the images in the database, you'll get even bigger file.Why that? I have 5 JPGs in my rcc, and several SVG-Graphics. I get an 23MB file storing the content in array-format. So that would mean that a QVariant will store much more information than the actual picture? That would mean that only Qt-based programms would be able to read that pictures

jacek
5th January 2008, 20:29
Why that? I have 5 JPGs in my rcc, and several SVG-Graphics. I get an 23MB file storing the content in array-format.
Are talking here about binary .rcc file or a .cpp file generated by rcc? Anyway, you can ask Qt to compress the resource file --- it should reduce the size of SVG files.


So that would mean that a QVariant will store much more information than the actual picture?
Not QVariant, but SQLite. It supports only text, so Qt will have to encode the data somehow. Try adding the same files to the database and compare the size of .rcc file and the database.


That would mean that only Qt-based programms would be able to read that pictures
Yes, only Qt knows how to read .rcc files. Another solution is to use some 3rd party library for storing those files or you can keep them as regular files.

C167
5th January 2008, 21:14
Are talking here about binary .rcc file or a .cpp file generated by rcc? Anyway, you can ask Qt to compress the resource file --- it should reduce the size of SVG files.hm... i looked at the cpp, sry, the binary that comes out is much smaller.

Not QVariant, but SQLite. It supports only text, so Qt will have to encode the data somehow. Try adding the same files to the database and compare the size of .rcc file and the database.So, is there a documentation about that? AFAIR, base64 would make the files 1.33 times larger

Yes, only Qt knows how to read .rcc files. Another solution is to use some 3rd party library for storing those files or you can keep them as regular files.no, i mean the data in the database... but that would be no big deal to write a simple program that reads one file and outputs the original jpg.

jacek
5th January 2008, 21:59
So, is there a documentation about that?
I don't think so. I've just made a simple test program and it seems that Qt cheats when it comes to QPixmaps stored as QVariants. You will have to convert images to strings yourself.

Thomas
5th January 2008, 22:17
Perhaps I am missing something here, but why shall the application contain the images but not load them dynamically?

At program start up I would rather browse through the image directory/directories, load them and store them into SQLite as BLOBs. BLOBs will be stored "as is" so neither a conversion is necessary nor will this result in an inflated data size.

Pros:
- All images will be automatically be stored in the DB after start up.
- If the CD image changes with respect to new images, no recompilation is necessary.
- A default DB could be created and put on the CD, containing already stored images which are common to all future versions.

Cons:
- Depending on the amount of images to be stored on start up, the time until the application is "ready" could increase significantly.

C167
6th January 2008, 17:22
Perhaps I am missing something here, but why shall the application contain the images but not load them dynamically?[QUOTE]Oh, maybe i was a bit unclear: the program+database gets copied to the cd, and the program should show the images, either from db directly or with the help of the db, from files. the discussion about containing them was about rcc's, which i use to store the button icons etc.
[QUOTE=Thomas;59052]At program start up I would rather browse through the image directory/directories, load them and store them into SQLite as BLOBs. BLOBs will be stored "as is" so neither a conversion is necessary nor will this result in an inflated data size.
Pros:
- All images will be automatically be stored in the DB after start up.
- If the CD image changes with respect to new images, no recompilation is necessary.
- A default DB could be created and put on the CD, containing already stored images which are common to all future versions.

Cons:
- Depending on the amount of images to be stored on start up, the time until the application is "ready" could increase significantly.
yea, I was unclear :)
we create a CD, that contains:
the cdlauncher
a pictureDB
some programms
pictures, that should be displayed
so, thats similar to digikam: we store information about the pics in the db right now.
ATM, the DB contains some tables containing author-, album- and picture-information. The application loads the db and if you select an image, it gets pulled from the contruct pics/{albumname}/{filename}
Scanning through the images at startup is problematically, because they are on the cd, which is quite slow. it would mean that we would have to browse through nearly 500MBs of images, so the program would need up to several minutes to start. impossible!
But writing a simple two-liner, that uses the db (which already stores everything neccessary, except the pic) to collect every image and writes it into the db, that would be a good method, as we have to run it once, put everything together in an iso and mount it in the windows-vm.
Thanks so far, i'll write a little test-prg to test how we have to deal with images in DBs :)
C167

C167
7th January 2008, 19:58
okay, i wrote a little testapp that stores an image (or every file you give it) into a BLOB-field. the db-file grows to the size of the given image, so it should be in it, although the chars i get if i do a select to qDebug() are only 8, all unprintable. So, here's my app:
int main( int argc, char *argv[] )
{
QCoreApplication app( argc, argv );
QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
db.setDatabaseName( "/home/stefan/source/qt4/cdlauncher/pictures.db" );
if ( !db.open() )
{
qDebug() << "Opening failed";
return 1;
}
qDebug() << "Opening successfull, using database " << db.databaseName();
qDebug() << "filling an image into the DB...";
QFile file( "/home/stefan/pic/space/191853main_image_feature_929_full.jpg" );
QByteArray fileData;
if ( file.exists() )
{
if ( file.open( QIODevice::ReadOnly ) )
{
fileData = file.readAll();
file.close();
}
}
else
{
qDebug() << "File " << file.fileName() << " could not be located";
}
QSqlQuery query("UPDATE pictures SET data=? WHERE rowid=1;");
query.addBindValue(fileData);
query.exec();
qDebug() << query.lastError();
return 0;
}that works :) everything is hardcoded, i know, but its only a test to see how it works.
So, now i want to retrieve the data. the normal way to display an image is
imgLabel->setPixmap(QPixmap::fromImage(QImage("filename")));After some testing, reading and coffee-ing, i found the following way:
int main( int argc, char *argv[] )
{
Q_INIT_RESOURCE( application );
QApplication app( argc, argv );
QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
db.setDatabaseName( "/home/stefan/source/qt4/cdlauncher/pictures.db" );
if ( !db.open() )
{
qDebug() << "Opening failed";
return 1;
}
QSqlQuery query( "SELECT data FROM pictures WHERE rowid=1;" );
QSqlRecord record = query.record();
query.next();
qDebug() << query.lastError();
QByteArray ba = query.value(0).toByteArray();
QWidget *wid = new QWidget();
QLabel *imgLabel = new QLabel( wid );
QPixmap *pic = new QPixmap();
pic->loadFromData( query.value( record.indexOf( "data" ) ).toByteArray() );
imgLabel->setPixmap( *pic );
wid->show();
return app.exec();
}it successfully reads out the image and displays it...
a SELECT-query seems not to like the QSqlQuery::exec () method. So i used a single next() for that...
So far, everything is fantastic, thank you very much Thomas and jacek :)

Thomas
7th January 2008, 20:22
One last issue. :p

Make sure you delete stuff which you created with new. :D

jacek
7th January 2008, 21:16
a SELECT-query seems not to like the QSqlQuery::exec () method.
If you pass a string to QSqlQuery constructor, it will execute it immediately. It should be:

QSqlQuery query;
query.prepare("UPDATE pictures SET data=? WHERE rowid=1;");
query.addBindValue(fileData);
query.exec();

And the select should be:
QSqlQuery query( "SELECT data FROM pictures WHERE rowid=1;" );
query.next(); // <- positions the query on the first row
QSqlRecord record = query.record();

C167
8th January 2008, 22:38
If you pass a string to QSqlQuery constructor, it will execute it immediately. It should be:

QSqlQuery query;
query.prepare("UPDATE pictures SET data=? WHERE rowid=1;");
query.addBindValue(fileData);
query.exec();

And the select should be:
QSqlQuery query( "SELECT data FROM pictures WHERE rowid=1;" );
query.next(); // <- positions the query on the first row
QSqlRecord record = query.record();
Okay, thank you :)

One last issue. :p
Make sure you delete stuff which you created with new. :DI thought Qt is handling such things for all the classes that inherit QObject, at least their own stuff? Okay, thx :) I'll add everything to my destructors

jacek
8th January 2008, 22:46
I thought Qt is handling such things for all the classes that inherit QObject, at least their own stuff?
Yes, it does, but only for objects that have a parent.

C167
22nd January 2008, 15:43
okay, thx ;)