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:
Related
Today I was working on a game in Java, a classic old MUD RPG, and think that was a good idea to create the map with Paint and saving it in bitmap.
The idea is that, I read the image pixel by pixel and based on the color, I load the properties of the cell.
I had no problem to reading it, but I find a strage thing. Some colors change their RGB value, by a little, and then the values that I expected for a particular type of cell is not matched anymore.
In the first place I thought it was my mistake, some errors in the code but opening paint again just give me the answer, which is that some colors (not just some pixel) are changed.
By changing the format from BMP to DIB it seems to work fine. But why saving a bitmap in bmp format change the colors?
This is how I read the map:
BufferedImage mapImg = ImageIO.read(new File(path));
for (int y = 0; y < col; y++) {
for (int x = 0; x < row; x++) {
int pixel = mapImg.getRGB(y, x);
int red = (pixel >> 16) & 0xff;
int green = (pixel >> 8) & 0xff;
int blue = (pixel) & 0xff;
}
}
And works fine.
I am using ImageIO to import an Image to store the image components (alpha, red, green, blue) in a byte array. Later on i need to read from this byte array, But i don't know in which sequence the components (I don't know if first element is alpha, second is red ... or not in the array) are stored and is alpha even stored ?
Is there a default sequence ? or Is there a way to change the sequence to some desired one like ABGR or ARGB etc.
Current code for getting the components in the array.
BufferedImage temp;
try{
temp = ImageIO.read(new File(path));
ImageArray = ((DataBufferByte)temp.getRaster().getDataBuffer()).getData();
}catch(IOException ex){
ex.printStackTrace();
}
the java documents didn't help me at all.
The BufferedImage object in java has two relevant methods:
int getRGB(int x, int y)
and
void setRGB(int x, int y, int rgb)
In both cases the pixel channels alway follow the same scheme regardless of how the picture is setup. The int rgb is a four byte integer.
The left most byte is the alpha, followed by red then blue then green. That is, argb. Since one byte can hold a small integer from values 0 to 255. Each byte has 256 different individual intensities. The actual bits look like this:
aaaaaaaarrrrrrrrggggggggbbbbbbbb
To extract the color or alpha you would like to access use the bitwise operators.
If I wanted just the red for example, I could use the bitshift operater to shift the bits 16 places right and then and it with a hex value to extract just that channel:
int rgb = image.getRGB(x, y);
int a = (rgb >> 24) & 0x000000ff;
int r = (rgb >> 16) & 0x000000ff;
int g = (rgb >> 8) & 0x000000ff;
int b = (rgb) & 0x000000ff;
Lets see how that plays out. Suppose we already have a color:
rgb -> the binary 00101011 10101010 11111111 00000000
Then lets shift it 16 bits to the right:
00000000 00000000 00101011 10101010
Notice, now the alpha is still there...and we don't want it. So we will clear everything but the red bits by anding them:
00000000 00000000 00101011 10101010
and 00000000 00000000 00000000 11111111
= 00000000 00000000 00000000 10101010
Which is just the red component of color 10101010.
You can also set all three channels of bits using the same line of thinking in reverse:
int rgb = (a << 24) | (r << 16) | (g << 8) | b;
...assuming each channel is already between 0-255.
I always remember how to use the bitwise operators by using the mnemonic
"set-or clear-and". That means to set a bit to 1 use "or". To clear a bit to 0 use "and". The "<<" and ">>" shift the bits left or right by a number of times specified by the operand on the right of the arrows.
AMENDED ANSWER (After code was added to question)
Even though it is discouraged for performance and clarity reasons, the raster can be directly accessed as various arrays. In these cases, the order of bytes follows the Type and Color Model of the image. Here is one such example:
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
// If we swap the type, what we put in our for loop will vary greatly
DataBufferByte dbb = ((DataBufferByte)img.getRaster().getDataBuffer());
byte[] bytes = dbb.getData();
for (int i = 0; i < bytes.length; i++) {
// modify byte array here with bytes[i];
}
try {
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_BYTE, 100, 100, 3, 100*3, new int[]{2, 1, 0});
DataBuffer dataBuffer = new DataBufferByte(bytes, bytes.length);
Raster raster = Raster.createRaster(sampleModel, dataBuffer, null);
img.setData(raster);
} catch stuff......
If you were to change TYPE_3BYTE_BGR to TYPE_3BYTE_RGB, every third byte (3n) would be red instead of blue in the example above; also, every third plus two (3n+2) byte would be blue instead of red. This would essentially just swap the red and blue bytes.
If TYPE_3BYTE... is changed from BYTE to INT, the array will be an array of bytes instead of ints.
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
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());
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);