Using setRGB to set 0-255 values instead of hex code values - java

I am currently using the .setRGB() method. It appears that the input for the int[] rgbArray is a hex-code value, which are very large integer values. I currently have a set of integers that range from 0 - 255, so whenever I input them using .setRGB, the image is just pure black, which makes sense given the range of hex values versus RGB values.
I was wondering is there a way for me to use non-hex values?

It's not Hex; it's bit-fiddled RGB. I would use java.awt.Color and then call getRGB(). So,
int rgb = new Color(red, green, blue).getRGB();

As mentioned in the other answer, the "large values" that you are talking about are the combined R,G,B components of the color, and possibly an "Alpha" component.
Setting a value of 255 with the setRGB method should thus cause the pixel to become perfeclty blue - unless it is an image that has an alpha channel. In this case it would become a perfectly transparent blue (aka "black").
However, when you have a value between 0 and 255, you can convert it into an RGB value (with 0=black and 255=white) as follows:
int value = ...
int rgb = (255 << 24) | (value << 16) | (value << 8) | value;
(The alpha component here is set to 255. For images without alpha channel, this will not change anything. But for images that have an alpha channel, this is crucial to make sure that the color is actually visible)

Related

How to check if a pixel is black using image.getRGB(x, y)

Should I expect the color of the pixel to be black if
image.getRGB(x, y) returns 0?
My assumption: I would expect 0 because the bit values of each of the values (Red, Green, Blue) would be zero. Am I correct in thinking this?
No, BufferedImage#getRGB() returns hex number. See this unit test:
public class TestRgb {
#Test
public void testBlack(){
BufferedImage bufferedImage = new BufferedImage(1,1, TYPE_BYTE_BINARY);
Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setPaint(new Color(0,0,0)); //black
graphics2D.fillRect(0,0,1,1);
// pass - alpha channel set by default, even on all black pixels
TestCase.assertTrue(bufferedImage.getRGB(0,0)==0xFF000000);
// pass - when looking at just the color values (last 24 bits) the value is 0
TestCase.assertTrue((bufferedImage.getRGB(0,0) & 0x00FFFFFF)==0);
// fail - see above
TestCase.assertTrue(bufferedImage.getRGB(0,0)==0);
}
}
"Returns the RGB value representing the color in the default sRGB ColorModel. (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are =blue)."
That is, the packing (in hex locations) is as follows, where each component can have a value of 0 (0x00) .. 255 (0xFF).
AARRGGBB
Thus, the final value is not only dependent upon RGB, when all color components are zero:
AA000000
In fact, AA will be 0xFF ("100% opaque") by default unless it has explicitly been set to a different value in a buffer / model that supports an alpha channel.

Understanding BufferedImage.getRGB output values

