BufferedImage Color Channel Mask - java

I have found this code on JavaDoc, but I can't seem to understand it.
output.setRGB(x, y, (image.getRGB(x, y) & 0xff00ff00)
| ((image.getRGB(x, y) & 0xff0000) >> 16)
| ((image.getRGB(x, y) & 0xff) << 16));
All I know that this code turns blue color to red in a BufferedImage.
but what if I want to replace blue with white or some other color and vice-versa?
I would appreciate any help.

Colors are stored like this, in hexadecimal:
RRGGBBAA
Red, green, blue, alpha. Now let's take a look at one of the lines:
(image.getRGB(x, y) & 0xff0000) >> 16
image.getRGB(x, y) would return an RRGGBBAA value, and this line is bitmasking it with 0xff0000. Here is a visual:
RRGGBBAA
&
00FF0000
=
00GG0000
Therefore, it transforms the RRGGBBAA value into GG0000.
Then, there is a bitshift 16 binary bits to the right. Java can't shift bits in hexadecimal, but we are visualizing the colors in hexadecimal right now. Therefore, we must convert the 16 binary shifts into 4 hex shifts, because hexadecimal is base-16. Binary is base-2, and 2^4 is 16, the base of hexadecimal.
Therefore, you must shift right 4 bits. This would turn GG0000 into GG, since the bits are being shifted 4 places to the right.
Therefore, we now have the value for the amount of green in our color.
You can apply similar logic to the other lines to see how they work.

When I work with color I use different idea:
BufferedImage image = //create Buffered image
int rgb = image.getRGB(x,y); //get Rgb color value
Color color = new Color(rgb); // create color with this value
Color resultColor = new Color(color.getRed(), color.getBlue(), color.getGreen()); //create new color change blue and green colors values
image.setRGB(x,y,resultColor.getRGB()); //set color
I think this idea is easier to understand.
if you want to get white color use this :
BufferedImage image = new BufferedImage();
Color color = new Color(255,255,255);
image.setRGB(x,y,color.getRGB());

Related

Loading 8-bit grayscale image using ImageIO

I want to load a 8-bit grayscale image using grayscaleImage = ImageIO.read(grayscaleFile). However, the BufferedImage class (which is the type of grayscaleImage) only provides a method getRGB(int x, int y). So, what are the values of color.getRed(), color.getGreen(), color.getBlue() and color.getAlpha() where
Color color = new Color(grayscaleImage.getRGB(x, y), true);
From a first observation, it seems like the 8-bit value, stored in the image file at pixel (x,y), is propagated into the red, green and blue component of color while it's alpha value is fixed at 255.
Can someone confirm this observation?
The value that is obtained with image.getRGB(x,y) is an int that consists of the three color components Red, Green and Blue, each having 8 bit. The Alpha value is fixed as 255 when the image does not contain transparency.
When the image is a grayscale image, the Red, Green and Blue components of this RGB value will be all equal. So you can obtain the "gray" value as
int rgb = image.getRGB(x,y);
// This yields a value between 0 (black)
// and 255 (white) :
int gray = rgb & 0xFF;
That's right. A gray color is just a color with same value in three color's components (red, green, blue). Although you only need one value to determine the color (because red, green and blue components have the same value), at image loading that value is assign to all three color components.
If you get the value for each pixel of the image, you must obtain the same value for three color's components for the same pixel x,y. For alpha component, as it's a grayscale image, is correct it be at 255.

Using BufferedImage to create an image in Java

