QPixmap memory size depending on fle size - qt

I am creating QGraphicsPixmapItems by loading images from files.
bool PixMapItem::loadItemFromFile(const QString &filename)
{
QPixmap p;
if(!p.load(filename))
return false;
setPixmap(p);
#ifdef NOT_QT_4
m_itemSize = p.size()/p.devicePixelRatio();
#else
m_itemSize = p.size();
#endif
return true;
}
caller:
item->loadItemFromFile(filename);
item->adjustForMaxSize(maxSize);
I would like to know how the memory used by the item depends on the image file size.
1) Type of image - will the encoding of the Pixmap stored in the item be minimal, or always 32 bit, or is there any way to set it ?
2) Assuming the item is resized immediately after load to match a specific size (see above), would the actual image size affect the item memory size ? Would memory size be better if I scale the pixmap instead of the item itself ?

Let me try to answer it, maybe it help you :
I have try long time ago and yes it will always 32 bit, it will be RGB or RGBA (if there is alpha on image, it can be check by hasAlpha). The way you can check is check the depth of the QPixmap which always return 32. Nothing we can do with the pixmap data because it handle internally, which stated on their QPixmap documentation :
Note that the pixel data in a pixmap is internal and is managed by the
underlying window system.
Smaller image will be smaller memory consumed. And you need to free your original pixmap after scale it.
QPixmap is design for painting performance on screen, if you want better handle IO (formating image, decrease the color, etc) use QImage. You also able to render QImage to screen using the painter but it will be slower compare to QPixmap.

Related

OpenGL / QT : Need help in Converting from QImage to Opengl format and render the pixels

