Get Pixel-Values on Screen (KDE)
-
@wrosecrans thanks for your answer! This is very helpful. Two issues have come up when I tried adapting the code from the Screenshot-Example:
- The existing code I'm trying to update with the Screenshot-Example was previously using Qt5. I understand that to use the
QScreen::grabWindow()
-function, I have to use Qt6. I did install Qt6 on my machine, however when I try to change theCMakeLists.txt
from
find_package (Qt5 REQUIRED COMPONENTS Core Gui ) # ... target_link_libraries (myprogram PUBLIC Qt5::Core Qt5::Gui
to this:
find_package (Qt6 REQUIRED COMPONENTS Core Gui Widgets ) # ... target_link_libraries (myprogram PUBLIC Qt::Core Qt::Gui Qt::Widgets
I see the following error in CMakes configure-step:
[cmake] -- Configuring done [cmake] CMake Error: The INTERFACE_QT_MAJOR_VERSION property of "Qt6::Widgets" does [cmake] not agree with the value of QT_MAJOR_VERSION already determined [cmake] for "myprogram".
- When trying to incorporate the following:
QScreen *screen = QGuiApplication::primaryScreen(); auto a = screen->grabWindow(0);
I get red highlighting under the arrow-accessor along with the following error:
Member access into incomplete type 'QScreen'
I can imagine that the second error will be fixed if get the first error to go away. Any idea on that? Thanks again for your response.
If you want to take a look at the code, you can find the mentioned snippets here (
CMakeLists.txt
) and here (Decoration.cc
). - The existing code I'm trying to update with the Screenshot-Example was previously using Qt5. I understand that to use the
-
Clean your build directory after switching from Qt5 to Qt6 and use Qt6::Foo instead Qt::Foo to be sure to use the Qt6 libs.
Member access into incomplete type 'QScreen'
As always - when you want to use a class you have to include the header where the class is defined.
-
@Christian-Ehrlicher I might really have included the wrong header! Thanks for pointing that out.
As for the build directory: I see the error even if I delete the build-directory and configure Cmake on a clean slate. Anything else I can check?
-
Since you did not show the whole CMakeLists.txt you did not tell us that you're also trying to link against KDE5 libs - this will not work you can't mix Qt5 and Qt6.
-
@Christian-Ehrlicher does that mean the idea of @wrosecrans won‘t work?
-
@tim-hilt said in Get Pixel-Values on Screen (KDE):
does that mean the idea of @wrosecrans won‘t work?
It does if you use the qt-5 docs instead the qt-6 ones
-
@Christian-Ehrlicher thanks. That did in fact work.
-
@Christian-Ehrlicher @wrosecrans The original question is answered so I marked the thread as solved. However, allow me to ask one more question:
My ultimate goal is to find the most prominent color in the first row of pixels in a window. My current, naive implementation looks like this:
QScreen *screen = QGuiApplication::primaryScreen(); auto window = screen->grabWindow(0).toImage(); // Convert to QImage // I have no way to debug, so I'm logging to journalctl syslog(LOG_NOTICE, "[Window Decoration] Width: %d, Height: %d", window.width(), window.height()); std::unordered_map<QRgb, unsigned int> cols{}; for (int i = 0; i < window.width(); i++) { cols[window.pixel(i, 0)]++; // Count color-occurences }
However the above code always logs, that the window is 0x0 pixels, so no pixel-value can actually be observed. Should I open another thread for this issue? Any idea what could have gone wrong? I added a 500ms delay before calling the above code, but that didn't change the behavior.
-
@tim-hilt
I'm using this kind of code:QScreen* screen=qApp->primaryScreen(); screen=window()->windowHandle()->screen(); if(!screen) return; QPoint pt=window()->geometry().topLeft(); auto pixmap= screen->grabWindow(this->winId(), pt.x(),pt.y(),300,height()); auto color = pixmap.toImage().pixelColor(2,2); qDebug()<<hex<<color<<color.rgb();
-
Hi @mpergand, thanks for the reply. It seems like you have an instance of QGuiApplication that you hold in the variable qApp. I unfortunately don't have any of that. I generally don't really understand your code. Why are you initializing
screen
with one value, if it's directly overwritten in the second line?I logged the screen-name that I get when using
QGuiApplication::primaryScreen()
. It printseDP-1
, which is my laptop-screen. So I correctly get the screen. The issue thus seems to happen when I usegrabWindow
.screen->grabWindow(0)
should grab the pixels of the entire screen, but that doesn't seem to be the case for me.I also tried
screen->grabWindow(QApplication::activeWindow()->winId())
to get the window-id of the currently active window, but that just crashes KDE.I'm unfortunately out of ideas for now. Any idea what else I could try?
-
@tim-hilt said in Get Pixel-Values on Screen (KDE):
Why are you initializing screen with one value, if it's directly overwritten in the second line?
You're right, that's old (test) code that I don't use because grab() doesn't work well:
- the colors of the grabbed image are ligther then the original
- there's a strange redraw bug on the original window after the grab operation (at least on mac)
Try with a portion of the screen:
auto pixmap= screen->grabWindow(winId,100,100,200,200);In my opinion, the grab method is not really reliable.
-
@mpergand the pixmap-size is still 0x0 pixels, even if I call
grabWindow
with coordinates. In my application I call.toImage()
on the returned pixmap. However both the pixmap and the image are both of size 0x0 pixels. So it also doesn't get lost in the conversion-process from pixmap to image. -
Test on KDE 21.04 in virtualbox.
int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget w1; w1.show(); w1.resize(300,200); QTimer::singleShot(500, 0,[&w1]() { QScreen *screen = QGuiApplication::primaryScreen(); auto screen_img = screen->grabWindow(0).toImage(); qDebug()<<screen_img; auto win_img= screen->grabWindow(w1.winId()); qDebug()<<win_img; } ); return app.exec(); }
QImage(QSize(1891, 972),format=QImage::Format_RGB32,depth=32,devicePixelRatio=1,bytesPerLine=7564,sizeInBytes=7352208)
QPixmap(QSize(300, 200),depth=32,devicePixelRatio=1,cacheKey=0x700000001)Work as expected.
-
@mpergand can you provide a CMakeLists.txt or the compile-command you used?
and just to make that clear: I’m using the same code distilled to
QScreen *screen = QGuiApplication::primaryScreen(); auto screen_img = screen->grabWindow(0).toImage();
So no app.exec or something like that. That shouldn’t matter however, since screen->name did resolve to the expected screen name.
If you have the capacity, you could try running my code (linked above). It‘s actually a window-decoration for KDE! The Readme contains installation-instructions and I added logs that you can read through journalctl.
-
Some more news about this:
- I used
qDebug
to log the returned object forQScreen::grabWindow
. It printsQPixmap(null)
! So thegrabWindow
-function doesn't seem to work on my machine. Versions are printed below. - I can observe the same behavior when compiling and running the Screenshot-Example that you guys were referring to earlier. When I execute the compiled binary and try to take a screenshot, this is the output I'm getting:
$ ./screenshot QPixmap::scaled: Pixmap is a null pixmap QPixmap::scaled: Pixmap is a null pixmap QPixmap::scaled: Pixmap is a null pixmap
Versions:
qt5-base: 5.15.7+kde+r177-1 kwin_wayland --version: kwin 5.26.4 plasmashell --version: plasmashell 5.26.4 uname -a: Linux t14s 6.1.1-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 21 Dec 2022 22:27:55 +0000 x86_64 GNU/Linux
@Christian-Ehrlicher can you give me your guess as to where this issue should be further pursued? Is it likely due to Arch Linux, KDE or Qt?
- I used