I'm getting an integer value for the pixel in an image using this method:
int colour = img.getRGB(x, y);
Then I'm printing out the values and I see that black pixels correspond to a value like "-16777216", a kind of blue to something like "-16755216", etc. Can someone please explain me the logic behind this value?
The RGB int color contains the Red, Green, Blue components of the color in its bits. You have to look at its binary or hexadecimal representation and not look at it as a whole integer number (not look at its decimal representation).
An int has 32 bits, 3x8 = 24 is used to store the RGB components (8 bits for each) in the following format:
2 1 0
bitpos 32109876 54321098 76543210
------ --+--------+--------+--------+
bits ..|RRRRRRRR|GGGGGGGG|BBBBBBBB|
You can extract or set the components using bitmasks:
int color = img.getRGB(x, y);
// Components will be in the range of 0..255:
int blue = color & 0xff;
int green = (color & 0xff00) >> 8;
int red = (color & 0xff0000) >> 16;
If the color also has an alpha component (transparency) ARGB, it gets the last remaining 8 bits.
3 2 1 0
bitpos 10987654 32109876 54321098 76543210
------ +--------+--------+--------+--------+
bits |AAAAAAAA|RRRRRRRR|GGGGGGGG|BBBBBBBB|
And the value:
int alpha = (color & 0xff000000) >>> 24; // Note the >>> shift
// required due to sign bit
An alpha value of 255 means that a color is completely opaque and a value of 0 means that the color is completely transparent.
Your color:
Your color is color = -16755216 which has:
blue : 240 // Strong blue
green: 85 // A little green mixed in
red : 0 // No red component at all
alpha: 255 // Completely opaque
getRGB(int x, int y) return you the value of color pixel at location (x,y).
You are misinterpreting the returned value.
It is in the binary format.
like 11...11010101 and that is given to you as int value.
If you want to get RGB (i.e. Red, Green, Blue) components of that value use Color class. e.g.
Color mycolor = new Color(img.getRGB(x, y));
Then you can get the Red, Green, Blue, or Alpha values by using getRed(), getGreen(), getBlue(), getAlpha().
Then an int value will be returned by these methods in familiar format having value 0 < value < 255
int red = mycolor.getRed();
If you don't want to use Color class then you will need to use bitwise operations to get its value.
See the implementation of ColorModel.getRgb:
589 public int getRGB(int pixel) {
590 return (getAlpha(pixel) << 24)
591 | (getRed(pixel) << 16)
592 | (getGreen(pixel) << 8)
593 | (getBlue(pixel) << 0);
594 }
It's explained in the docs:
Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB) [...]
So you get 8 bits alpha channel, 8 bits red, 8 bits green, 8 bits blue.
A simple (and slow way) to examine the value is to use new java.awt.Color(colour, true); and then call the getters.
Or you can print the value as an unsigned 32bit hex value: Integer.toString(colour, 16). Each two characters of the output will be one part of the ARGB set.
Actually,You can transform the int to binary string by Integer.toBinaryString(-16755216),which is 11111111000000000101010111110000.it made up of 4 bytes: alpha, red, green, blue. The values are unpremultiplied, meaning any transparency is stored solely in the alpha component, and not in the color components. The components are stored as follows (alpha << 24) | (red << 16) | (green << 8) | blue. Each component ranges between 0..255 with 0 meaning no contribution for that component, and 255 meaning 100% contribution. Thus opaque-black would be 0xFF000000 (100% opaque but no contributions from red, green, or blue), and opaque-white would be 0xFFFFFFFF.

Java Color(int rgba) constructor and int overflow

According to the docs, this constructor exists:
public Color(int rgba,
boolean hasalpha)
I'm failing to see how you could use this to create the equivalent of Color(255,255,255,255) (e.g. 0xFFFFFFFF) given that java has no unsigned ints, however.
How do you use this constructor for a "big" color?
EDIT
Evidently the constructor can be used (surprise), but parsing an RGBa color string like this fails:
int x = Integer.parseInt("0xFFFFFFFF", 16); // Number format error
Color c = new Color(x, true);
The solution seems to be to use BigInteger to do the parsing. Sorry for the misdirected question!
Your question is not misdirected, but you seems to have misunderstood Kon's answer:
You are right about Java's Integer being signed all the time, but this doesn't mean that there are less bits of information in that number.
When you create a Color:
new Color(255, 255, 255, 255)
it is the same as using:
new Color(0xFFFFFFFF, true)
or using:
new Color(0b11111111111111111111111111111111, true)
0xFFFFFFFF is in fact -1, but this doesn't mean that any of the bits change; It's only a question of representation. The Color just cuts out the necessary bits for each color component.
So you can, in fact, create your desired color using:
Color c = new Color(-1,true);
System.out.println(c);
System.out.println(c.getAlpha());
which yields:
java.awt.Color[r=255,g=255,b=255]
255
Go binary.
Color c = new Color(0b11111111111111111111111111111111, true);
As per the Java docs, "alpha component is in bits 24-31, the red component is in bits 16-23, the green component is in bits 8-15, and the blue component is in bits 0-7"

What is the meaning of a negative number when using getRGB()?

