5

In my Java program I need to analyze a color of a pixel in given coordinates. Because of the fact that I need to do it often, first I capture a part of the screen, and then get a pixel color. I am doing this with:

BufferedImage bi = robot.createScreenCapture(new Rectangle(0,0,100,100));
...
pxcolor = GetPixelColor(bi,x,y);
...
ImageIO.write(bi, "bmp", new File("myScreenShot.bmp"));

The GetPixelColor function is quite obvious:

public Color GetPixelColor(BufferedImage b, int x, int y)
{
    int pc = b.getRGB(x, y);
    Color ccc = new Color(pc,true);
    int  red = (pc & 0x00ff0000) >> 16;   // for testing
    int  green = (pc & 0x0000ff00) >> 8;  // for testing
    int  blue = pc & 0x000000ff;          // for testing
    return ccc;     
}

For testing purposes I have created a pure pink picture (RGB(255,0,255)). The problem is that even if the pixel is pure pink, the function returns something like RGB(250,61,223) as well as testing variables red, green and blue there. Also, the saved file (the myScreenShot.bmp) looks quite different.

What am I doing wrong. Could it be somehow ColorModel related?

UPD: getting the DataBuffer from bi doesn't seems to produce right results - the first element of produced DataBuffer is equal to "-2105371". I don't know from where came minus sign, but if I transform it to HEX I will get something like "FFFFFFFFFFDFDFE5". The real pixel RGB is (E5,E5,EB), and the buffer is already corrupted, having instead RGB(DF,DF,E5). This drives me nuts already.

kaytrance
  • 2,657
  • 4
  • 30
  • 49
Quest
  • 51
  • 2
  • @Quest: *getRGB* is not only amazingly ssllooww (up to 3 orders, yup... Up to 1 000 times slower!!!, measured repeatedly on a MacMini with OS X 10.5) but it's also "wrong" in that it tries to be "smart" with the color models. I really advice you to work with BufferedImage backed by an *int[]* and manipulate pixels directly from the *int[]* instead of using *getRGB / setRGB*. Then you'll read the exact pixels you captured with Robot's *createScreenCapture* and you'll read them *fastly*. Been there, done that. – SyntaxT3rr0r Jun 29 '11 at 11:40
  • @Quest: in addition to that, if you intend to parse a lot of the pixels you captured (as, say, in examining every pixel of a 1920x1200 screen), then you'll have to deal with millions of pixels and you'll see that the entire "Object" concept simply doesn't cut it speedwise. A *Color* is really a very lame object abstraction for something very simple: a fast, lean, elegant primitive *int* (typically representing the ARGB value of your pixel, each on 8 bits). – SyntaxT3rr0r Jun 29 '11 at 11:43
  • @SyntaxT3rr0r. As i wrote in update section the "buffer" seems to have already bad values, so if I take the first byte out of it, it is already incorrect. Ok, not the first byte, because it's alpha, but second. Could you give me some code example, please, because maybe I am extracting the buffer incorrectly. – Quest Jun 29 '11 at 13:07
  • @Quest: if *src* is a BufferedImage **backed by an int[]** (experiment/Google) then *int[] srcbuf = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();* shall give you and *int[]*. Then it's easy: *srcbuf[0] = 0xFFFF00FF* shall put a "pure pink" (as you called it) at pixel (0,0). Then *int p = srcbuf[0]* shall give you back your pure pink pixel. Also, upvote and favorite the following question (it contains the example you're after): http://stackoverflow.com/questions/2825837 – SyntaxT3rr0r Jun 29 '11 at 15:06
  • It appears that it is not backed by int, even if I am not sure what you mean, but int[] srcbuf = ((DataBufferInt) src.getRaster().getDataBuffer()).getData(); produces an error saying that DataBuffer cannot be converted to DataBufferInt. If I debug and stop at the line where createScreenCapture is called, in "variables" window I can see that the buffer already has some bad values. Also, on my windows machine everything is ok, on my mac - wrong colors. – Quest Jun 30 '11 at 10:07
  • @Quest: but you can typically force your BufferedImage to have a *DataBufferInt*. Yup, the Windows "correct color" and Mac "color model wrong colors" is typical: the Java "picture manipulation" have been totally and needlessly overthought (seriously, how many serious image manipulation programs are written in Java?). I feel your pain. I do need to manipulate big pictures in Java and it's a royal PITA. – SyntaxT3rr0r Jun 30 '11 at 13:14

1 Answers1

1

It is most likely due to the color model.

According to this code it uses a DirectColorModel (see below) regardless of your color depth of your screen.

/*
 * Fix for 4285201
 * Create a DirectColorModel equivalent to the default RGB ColorModel,
 * except with no Alpha component.
 */
screenCapCM = new DirectColorModel(24,
                 /* red mask */    0x00FF0000,
                 /* green mask */  0x0000FF00,
                 /* blue mask */   0x000000FF);
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • I just tried changing the color model using reflection and unfortunately it looks like the problem is deeper; `RobotPeer.getRGBPixels` returns the incorrect RGB values. So it seems the issue is unrelated to the `ColorModel` in use. – Roman Nurik Feb 09 '12 at 22:05