how to get a screen pixel's color in x11
Asked Answered
S

2

8

I want to get the RGB value of the top/left pixel (0;0) of the whole x11 display.

what I've got so far:

XColor c;
Display *d = XOpenDisplay((char *) NULL);

XImage *image;
image = XGetImage (d, RootWindow (d, DefaultScreen (d)), x, y, 1, 1, AllPlanes, XYPixmap);
c->pixel = XGetPixel (image, 0, 0);
XFree (image);
XQueryColor (d, DefaultColormap(d, DefaultScreen (d)), c);
cout << c.red << " " << c.green << " " << c.blue << "\n";

but I need those values to be 0..255 or (0.00)..(1.00), while they look like 0..57825, which is no format I recognize.

also, copying the whole screen just to get one pixel is very slow. as this will be used in a speed-critical environment, I'd appreciate if someone knows a more performant way to do this. Maybe using XGetSubImage of a 1x1 size, but I'm very bad at x11 development and don't know how to implement that.

what shall I do?

Sekofski answered 8/7, 2013 at 2:59 Comment(6)
sure, that's what I'm doing right now, but it's giving me creeps, because a) I don't know why it works, b) I don't know how reliable it is and c) It's still slow (time says "cpu 0,054 total" for a single pixel!).Sekofski
Actually, according to this, it should just be uninitialized junk values. Use some basic bit wise operators on the long returned by XGetPixel and you should be set.Innuendo
Screen caps are inherently slow. If there is any other way to get what you want, use that instead of a screen capture.Innuendo
the only other way to get what I want would require getting a randomized runtime memory offset and messing around in foreign processes running through wine. so, basically, I think using that one pixel is still faster. XGetSubImage would be faster (effectively screencapping only the pixel I need), but dunno how.Sekofski
Use a toolkit like Qt or Gtk... It is much simpler....Bedroom
simpler and slower. by the way, the only way to do this in QT is doing exactly what I did above, but using QImage. dunno how it's done in gtk, never wrote anything with gtk, the whole gobject thing is strange ;-)Sekofski
M
13

I took your code and got it to compile. The values printed (scaled to 0-255) give me the same values as I set to the desktop background image.

#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

using namespace std;

int main(int, char**)
{
    XColor c;
    Display *d = XOpenDisplay((char *) NULL);

    int x=0;  // Pixel x 
    int y=0;  // Pixel y

    XImage *image;
    image = XGetImage (d, XRootWindow (d, XDefaultScreen (d)), x, y, 1, 1, AllPlanes, XYPixmap);
    c.pixel = XGetPixel (image, 0, 0);
    XFree (image);
    XQueryColor (d, XDefaultColormap(d, XDefaultScreen (d)), &c);
    cout << c.red/256 << " " << c.green/256 << " " << c.blue/256 << "\n";

    return 0;
}
Morrison answered 8/7, 2013 at 11:32 Comment(1)
Your code doesn't compile for me. I needed to add an X before some functions: XRootWindow, XDefaultScreen and XDefaultColormap.Quechua
C
2

From the XColor(3) man page:

The red, green, and blue values are always in the range 0 to 65535 inclusive, independent of the number of bits actually used in the display hardware. The server scales these values down to the range used by the hardware. Black is represented by (0,0,0), and white is represented by (65535,65535,65535). In some functions, the flags member controls which of the red, green, and blue members is used and can be the inclusive OR of zero or more of DoRed, DoGreen, and DoBlue.

So you must scale these values to whatever range you want.

Coefficient answered 8/7, 2013 at 3:6 Comment(1)
actually I tried that (because it's the nearest value making some sense), but it's more inaccurate compared to 57825 :-(Sekofski

© 2022 - 2024 — McMap. All rights reserved.