2

I'm trying to get the colour of a pixel on the screen, but I can't find a method that has a sustainable tick rate.

So the first option I tried is the Robot class in Java - it's simple to use, but it just simply isn't fast enough.

I then found a way of capturing screen shots using JNA from this post. After testing and playing around with the code a bit, I found that I'm able to almost get what I wanted, mostly by modifying this line:

GDI32Extra.INSTANCE.BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, WinGDIExtra.SRCCOPY);

The only issue is that it still captures the whole window before picking out the single pixel that you want and it just doesn't seem right. This slows down the tick rate by quite a bit.

Is there any way I can capture just a single pixel, or am I forced to always capture an entire window first?

I'm pretty inexperienced with JNA's libraries so maybe I'm just missing something simple. If anyone could point me in the right direction, it would be much appreciated.

Thanks.

Jordan
  • 323
  • 1
  • 14
  • 1
    Looks like [GetPixel](https://learn.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-getpixel) will work for you. You can create an interface extending the existing GDI32 one to add this function. See [this post](https://stackoverflow.com/questions/30513928/adding-another-method-to-jna-class-java-kernel32) for an example on adding a function. No guarantees that it'll be fast, but it does answer your question.... – Daniel Widdis Mar 22 '19 at 18:46
  • Also which part of the `Robot` class did you use? Did you use [createScreenCapture()](https://docs.oracle.com/javase/7/docs/api/java/awt/Robot.html#createScreenCapture%28java.awt.Rectangle%29) (possibly slow) and then [grab an array of pixels to process](https://stackoverflow.com/questions/6524196/java-get-pixel-array-from-image) (fast)? – Daniel Widdis Mar 22 '19 at 18:52
  • I have tested, and yes, `createScreenCapture()` is very slow. Even when just getting a 1x1 Rectangle (single pixel) so it would definitely not be suitable for rapidly repeating pixel sampling from the live screen. – xtratic Mar 22 '19 at 19:29
  • Even `Robot.getPixel(x,y)` is slow for repeated sampling.. ~7 seconds to scan 400 pixels individually.. – xtratic Mar 22 '19 at 19:43

1 Answers1

2

Try adding the GetPixel function to your own JNA class.

public interface MyGDI32 extends com.sun.jna.platform.win32.GDI32 {
    MyGDI32 INSTANCE = Native.load("gdi32", MyGDI32.class, W32APIOptions.DEFAULT_OPTIONS);

    int GetPixel(HDC hdc, int x, int y);
}

Then call it with MyGDI32.INSTANCE.GetPixel().

I can't guarantee it'll be any faster than the Robot class, but it does answer your question how to "Get the colour of a single pixel using JNA."

You'll have to parse the DWORD (32 bit int) return value which is in COLORREF format: 0x00bbggrr.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
  • This is exactly what I've been looking for, although after testing, I've come across something strange. So the way I'm creating a loop is just with `while (x)...` and then using `sleep(1000/TPS);` (let me know there's anything wrong with this). The strange thing is when the target is 60tp/s, the result is only about 30tp/s. However, when I up the target to 70, suddenly it's able to sustain around 50-60tp/s. Do you know why this could be? – Jordan Mar 22 '19 at 23:19
  • I made a very rough example of how I'm using the code here: https://hastebin.com/yuqerubeku.java – Jordan Mar 22 '19 at 23:46
  • 1000/60 corresponds to a 60 Hz refresh rate, the Windows default. It's also the default system clock tick rate. If you're sleeping for 1000/60 (16) ms, you may be missing this tick/refresh and having to wait for the next one at the 33 ms point. The 1000/70 tp/s setting only sleeps for 14 ms so if the `GetPixel` call takes less than 2ms, you're probably catching the update. Not sure whether it's display refresh or system clock (or both?) causing this, but I suspect a "sleep 0" would still give you the same 50-60 tp/s rate. – Daniel Widdis Mar 23 '19 at 05:20