I have a signed value e.g. -7368817
when I cast it to byte it will be something like: -113
I convert it to unsigned byte bye & 0xff and it will be something like 143
now I manipulate this byte value and after that I want to whole way back! to get the signed integer of the new byte. :)
Update
The whole story:
I have an image which is 8-bit depth and gray scale! it means that all pixels are presented using 1 byte
BufferedImage image = ImageIO.read(new File("my_grayscal_8bit_photo.jpg"));
int intPixel = image.getRGB(1, 1);
now I need some bit manipulation in this pixel but since it is int I must convert it to byte first:
byte bytePixel = (byte) intPixel;
and to make it unsigned:
int intPixel2 = bytePixel & 0xff;
now I do my bit manipulation and want to convert it to int and do:
image.setRGB(1, 1, neworiginalint);
The getRGB(int x, int y) method always returns an int pixel in the TYPE_INT_ARGB color model. To manually extract the red, green, blue and alpha values for the pixel you can do this:
int pixel = image.getRGB(1, 1);
int a = (pixel >> 24) & 0xFF;
int r = (pixel >> 16) & 0xFF;
int g = (pixel >> 8) & 0xFF;
int b = pixel & 0xFF;
Or use the Color(int rgba, boolean hasalpha) constructor for convenience (at the cost of performance). Once you've manipulated the red, green, blue and alpha values (in the range of 0 to 255) you can recombine them back into an int for setting pixels:
int newPixel = (a << 24) | (r << 16) | (g << 8) | b;
Using the -7368817 pixel you mentioned with this code, the alpha is 255 (so no transparency) and the red, green and blue values are all 143. Since you're dealing with grayscale you could just pick any of red, green or blue to get the gray value. However on setting the pixel you're going to have set all three to maintain the grayscale since it's RGB. You could shortcut it a bit like so:
int pixel = image.getRGB(1, 1);
// extract your gray value from blue, assume red and green are same
int gray = pixel & 0xFF;
// this method does your manipulation on the gray value, 0 to 255
gray = manipulate(gray);
// recombine back into int, preserving the original alpha
int newPixel = (pixel & 0xFF000000) | (gray << 16) | (gray << 8) | gray;
// now you can set your new pixel
image.setRGB(1, 1, nexPixel);
Basically the trick is to use int as your unsigned byte. Just make sure you keep the values from 0 to 255 and everything should work fine.
Are you asking how to manipulate the least-significant byte in an signed int, without touching the more significant byte?
This can be done like this:
int i = -7368817; // 0xFF8F 8F8F
int b = i & 0xFF; // "signed byte", = 0x8F = 143
b += 0x2C; // your manipulation, result = 0xBB
i = (i & 0xFFFFFF00) | (b & 0xFF); // result of LSB modification = 0xFF8F8FBB
or in one step: i = (i & 0xFFFFFF00) | ((i + 0x2C) & 0xFF); if it is a simple manipulation.
If the manipulation can't ever produce an overflow, you can simply do it on the whole int:
i ^= 0x34; // i = 0xFF8F8FBB
Related
The following code shows a part of my code.
When I delete the part between '// start of color extraction & composing'
and '// end of color extraction & composing' I always get the same color image back
in tmpBmp. But if I insert the part, then I always get a grey-level image
displayed (whereas I'm expecting the same color image).
Is there any reason that the code between '// start of color extraction & composing' and '// end of color extraction & composing' returns a grey-scaled image?
int width = captureBmp.getWidth();
int height = captureBmp.getHeight();
int red, green, blue, alpha;
Bitmap tmpBmp = captureBmp.copy(Bitmap.Config.ARGB_8888, true);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int value = captureBmp.getPixel(x, y);
// start of color extraction & composing
alpha = value & 0xFF000000 >> 24;
red = value & 0x00FF0000 >> 16;
green = value & 0x0000FF00 >> 8;
blue = value & 0x000000FF;
value = ( (alpha << 24) & 0xFF000000) |
( (red << 16) & 0x00FF0000) |
((green << 8) & 0x0000FF00) |
(blue & 0x000000FF);
// end of color extraction & composing
tmpBmp.setPixel(x, y, value);
}
}
ImageView imgView = (ImageView) findViewById(R.id.imageview);
imgView.setImageBitmap(tmpBmp);
The line
red = value & 0x00FF0000 >> 16
is the same as
red = value & (0x00FF0000 >> 16)
Note that (0x00FF0000 >> 16) is just 0x000000FF. The same happens for green and blue, so you get the same value three times. Hence it's grey.
The alpha value is different because 0xFF000000 >> 24 is 0xFFFFFFFF due to the way the signed right shift works.
The solution is to rebracket. (I'd also use >>> for this, but it actually makes no difference because alpha gets shifted back 24 places left anyway).
alpha = (value & 0xFF000000) >>> 24;
red = (value & 0x00FF0000) >>> 16;
green = (value & 0x0000FF00) >>> 8;
blue = value & 0x000000FF;
The problem is that this code:
alpha = value & 0xFF000000 >> 24;
red = value & 0x00FF0000 >> 16;
green = value & 0x0000FF00 >> 8;
blue = value & 0x000000FF;
First masks with bitwise mask and then shifts, try the opposite. Shift then, bitmask with 0xFF.
It probabbly has to do with byte formats and unsigned integers and unsigned right shift in java.
As already noted by #Paul Boddington operator precedence plays a major part.
The question is pretty much inside the title.
I want to host inside a byte ,a color without losing any sort of information, keeping in mind that the Color.argb is actually an int.
Byte colorToSave;
colorToSave = Color.argb(255, 255,0, 100);
As far as I know this is pretty much impossible, but perhaps someone found a nice workaround.
No its not possible - the core of Color.argb is a number of bitwise operations -
alpha << 24) | (red << 16) | (green << 8) | blue;
So if we break it down with your values (255,255,0,100) you can see that you can see the precision loss -
int alpha = 255;
System.out.println(Integer.toBinaryString(alpha));
int red = 255;
System.out.println(Integer.toBinaryString(red));
int green = 0;
System.out.println(Integer.toBinaryString(green));
int blue = 100;
System.out.println(Integer.toBinaryString(blue));
int argb = 255<<24 | 255 << 16 | 0 << 8 | 100;
System.out.println(Integer.toBinaryString(argb));
byte argbbyte = (byte) argb;
System.out.println(Integer.toBinaryString(argbbyte));
Producing an output -
11111111
11111111
0
1100100
11111111111111110000000001100100
1100100
The final part of the output is casting the int to a byte which shows we return the color for blue
Here is my code for GrayScale filter want to know about this
class GrayScale extends RGBImageFilter {
#Override
public int filterRGB(int x, int y, int rgb) {
int a = rgb & 0xff000000;
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
rgb = (r * 77 + g * 151 + b * 28) >> 8;
return a | (rgb << 16) | (rgb << 8) | rgb;
}
}
The format of your input is 0xAARRGGBB where AA is the alpha (transparency), RR is the red, GG is the green, and BB is the blue component. This is hexadecimal, so the values range from 00 to FF (255).
Your question is about the extraction of the alpha value. This line:
int a = rgb & 0xFF000000
If you consider a value like 0xFFFFFFFF (white), AND will return whatever bits are set in both the original colour and the mask; so you'll get a value of 0xFF, or 255 (correctly).
The
int a = rgb & 0xff000000;
...
return a | ...;
simply preserves the top 8 bits of rgb (which contain the alpha component).
Beside Ashes999 and NPE answers, if you want to know how it's treated internally in java, check out this post
thank you for your time :). I have already taken a look at Format of TYPE_INT_RGB and TYPE_INT_ARGB and now know how to convert this TYPE_INT_RGB into 4 separate values, but if I were to do a modification to each (say add 20 to each, so Alpha+=20, red+=20, and so on) how would I recombine these values into this TYPE_INT_RGB formatting? Thank you!
// to extract the components into individual ints.
int argb = something();
int red = 0xFF & ( argb >> 16);
int alpha = 0xFF & (argb >> 24);
int blue = 0xFF & (argb >> 0 );
int green = 0xFF & (argb >> 8 );
// to recreate the argb
int argb = (alpha << 24) | (red << 16 ) | (green<<8) | blue;
I would use java.awt.Color for this.
int ARGB = new Color(red, green, blue, alpha).getRGB();
I guess you are using bitwise operations to pull out the individual color channels, but again the Color class can hide those gory details.
Color color = new Color(ARGB);
int red = color.getRed();
int green = color.getGreen();
// etc.
I believe this should work
int RGB = alpha;
RGB = (RGB << 8) + red;
RGB = (RGB << 8) + green;
Rgb = (RGB << 8) + blue;
There's another way without bit shifting, but I'm sure you'll figure it out.
This one is okay, too:
int rgba = new java.awt.Color(r,g,b,a).getRGB();
I try to convert image to RGB565 format.
I read this image:
BufferedImage bufImg = ImageIO.read(imagePathFile);
sendImg = new BufferedImage(CONTROLLER_LCD_WIDTH/*320*/, CONTROLLER_LCD_HEIGHT/*240*/, BufferedImage.TYPE_USHORT_565_RGB);
sendImg.getGraphics().drawImage(bufImg, 0, 0, CONTROLLER_LCD_WIDTH/*320*/, CONTROLLER_LCD_HEIGHT/*240*/, null);
Here is it:
Then I convert it to RGB565:
int numByte=0;
byte[] OutputImageArray = new byte[CONTROLLER_LCD_WIDTH*CONTROLLER_LCD_HEIGHT*2];
int i=0;
int j=0;
int len = OutputImageArray.length;
for (i=0;i<CONTROLLER_LCD_WIDTH;i++) {
for (j=0;j<CONTROLLER_LCD_HEIGHT;j++) {
Color c = new Color(sendImg.getRGB(i, j));
int aRGBpix = sendImg.getRGB(i, j);
int alpha;
int red = c.getRed();
int green = c.getGreen();
int blue = c.getBlue();
//RGB888
red = (aRGBpix >> 16) & 0x0FF;
green = (aRGBpix >> 8) & 0x0FF;
blue = (aRGBpix >> 0) & 0x0FF;
alpha = (aRGBpix >> 24) & 0x0FF;
//RGB565
red = red >> 3;
green = green >> 2;
blue = blue >> 3;
//A pixel is represented by a 4-byte (32 bit) integer, like so:
//00000000 00000000 00000000 11111111
//^ Alpha ^Red ^Green ^Blue
//Converting to RGB565
short pixel_to_send = 0;
int pixel_to_send_int = 0;
pixel_to_send_int = (red << 11) | (green << 5) | (blue);
pixel_to_send = (short) pixel_to_send_int;
//dividing into bytes
byte byteH=(byte)((pixel_to_send >> 8) & 0x0FF);
byte byteL=(byte)(pixel_to_send & 0x0FF);
//Writing it to array - High-byte is second
OutputImageArray[numByte]=byteH;
OutputImageArray[numByte+1]=byteL;
numByte+=2;
}
}
Then I try to restore this from resulting array OutputImageArray:
i=0;
j=0;
numByte=0;
BufferedImage NewImg = new BufferedImage(CONTROLLER_LCD_WIDTH, CONTROLLER_LCD_HEIGHT, BufferedImage.TYPE_USHORT_565_RGB);
for (i=0;i<CONTROLLER_LCD_WIDTH;i++) {
for (j=0;j<CONTROLLER_LCD_HEIGHT;j++) {
int curPixel=0;
int alpha=0x0FF;
int red;
int green;
int blue;
byte byteL=0;
byte byteH=0;
byteH = OutputImageArray[numByte];
byteL = OutputImageArray[numByte+1];
curPixel= (byteH << 8) | (byteL);
//RGB565
red = (curPixel >> (6+5)) & 0x01F;
green = (curPixel >> 5) & 0x03F;
blue = (curPixel) & 0x01F;
//RGB888
red = red << 3;
green = green << 2;
blue = blue << 3;
//aRGB
curPixel = 0;
curPixel = (alpha << 24) | (red << 16) | (green << 8) | (blue);
NewImg.setRGB(i, j, curPixel);
numByte+=2;
}
}
I output this restored image. But I see that it looks very poor.
I expected the lost of pictures quality.
But as I thought, this picture has to have almost the same quality as the previous picture. Is it right?
Is my code right?
The reason you see these yellow artefacts is simply due to negative values for byteL overwriting bits from byteH containing the correct values for red and (part of) green channels. Let me explain.
Remember, if the highest bit in a byte is set to 1, the value is considered negative (-128 to -1 instead of 128 to 255), and by converting it to an int all the extra high-bits are set to 1 to conserve the same values (-128 to -1).
In your program, these extra bits set to 1 are in direct conflict with the value in byteH when applying the OR bit-operator |, overwriting (saturating) the red and (part of) green values you are trying to extract and display.
curPixel = (byteH << 8) | (byteL); // BUG: issue with negative byteL values
A solution is to apply an AND-mask to be sure to get rid of any unwanted bits before applying the OR bit-operator.
curPixel = byteL & 0xFF; // Convert byte to int to be within [0 , 255]
curPixel = (byteH << 8) | curPixel; // Apply OR bit-operator