I am trying to extract the pixel data from every frame, but when I try to get the pixmap it returns null. I thought that the pixmap would return the actual pixel data of what was on the screen, similar to glReadPixels but I think I am mistaken. I think it's meant to access the pixel map of the result of setPixmap.
Is there a way to access the raw pixels rendered on the screen? With the below example, "Hello World" is rendered on the screen and I want the actual pixel data of that label.
QWidget window;
window.resize(1280, 720);
window.show();
window.setWindowTitle(QApplication::translate("toplevel", "Top-Level Widget"));
QLabel *label = new QLabel(QApplication::translate("label", "Hello World"), &window);
label->move(500, 500);
label->raise();
label->show();
QPixmap pixmapVal = label->pixmap(Qt::ReturnByValue);
Cause
QPixmap:
The QPixmap class is an off-screen image representation that can be used as a paint device
In other words, it is a drawing canvas and, as any other canvas, if you have not drawn on it, it would be empty.
On the other hand QLabel serves as a view for the pixmap, not as its content, and when you try to access the pixmap of the label without having set one, it returns null.
Solution
There is of course a way to make a widget, the label in your case, content of the pixmap and access the pixel data. My approach to the this problem would be like this:
Create an empty pixmap with the size of the widget whos pixel content you want to access, e.g.:
QPixmap pixmap(widget->size());
pixmap.fill(Qt::transparent);
Use QWidget::render to render the content of the widget onto the pixmap:
widget->render(&pixmap);
Convert the pixmap to QImage and use QImage::pixel or QImage::pixelColor to access the rgb data of the pixel at (pixelX, pixelY) like this:
pixmap.toImage().pixelColor(pixelX, pixelY);
Example
Here is an example I have prepared for you to demonstrate how the proposed solution could be implemented:
#include "MainWindow.h"
#include <QApplication>
#include <QLabel>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
auto *label = new QLabel(QObject::tr("Hello World"), &w);
label->move(500, 500);
label->raise();
w.setWindowTitle(QObject::tr("Top-Level Widget"));
w.resize(1280, 720);
w.show();
QPixmap pixmap(label->size());
pixmap.fill(Qt::transparent);
label->render(&pixmap);
int pixelX = 10;
int pixelY = 5;
// Access image pixels
qDebug() << pixmap.toImage().pixelColor(pixelX, pixelY);
return a.exec();
}
Result
For the pixel at (10, 5) the example produces the following result:
QColor(ARGB 1, 0, 0, 0.156863)
Related
How could I set the fill color (not the stroke color) for the QPainter in QT?
For example, I have a code which is responsible for filling the rectangle. It looks like:
painter.fillRect(fillRect, Qt::SolidPattern);
Where the type of painter is QPainter. Of course, I know that it is possible to specify the color in the case as a second parameter, but I have such a design in my program that it would be a lot better if I could set the painter fill color beforehand (by default the color is black).
I tried to use painter.setBackground(Qt::yellow);, but it did not help.
Hm. According to this we have:
Sets the painter's brush to the given brush.
The painter's brush defines how shapes are filled.
So, I would expect something like
QRect fillRect;
painter.setBrush(QBrush(Qt::yellow));
painter.fillRect(fillRect, Qt::SolidPattern);
to work. But it does not. What am I doing wrong?
After debugging it turns out that the setBrush method does not update the brush color at all:
The color rgb stays the same: (0, 0, 0).
fillRect() accepts a QBrush as a second parameter, so I could use it:
painter.fillRect(r, QBrush(Qt::yellow, Qt::SolidPattern));
Update:
#include <QApplication>
#include <QLabel>
#include <QPainter>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPixmap pixmap(128, 128);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
QRect r= pixmap.rect();
painter.setBrush(QBrush(Qt::yellow));
painter.fillRect(r, painter.brush());
painter.end();
QLabel w;
w.setPixmap(pixmap);
w.show();
return a.exec();
}
I have this setup:
// ...
// variable document is a QTextDocument* which has some 'RichText' + 'Images'
QTextEdit textEdit;
textEdit.setDocument(document);
textEdit.setLineWrapMode(QTextEdit::LineWrapMode::NoWrap);
auto image = QImage(document->size().width(), document->size().height(),
QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter painter(&image);
document->drawContents(&painter);
// ...
I'm doing this to have my text rendered in a long horizontal QImage (hence the "NoWrap" LineWrapMode), so I can select a small part of it at a time with QImage::copy(QRect) and create a scrolling text effect.
The reason I'm doing it this way is that I need to have a QImage at the end which then I would feed its buffer (QImage::bits()) to the hardware that I'm using as my final output.
So it works great, it displays formatted text with fonts and colors and everything except for the images, it seems to skip them, notice the file icon in "result of text with image" picture.
This is text only in editor
This is result of text only
This is text with image in editor
This is result of text with image
This is how I'm inserting images to my QTextDocument:
QImage image(url.toLocalFile());
if (image.isNull())
return;
image = image.scaledToHeight(getDocumentHeight(), Qt::SmoothTransformation);
auto filename = QUrl(url.fileName());
textEdit->document()->addResource(QTextDocument::ImageResource, filename, image);
textEdit->textCursor().insertImage(filename);
So I don't think it's because "DrawContents" fails to find the image resource file or something like this.
What should I do? Is there something that I'm missing? Any kind of help in the matter is highly appreciated! ;)
In the following code I show how an image should be loaded, then save it to a file, probably the error is that you have not finished painting, for this you must call painter.end() or delete painter from memory.
main.cpp
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget widget;
QVBoxLayout vlayout(&widget);
QTextEdit textEdit;
QPushButton button("save image");
QPushButton loadButton("Load and Insert");
vlayout.addWidget(&loadButton);
vlayout.addWidget(&textEdit);
vlayout.addWidget(&button);
widget.show();
textEdit.append("some text");
QObject::connect(&loadButton, &QPushButton::clicked,[&textEdit](){
QString filename = QFileDialog::getOpenFileName(&textEdit, "Select", "", "*.png");
if(!filename.isEmpty()){
QImage image(filename);
QUrl url = QUrl::fromLocalFile(filename);
image = image.scaledToHeight(100, Qt::SmoothTransformation);
textEdit.document()->addResource(QTextDocument::ImageResource, url, image);
textEdit.textCursor().insertImage(image);
}
});
QObject::connect(&button, &QPushButton::clicked, [&textEdit](){
QImage image(textEdit.document()->size().toSize() , QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::transparent);
QPainter painter(&image);
textEdit.document()->drawContents(&painter);
painter.end();
image.save("image.png");
});
return a.exec();
}
I am currently writing a real-time visualization tool for processing simulation data. The data are two-dimensional data like a pressure/temperature field. Currently, I am using QImage to manipulate the data and QPixmap to display those data but are there any better/faster way? Does QPixmap::fromImage() copy the data from the given image and how costly is that? The source code from my approach looks like this:
int main(int argc, char **argv) {
QApplication app(argc, argv);
QMainWindow* mainWindow = new QMainWindow(0, 0);
mainWindow->setMinimumSize(1024, 768);
mainWindow->show();
QGraphicsScene* scene = new QGraphicsScene();
QGraphicsView* view = new QGraphicsView(scene);
mainWindow->setCentralWidget(view);
QImage* image = new QImage(640, 480, QImage::Format_RGB32);
image->fill(0);
QGraphicsPixmapItem* item = scene->addPixmap(QPixmap::fromImage(*image));
item->setPos(0, 0);
// DO SOME CALCULATION AND SET PIXEL COLOR ON image
item->setPixmap(QPixmap::fromImage(*image));
return app.exec();
I'm trying to generate pixmaps with the following code
QList<QPixmap> pixmapList;
for (int i=0;i<50;++i){
QPixmap pixmap = QPixmap(10050,10050);
pixmap.fill(Qt::transparent);
pixmapList<<pixmap;
}
The above part works find. And I would like to paint on those pixmaps later, e.g.
QPixmap pixmap = pixmapList[10];
QPainter painter(&pixmap);
painter.drawPixmap(....); // this pixmap is 10*10
pixmapList[10]=pixmap;
or
QPainter painter(&pixmapList[10]);
painter.drawPixmap(....); // this pixmap is 10*10
but they both gave me "QPainter::begin: Paint device returned engine == 0, type: 2". May I ask the right way to paint on pixmaps in the pixmapList? Thanks very much!
Your code is OK, except that the pixmaps are too big (they occupy ~400MBytes each).
After making the pixmaps smaller, it works fine (shown for Qt 5):
#include <QGuiApplication>
#include <QPixmap>
#include <QPainter>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QList<QPixmap> pixmapList;
for (int i=0;i<50;++i){
QPixmap pixmap = QPixmap(1000,1000);
pixmap.fill(Qt::transparent);
pixmapList<<pixmap;
}
QPainter painter(&pixmapList[10]);
painter.drawLine(0, 0, 100, 100);
return 0;
}
I'm writing interface with C++/Qt in QtCreator's designer. What element to chose to make as a rect with some background image?
And the second question: how to draw tiled image? I have and image with size (1×50) and I want to render it for the parent width. Any ideas?
mTopMenuBg = QPixmap("images/top_menu_bg.png");
mTopMenuBrush = QBrush(mTopMenuBg);
mTopMenuBrush.setStyle(Qt::TexturePattern);
mTopMenuBrush.setTexture(mTopMenuBg);
ui->graphicsView->setBackgroundBrush(mTopMenuBrush);
QBrush: Incorrect use of
TexturePattern
If you just want to show an image you can use QImage. To make a background with the image tiled construct a QBrush with the QImage. Then, if you were using QGraphicsScene for example, you could set the bursh as the background brush.
Here is an example which fills the entire main window with the tiled image "document.png":
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
QGraphicsScene *scene = new QGraphicsScene(100, 100, 100, 100);
QGraphicsView *view = new QGraphicsView(scene);
mainWindow->setCentralWidget(view);
QImage *image = new QImage("document.png");
if(image->isNull()) {
std::cout << "Failed to load the image." <<std::endl;
} else {
QBrush *brush = new QBrush(*image);
view->setBackgroundBrush(*brush);
}
mainWindow->show();
return app.exec();
}
The resulting app:
Alternatively, it seems that you could use style sheets with any widget and change the background-image property on the widget. This has more integration with QtDesigner as you can set the style sheet and image in QtDesigner.