I am trying re-create an image using given 2D pixel arrays (rows, and columns) using the setRGB() method in BufferedImage.
Below is the follwing code:
BufferedImage bufferedImage = new BufferedImage(reconstructedJPEG[0].length, reconstructedJPEG.length, BufferedImage.TYPE_INT_RGB);
//loop through redPixels[][] array
for(int row=0; row<redPixels.length; row++){
for(int col=0; col<redPixels[0].length; col++){
//call setRGB() on redPixels
bufferedImage.setRGB(col, row, (redPixels[row][col]));
}
}
The code above works, but I am not sure how I can also set the green and blue pixel arrays?
Right now, its a very dull, dark red/purple image, that does no look like the original image.
Also, is there a another away I can form these arrays into a 1D image (which would be its raw pixels, red+green+blue components into one integer?
Thanks any help would be great.
Combine the individual color values for the 3 channels (red, green and blue) in one pixel using bitwise operators:
int rgb = (redValue & 0xff) << 16 | (greenValue & 0xff) << 8 | (blueValue & 0xff);
Then call setRGB with the composed value as parameter:
bufferedImage.setRGB(col, row, rgb);
The bitwise operation sentence can be cumbersome at first sight but it does the following:
Take every channel value and make it 8-bit range based value (0, 255) using the & 0xff mask (the format BufferedImage.TYPE_INT_RGB expects channels to be 8-bit values)
redValue & 0xff,
greenValue & 0xff,
blueValue & 0xff
Accommodates the channel values packing then into one 32 bit integer using the following layout:

Convert 8-bit Indexed color to RGB

I cannot find a conversion routine for converting 8-bit indexed color to RGB. For some background details, I am using POI to read an xlsx file and one of the cells has a background color indexed as value 64. When I attempt to create a PdfPCell in iText with this value for the background BaseColor, I get a Navy Blue and the correct color should be Black. So I need a routine that will convert the value of 64 to rgb(0, 0, 0).
This is the code that sets the background to Navy Blue
short c = ((XSSFColor) color).getIndexed();
BaseColor base = new BaseColor(c);
I found a similar question here on SO but the "packed" routine failed with "Color value outside range 0-255".
short packed = ((XSSFColor) color).getIndexed();
log.debug("Indexed {}", packed);
int r = (packed >> 5) * 32;
int g = ((packed >> 2) << 3) * 32;
int b = (packed << 6) * 64;
BaseColor base = new BaseColor(r, g, b);
Update 1: It seems that there is a Palette somewhere in the document, in my case an XSSFPalette. Once I find the answer I'll update it here.
Update 2: XSSFWorkbook doesn't provide access to the palette, hence my follow question: Access to the color palette in an XSSFWorkbook
There isn't a mathematical relationship between color index and RGB values. It's a lookup.
Eight-bit indexed color means that each pixel's color is represented by the number 0-255. What those colors actually are depends on your pallette (just like a painter would use!) The eight bits, therefore, allow you to have 256 separate colors in your picture.
If your image displays in color, then you have a pallette somewhere that will tell you what index corresponds to what RGB triplet.
http://en.wikipedia.org/wiki/Indexed_color

Color detector in Java

I have list of colors in HEX format (for example #000000) and I would like to detect color type (blue, red, green etc.) and then change color type to another color type. Is this possible and are there any frameworks/libraries for this task?
Example:
I have color #EB1369 (red) then I convert it to blue and it becomes for example #1313EB (blue).
Here's a function that will let you shift colors around the hue circle. You should read the wikipedia page on the HSB (or HSV) color system to really understand what is going on: http://en.wikipedia.org/wiki/HSV_color_space
/** Converts an input color given as a String such as "ab451e" to
* the HSB color space. Shifts its hue from the given angle in degrees.
* Then returns the new color in the same format it was given.
*
* For example shift("ff0000", 180); returns "80ff00" (green is the opposite of red).*/
public static String shift(String rgbS, int angle) {
// Convert String to integer value
int value = Integer.parseInt(rgbS, 16);
// Separate red green and blue
int r = value >> 16;
int g = (value >> 8) & 0xff;
int b = value & 0xff;
// Convert to hsb
float[] hsb = Color.RGBtoHSB(r, g, b, null);
// Convert angle to floating point between 0 and 1.0
float angleF = (float)(angle/360.0);
// Shift the hue using the angle.
float newAngle = hsb[0] + angleF;
if(newAngle > 1.0)
newAngle = newAngle - 1.0f;
hsb[0] = newAngle;
// Convert back to RGB, removing the alpha component
int rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
rgb = rgb & 0xffffff;
// Build a new String
return Integer.toHexString(rgb);
}
Detecting colors can be complex, it depends on the result you really expect.
If what you want is simply an approximation (red, green, blue, yellow, etc.) then you can look at the hue circle of the HSB color-space, choose a hue value for each color you want to define, and then map the color you get in input to the closest one you chose.
You can also rely on things like named HTML colors: http://www.w3schools.com/html/html_colornames.asp . Take this list, create a mapping in your program, then all you have to do is map the color you get to the closest one in your map, and return its name. Be wary though: computing the distance between two colors can be tricky (especially in RGB) and naive approaches (such as channel-by-channel difference) can give surprisingly bad results. Colorimetry is a complex topic, and you will find good methods on this page: http://en.wikipedia.org/wiki/Color_difference
Try convert RGB values to HSV (HSB exactly) - it is format for colors which is more comfortable for human. After conversion, all u need to do is change H V (probably) and convert it back to RGB.
I guess that you like to convert RGB color to HSB. YOu can do this wuth:
java.awt.Color.RGBtoHSB(...)
then you can easily determine whetther H value fits in your definition of blue, and modify it to whatever you like. After this, you can easily convert it back to RGB via:
java.awt.Color.getHSBColor(...)
And ifg you do not like jawa.awt.color just multiply color vector by transofrmation matrix.
Each HEX Color has three parts in it, red, green and blue the # identifies a HEX color, the following two letters are the amount of red; the next two are green and the next two are blue. i.e: RGB
The two letters can have a maximum hexidecimal value of FF which is 255, and a minimum of 00 which is zero.
So you can argue like this, I want a color with 2 red parts, 7 green parts, and zero blue parts, which will give you #020700
That is why #FFFFFF is white (all the colors together) and #000000 is black (no colors at all)
With this logic you can modify the color in any way you want; The Color class can also help a lot.

How to use this Color's constructor? Java

According to Oracle's site, the class Color has a constructor that accepts a single int value which represents an RGB value. http://download.oracle.com/javase/1.4.2/docs/api/java/awt/Color.html#Color(int)
An RGB color is actually three different numbers ranging from 0-255. So combining them together to make one int would look like this:
White 255,255,255
White 255255255
Right? So I pass this to the constructor and get a vibrant teal color. What am I doing wrong? What haven't I understood?
From Convert RGB values to Integer
int rgb = red;
rgb = (rgb << 8) + green;
rgb = (rgb << 8) + blue;
To pull values out:
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
Javadoc from the other constructor:
Creates an sRGB color with the
specified combined RGBA value
consisting of the alpha component in
bits 24-31, the red component in bits
16-23, the green component in bits
8-15, and the blue component in bits
0-7. If the hasalpha argument is
false, alpha is defaulted to 255.
So, you just need to construct the int using bit operations.
Color col=new Color(255,255,255);
Label l1=new Label("I got this color");
//setting the color in label background
l1.setBackground(col);

Categories

Resources