QTextDocument::addResource question please
-
Hello,
I am using the QTextDocument::addResource() function to add images from a SQLite BLOB, which will be shown using HTML <img> tags (and any other text and HTML tags necessary for formatting). DO i need to release the memory for these image resources somehow? Or do I simply need to jsut delete the QImage pointer?Thank you very much!
-
Hi,
You can find it in QImage documentation:bq. QImage::QImage ( uchar * data, int width, int height, Format format )
Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels, data must be 32-bit aligned, and each scanline of data in the image must also be 32-bit aligned.
The buffer must remain valid throughout the life of the QImage. The image does not delete the buffer at destruction.
If format is an indexed color format, the image color table is initially empty and must be sufficiently expanded with setColorCount() or setColorTable() before the image is usedWhenever QImage is created with external buffer it's Your responsibility to free that buffer.
-
Thank you for your reply przybysh, I appreciate your time and consideration helping me.
I am new to Qt, so I hope you can bear with me. I presume the external buffer would be the QSqlQuery that I used to query the image data?
Below is the general process of what I will be doing (just in case)
@
QTextDocument doc;QSqlQuery query("SELECT imgData FROM table WHERE imgIndex = 100");
query.next();QImage *img = new QImage;
img->loadFromData(query.value(0).toByteArray());doc.addResource(QTextDocument::ImageResource, QUrl("imageName.jpg"), *dbImg);
@
Thank you again!
-
NO, this does not work.
The QVariant of value(0) eventually goes out of scope and is destroyed. The buffer in turn is not valid anymore and QImage will access invalid data, or, worse, memory that has been released already. You must take the bytes and copy them over to something, you have control over (e.g. a permanent QByteArray that you store somewhere).
-
Are you sure, Volker? Note that phantom23 uses the loadFromData method, as opposed to the constructor that takes a raw buffer. The loadFromData method does not specify that the buffer would need to stay valid, and it would be weird if it did. After all, the method does not take a pointer to a QByteArray, but a normal QByteArray. That means it makes a copy, after which QImage could not care less what happens to the original...
-
For sure
bq. bool loadFromData ( const uchar * data, int len, const char * format = 0 )
Requires that data must be valid as long as QImage, later on user is responsible for freeing data.
Probably same applies to
bq. bool loadFromData ( const QByteArray & data, const char * format = 0 )
Documentation is not precise about that.
-
@Andre:
Yes, you're right. I mixed up the QImage constructor taking a char array with the loadFromData() method. While the former relies on the data not going away, the latter does not.@przybysh:
It's stated nowhere that loadFromData() requires the uchar array to be valid dring the life time of the QImage object. The source code doesn't suppose that either. The overload that takes a QByteArray just calls the uchar version, so anything that holds true for the one does so for the other too. -
[quote author="Volker" date="1330691822"]
@przybysh:
It's stated nowhere that loadFromData() requires the uchar array to be valid dring the life time of the QImage object. The source code doesn't suppose that either. The overload that takes a QByteArray just calls the uchar version, so anything that holds true for the one does so for the other too.[/quote]I agree that it's not stated explicitly. Later today I will provide example which proves that loadFromData() requires valid data during life time. For me loadFromData acts just like
bq. QImage ( const uchar * data, int width, int height, Format format )
-
przybysh, Volker and Andre: Thank you for your time and input. I tried the code below, and the image was displayed (I used a QPixmap instead of a QImage, but I presume the behavior would be the same). Since the image displayed properly, I can only assume that a deep copy of the image data was made, as the QSqlQuery would have gone out of scope.
@
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("testDB.db");
db.open();QPixmap px; { QSqlQuery query("SELECT imgData FROM Tbl WHERE imgIndex = 100",db); query.next(); px.loadFromData(query.value(0).toByteArray()); } QLabel lb; lb.setPixmap(px); lb.show();
@
I have two follow-up questions if it is not too much of a hassle:
-
If QImage does indeed create a deep copy of the image data, should I assume that the destructor will release the memory? Or should I create a QByteArray, copy the image data into that and release it myself when the iamge is no longer needed?
-
I also have a question related to QTextDocument::addResource(). When I'm done with the image, should I re-set the resource name using a null QVariant, or is that not necessary?
Thank you again!
-
-
[quote author="przybysh" date="1330692429"][quote author="Volker" date="1330691822"]
@przybysh:
It's stated nowhere that loadFromData() requires the uchar array to be valid dring the life time of the QImage object. The source code doesn't suppose that either. The overload that takes a QByteArray just calls the uchar version, so anything that holds true for the one does so for the other too.[/quote]I agree that it's not stated explicitly. Later today I will provide example which proves that loadFromData() requires valid data during life time. For me loadFromData acts just like
bq. QImage ( const uchar * data, int width, int height, Format format )
[/quote]OK, I took a look at the code, and my conclusions are that loadFromData follows a completely different code path than the constructor version, but that indeed the QByteArray version is the same as the uchar* version (in quite a weird way, actually[1]).
The loadFromData version creates a QBuffer, and then uses the normal image loading code (QImageReader) to create a new image, which is then assigned to this using an explicit operator=() call. My conclusion is that the data does not need to stay valid after that.
[quote author="phantom23" date="1330745543"]I have two follow-up questions if it is not too much of a hassle:
- If QImage does indeed create a deep copy of the image data, should I assume that the destructor will release the memory? Or should I create a QByteArray, copy the image data into that and release it myself when the iamge is no longer needed?
[/quote]
QByteArray will take care of clearing up its own data. There is no need for manual memory management here. QImage using this path indeed will own the data it stores the image in.
[quote] - I also have a question related to QTextDocument::addResource(). When I'm done with the image, should I re-set the resource name using a null QVariant, or is that not necessary?[/quote]
I'm not sure what you mean by this exactly.
[1] The QByteArray version calls the uchar* version, which in turn creates a QByteArray from the raw data. Doing it the other way around would have been more logical, IMHO.
- If QImage does indeed create a deep copy of the image data, should I assume that the destructor will release the memory? Or should I create a QByteArray, copy the image data into that and release it myself when the iamge is no longer needed?