We are migrating from Old OpenGl to Modern OpenGL. I am trying to port two functions which uses QT/OpenGL and want to convert to Modern OpenGL. QImage content should be converted to OpenGL Format. Then I want to read the pixels of QImage and render in OpenGL. How to do this in Modern OpenGL. I know glcopypixels() / glDrawPixels() is deprecated. Any pointers? I have the following code but it is in old OpenGL. Basically the whole idea is writing to back buffer and restoring the back buffer and render pixels to avoid redraw. I am using QOpenglWidget Class given by QT Framework (QT 5.1). I have tried many things converting to OpenGL format from QImage. But it did not work. Need your help. Thanks in Advance.
QImage _savedBackBuffer;
void SaveBackBuffer()
{
glReadBuffer(GL_BACK);
QImage buf = this->grabFramebuffer();
_savedBackBuffer = convertToGLFormat(buf); // convertToGLFormat is not available in
QOpenGLWidget class
}
void restoreBackBuffer()
{
glDrawBuffer(GL_BACK);
**glDrawPixels**( _savedBackBuffer.width(), _savedBackBuffer.height(),
GL_RGBA, GL_UNSIGNED_BYTE, _savedBackBuffer.bits() ); ---> glDrawPixels is Deprecated. How to handle this call.
}
flush () {
glReadBuffer (GL_BACK);
glDrawBuffer(GL_FRONT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
**glCopyPixels**(0, 0, _scrWidth, _scrHeight, GL_COLOR); // glCopyPixels Deprecated
...
glflush();
}
I have added below code to grab the Framebuffer. But still I am getting an Empty QImage. Anything wrong with my code.
saveBackBuffer()
{
_bSavingBackBuffer = true;
QString fileName("C:\\Users\\ey617e\\Desktop\\yourFile.png");
QFile file(fileName);
file.open(QIODevice::WriteOnly);
glReadBuffer(GL_BACK);
makeCurrent();
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject * fbo = new
QOpenGLFramebufferObject(_scrWidth, _scrHeight, format);
fbo->bind();
paintGL();
_savedBackBuffer = fbo->toImage();
_savedBackBuffer.save(file.fileName(), "PNG");
fbo->release();
}
paintGL()
{
QOpenGLPaintDevice fboPaintDev(_scrWidth, _scrHeight);
QPainter painter(&fboPaintDev);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.beginNativePainting();
drawDisplayLists(_underIllusDisplayLists);
drawDisplayLists(_illusDisplayLists);
painter.endNativePainting();
painter.drawText(20, 40, "Foo");
painter.end();
}
You can create a QOpenGLTexture object directly from a QImage: https://doc.qt.io/qt-5/qopengltexture.html#QOpenGLTexture-1
You can then use that texture directly for any image related OpenGL operations.
Basically the whole idea is writing to back buffer and restoring the back buffer and render pixels to avoid redraw.
Don't do that! It will actually impair performance, since drawing on top of previously rendered content introduces implicit synchronization points, thereby eliminating options to render new contents in parallel to advancing the presentation swap chain.
As "counterintuitive" as it may sound, just redraw the whole thing, each and every frame. If your codebase is that old, then the complexity of what you're drawing very likely is going to be so low, that you could easily render thousands of frames per second.
On the other hand retaining the contents of the backbuffer constitutes a cache and thus introduces the complexity of deciding upon cache invalidation.
I bet, that just redrawing using modern methods (geometry in buffer objects, index buffers, untangling of sync points) and simplifying the rendering code path by mere elimination the code that's responsible for determining when to actually redraw portions of the picture will actually vastly outperform anything what you had before.

Display image using QImage without using pixmap in Qt?

I have a requirement to read pixel values from the picture displayed on the GraphicScene layout. How can I display image using QImage without using pixmap in Qt so that I am able to read the pixel values?
On most platforms, a QPixmap is a thin wrapper around a QImage. The conversions between the two are cheap - especially the pixmap-to-image conversion. Thus, you can use the QGraphicsPixmapItem and use item->pixmap().toImage() without much worry. To confirm that QPixmap is indeed a wrapper, the following check will do:
bool isPixmapThin(const QPixmap &pix) {
auto const a = pix.toImage();
auto const b = pix.toImage();
return a.bits() == b.bits();
}
In all cases, ensure that the image you take from the pixmap won't detach, i.e. always make it const (as in the code example above).

Qt: How to clean up a QImage from memory

How to clear or clean up a QIMage
Following method of mine get a const reference to a QIMage.
MyMethod(const QImage & img) {
// save it to a file
img.save("/path/to/save/the/qimage");
// now I want to clan up img from memory. How should I do it?
}
Question:
How should I clean up the QImage object from memory after use?
Note:
Note that it is a const & QImage. So, answer would involve casting the QImage into non-const?
Also, I am looking at trying to get a QImageData pointer to the data & delete it. Not sure if that is the correct approach here. Do suggest.
You need a non-const reference or a pointer. With a pointer the answer is obvious. With a reference you just assign a default-constructed QImage to it.
MyMethod(QImage & img) {
img.save("/path/to/save/the/qimage");
img = QImage();
}
However, this may still not clean up the memory occupied by the image, if there are additional QImage instances referencing that same image. To overcome this hurdle you need to avoid multiple QImage instances referencing the same image. A Qimage instance is like a shared pointer in this regard.
A const-cast would be considered to reveal a design flaw in your case. I'd recommend against it.

How can I mirror a movie and play it in reverse?

I have been playing with QMovie a bit trying to mirror a movie as well as play it in reverse.
For the mirroring bit I tried assigning a negative width to no avail. Since QImage does offer facilities for this I had hoped QMovie would do the same.
There don't seem to be any facilities in the QMovie object for those things, so I'm wondering if I could manipulate the QIODevice to the QMovie object instead to achieve this, but this is completely new territory for me and I don't see anything obvious in the documentation that would achieve mirroring or playing in reverse.
The code example to start with would be the same as on the PySide page:
label = QLabel()
movie = QMovie("animations/fire.gif")
label.setMovie(movie)
movie.start()
Any ideas would be greatly appreciated.
Thanks,
Frank
QMovie doesn't provide the methods to set the current image, so you have to use directly QImageReader to play it in reverse (using QImageReader::jumpToImage()). This is not very easy bacause the delay between a frame and the next can change, but however you can get it calling QImageReader::nextImageDelay().
To display the movie, you can implement your own widget to draw the movie as you want.
In the paintEvent() you can set a transformation to the painter to get the mirror effect and than draw the current image of the movie.
Example:
void MyWidget::paintEvent(QPaintEvent * event)
{
QPainter painter(this);
painter.scale(-1, 1); // x-axis mirror
//here maybe you must adjust the transformation to center and scale the movie.
painter.drawImage(0, 0, currentImage);
}
To play the movie you have to set a timer that change the current image.
Example:
//you must create a timer in the constructor and connect it to this slot
void MyWidget::timeoutSlot()
{
int currentImageIndex;
//here you have to compute the image index
imageReader.jumpToImage(currentImageIndex);
currentImage = imageReader.read(); //maybe you want to read it only if the index is changed
update();
}
Here you can find an example of widget subclass, with timer and painter transformation
See also QImageReader, QTimer, QWidget::paintEvent

drawText() on a QImage crashes program

I have an image in uint8_t buffer and I am trying to use QImage as a wrapper to write text on the image. I have used drawLine() with no issues, but drawText() crashes the program. The below code is part of a boost thread in which I want to write text unto each image as it iterates through the function. Are there any bugs in Qt I am unaware of?
uint8_t *frameBuffer; // this contains image pixels
QImage img(frameBuffer, sizeX, m_sizeY, QImage::Format_RGB888);
QPainter p(&img);
p.setPen(QPen(Qt::green));
p.setFont(QFont("Times", 10, QFont::Bold));
p.drawLine(img.rect().bottomLeft().x(), img.rect().bottomLeft().y()-10,
img.rect().bottomRight().x(), img.rect().bottomRight().y()-10); //works!
p.drawText(img.rect(), Qt::AlignCenter, "Help"); //crashes program
My project was set to a QCoreApplication (I had no GUI). Changing it to QApplication did the trick!
Just a guess... (I've never seen this error before, but have had other font issues on threads.)
Font rendering on background threads can be a little flaky in Qt, depending on how it was compiled. Check the value of QFontDatabase::supportsThreadedFontRendering on your system.
Note the documentation:
Returns true if font rendering is supported outside the GUI thread,
false otherwise. In other words, a return value of false means that
all QPainter::drawText() calls outside the GUI thread will not produce
readable output.

Resources