I am new to color stuff, rendering etc. and watching a couple tutorial videos about rendering etc. My question is, when I call a getRGB method on a pixel, it returns a negative int. what is the meaning of this negative number? For example, when i call getRGB on a color with r: 186, g: 186, b: 186, it returns -4539718. How is this number related to its rgb value? I've made a couple of google search but was not successful.
The getRGB method returns an int whose 4 bytes are the alpha, red, green, and blue components in that order. Assuming that the pixel is not transparent, the alpha is 255 (0xFF). It's the most significant byte in the int, and the first bit is set in that value. Because in Java int values are signed according to Two's Complement, the value is actually negative because that first bit is on.
To get the color of a pixel:
Color c = new Color(image.getRGB(10,10));
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();

Convert integer color value to RGB

I am trying to modify a third party software. I want to use a color which is returned by some methods (which I cant modifiy) as an integer. However, I would like to use RGB format, like #FF00FF. How can I make a conversion?
Here is an HTML example http://www.shodor.org/stella2java/rgbint.html
I would like to archive same thing in Java, on Android.
What I found to be the simplest and best solution for me was to directly use the Color class as follows:
int red = Color.red(intColor);
int green = Color.green(intColor);
int blue = Color.blue(intColor);
int alpha = Color.alpha(intColor);
This way I could already deal with the integer values without having to handle strings. If on the other hand the string representing the rgb color is what you need, Pankaj Kumar's answer is the best. I hope this is useful to someone.
Use this
String hexColor = String.format("#%06X", (0xFFFFFF & intColor));
We know lenght of color value in HEX is 6. So you see 6 here. %06X matches the result coming from (0xFFFFFF & intColor) and if length is less than 6, it makes result with 6 by appending ZERO to left side of result. And you see #, so this # char gets appended to result and finally you get a HEX COLOR value.
Update since API 26
Since API 26, new methods Color.valueOf(....) has been introduced to convert colors for similar reason. you can use it like
// sRGB
Color opaqueRed = Color.valueOf(0xffff0000); // from a color int
Color translucentRed = Color.valueOf(1.0f, 0.0f, 0.0f, 0.5f);
// Wide gamut color
ColorSpace sRgb = ColorSpace.get(ColorSpace.Named.SRGB);
#ColorLong long p3 = Color.pack(1.0f, 1.0f, 0.0f, 1.0f, sRgb);
Color opaqueYellow = Color.valueOf(p3); // from a color long
// CIE L*a*b* color space
ColorSpace lab = ColorSpace.get(Named.CIE_LAB);
Color green = Color.valueOf(100.0f, -128.0f, 128.0f, 1.0f, lab);
mView.setBackgroundColor(opaqueRed.toArgb());
mView2.setBackgroundColor(green.toArgb());
mView3.setBackgroundColor(translucentRed.toArgb());
mView4.setBackgroundColor(opaqueYellow.toArgb());
Since SDK 26 you can just use
Color c = Color.valueOf(colorInt);
apart from that it does not seem to possible to create a Color instance from arbitrary argb. The underlying code uses a private constructor:
/**
* Creates a new <code>Color</code> instance from an ARGB color int.
* The resulting color is in the {#link ColorSpace.Named#SRGB sRGB}
* color space.
*
* #param color The ARGB color int to create a <code>Color</code> from
* #return A non-null instance of {#link Color}
*/
#NonNull
public static Color valueOf(#ColorInt int color) {
float r = ((color >> 16) & 0xff) / 255.0f;
float g = ((color >> 8) & 0xff) / 255.0f;
float b = ((color ) & 0xff) / 255.0f;
float a = ((color >> 24) & 0xff) / 255.0f;
return new Color(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB));
}
RGB uses hexa decimal number format,.
if you have integer value, convert it to hexa,.
It seems the value being quoted and the format desired are mismatched. The value is hexadecimal, while RGB would read 255, 0, 255 and the integer is a composite color representation. Since it is unclear what is being accomplished, here are all three variations:
If you have an integer for the composite color, then most color endpoints will accept it unmodified. This would be something like setBackgroundColor(colorInt)
If you have the hexadecimal value, then Color.parseColor(#colorHex) would convert it to a color object.
Likewise, Color.rgb(redInt, greenInt, blueInt) would convert the red, green, and blue values to a color object.
If you need to restore the composite integer into a color object, that is even simpler with Color.valueOf(colorInt)

Categories