Changing RGB ints after parsing from hex - java

The code:
String green = "#99FFCC";
adjustColor(green);
private int adjustColor(String color){
int colorToAdjust = Color.parseColor(color);
//Pseudocode
int red = colorToAdjust.getRed(); //get red value from RGB
red *= 0.5; //halve it
colorToAdjust.setRed(red); //set red value
return colorToAdjust;
}
Given a string hex color, I parse it to an int. How do I change the individual RGB colors? Above is a somewhat pseudo-code of what I'm trying to do: parse hex, get individual color, change it, write it back

You can simply extract the amount of Red by calling red() function and then create the new color based on the original values of Blue & Green and the halved value of the Red you extracted before.
You can then create the new color by calling the rgb() function and passing it the new values of Red, Green & Blue.
Here is the code snippet:
String green = "#99FFCC";
adjustColor(green);
private int adjustColor(String color) {
/* Get RGB Value Of Color */
int colorToAdjust = Color.parseColor(color);
/* Get Red Value From RGB */
int redAmount = Color.red(colorToAdjust);
/* Return New Color By Halving Red */
return Color.rgb(0.5 * redAmount, Color.green(colorToAdjust),
Color.blue(colorToAdjust));
}
You can have a look at this Reference for more information.

Related

Sorting an ArrayList<Color> based on RGB

i'm having trouble trying to sort an ArrayListof Color.
I'm retrieving all the colors from this image
imgRed.jpg
The code i'm using:
public static ArrayList<Color> getColors(BufferedImage img){
int height = img.getHeight();
int width = img.getWidth();
boolean found = false;
ArrayList<Color> List = new ArrayList<>();
for(int x=0;x<width;x++) {
for(int y=0;y<height;y++) {
found = false;
Color color = new Color(img.getRGB(x, y));
for(Color c : List) {
if(color.getRGB()<c.getRGB()+100 && color.getRGB()>c.getRGB()-100) {
found=true;
}
}
if(!found) {
List.add(color);
}
}
}
return List;
}
After i've collected all the colors, i sort them:
Collections.sort(Colors, Comparator.comparing(Color::getRed)
.thenComparing(Color::getGreen)
.thenComparing(Color::getBlue));
Subsequently i create a new image containing all the colors sorted:
public static void createImage(ArrayList<Color> Colors) {
int width=500;
int height=Colors.size()*10;
BufferedImage b_img = new BufferedImage(width,height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = b_img.createGraphics();
int partialHeight = 0;
int amount = Colors.size();
for(Color c : Colors) {
System.out.println("Colors remaining: "+amount);
graphics.setPaint ( c );
graphics.fillRect ( 0, partialHeight, b_img.getWidth(), partialHeight+10 );
partialHeight = partialHeight + 10;
amount--;
}
File outFile = new File("C:/test/img/out/testColor/outputRed4.png");
try {
ImageIO.write(b_img, "png", outFile);
} catch (IOException e) {
e.printStackTrace();
}
}
This function produces this image: outputRed.png
As you can see, the colors are not really sorted. This is because (i think) colors are sorted basing its numeric value (Red, Green, Blue) and because the RGB numeric value isn't ordered by our perspective.
I remember that the image produced hasn't a color twice so all the color in that image are different.
My question is:
How can i order all the colors following all the shades of each color without having such a jagged result?
Thanks to all
The issue you are encountering comes from the fact that you are taking 3-dimensional data (red values, green values, blue values) and trying to order them in 1 dimension (a List with only an index parameter).
The output you are receiving is most likely exactly what you should expect if you sort first, by the red value of a colour, and then by the green, and then blue. Remember, this method only compares the green value to sort colours with identical red values, and similarly only compares the blue value to sort colours with identical red and blue values.
Perhaps the reason it looks "jagged" is because of the suddenly changing intensity. Given that the input image is pretty much entirely shades of red at different intensities, it might be worth using Comparator.comparing(Color::getTotal) where getTotal() is defined as:
int getTotal() {
return getGreen() + getBlue() + getRed();
}
This will sort by intensity (i.e. brightness), and will make the image look less "jagged", but on images with more than just red, the colours will not be in "colour order" or "rainbow order".
Again, this is an issue of trying to map 3-d data into a 1-d space. Compromises will always have to be made.

Java, image is changing to wrong rgb values

i wrote a java code to change all the red values of a black and white image to 255, so the output would be a red image.
But its not red, instead it outputs a brighter image.
What did I do wrong?
File bwgFile = new File("X:/Java/Documents/NetBeansProjects/colour/input/bwg.png");
BufferedImage bwgImage = ImageIO.read(bwgFile);
int width=bwgImage.getWidth();
int height=bwgImage.getHeight();
for(int w=0; w<width; w++){
for(int h=0; h<height; h++){
int pixel = bwgImage.getRGB(w,h);
Color bwg = new Color(pixel);
int c=bwg.getRed();
Color red = new Color(255,c,c);
int cpixel = red.getRGB();
bwgImage.setRGB(w,h,cpixel);
}
}
ImageIO.write(bwgImage, "png", new File("X:/Java/Documents/NetBeansProjects/colour/output/c.png"));
input
output
EDIT:
I have found out what the problem was, apparently when the input is a greyscale image it will try to make the output a greyscale image as well thus making it darker when blue and green colors get removed and brighter when red gets added. not using a grayscale image as input fixed it.
If I understand what you're trying to do, you're trying to create a greyscale image, except that it is "redscale", using only shades of red. Therefore, you need to compute the greyscale constant of each pixel.
From wikipedia (Greyscale), the luminance of a pixel Y = 0.2126R + 0.7152G + 0.0722B. So, try this
int pixel = bwgImage.getRGB(w,h);
Color bwg = new Color(pixel);
float c = (0.2126f * bwg.getRed() + 0.7152f * bwg.getGreen() + 0.0722f * bwg.getBlue());
int cc = (int)Math.round(c);
Color red = new Color(cc, 0, 0);
int cpixel = red.getRGB();
bwgImage.setRGB(w,h,cpixel);
Alternatively, you can simply retain the red component and set green and blue to 0. This will leave you with just the "redness" of each pixel.
int pixel = bwgImage.getRGB(w,h);
Color bwg = new Color(pixel);
int c=bwg.getRed();
Color red = new Color(c,0,0);
int cpixel = red.getRGB();
bwgImage.setRGB(w,h,cpixel);
NOTE: This solution above only works on images that are not using IndexColorModel. You can check the color model using BufferedImage's getColorModel(). For IndexColorModel, setRGB() does not work directly and instead picks a color in the index closest to the set color, as per HaraldK's comment. To achieve the desired result for images using IndexColorModel, you can create a new BufferedImage with TYPE_INT_ARGB:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Then, write the calculated pixel colors to this new image and save the new image instead.

Java Color conversion

I am having a problem using a method from com.esri.arcgis.display.IColor. The method is IColor.getRGB() which returns an int.
IColor symbolColor = symbol.getColor();
int colorInt = symbolColor.getRGB();
//TODO: get RGB values from colorInt
From the documentation:
RGB returns the Long (ASCII) number calculated from the Red, Green and Blue color attributes.
I need to get the individual RGB values (standard 0-255) from this int somehow but I have been unable to find almost any information on converting from an ASCII number to RGB values.
Have solved by converting the int to hex, and then decoding the hex string using Color.decode() to obtain a Color. Using Color instance we can grab the individual RGB values.
IColor symbolColor = symbol.getColor();
int colorInt = symbolColor.getRGB();
String hexColor = Integer.toHexString(colorInt);
Color color = Color.decode("#"+hexColor);
int red = color.getRed();
int blue = color.getBlue();
int green = color.getGreen();
int alpha = color.getAlpha();`
It is possible to convert these values by transferring their RGB integer.
int rgb = symbol.getColor().getRGB();
Color color = new Color(rgb);
int red = color.getRed();
int blue = color.getBlue();
int green = color.getGreen();
int alpha = color.getAlpha();
You might need to further investigate wether that rgb variable also contains the alpha values, in which case you want to use new Color(rgb, true) instead.

Get RGB components from ColorModel

I want to extract the R,G and B values of the pixels of an image. I do it in two ways.
File img_file = new File("../foo.png");
BufferedImage img = ImageIO.read(img_file);
1st method(which works fine):
img.getRaster().getPixel(i, j, rgb);
2nd method(which throws new IllegalArgumentException("More than one component per pixel"))
red = img.getColorModel().getRed(img.getRGB(i, j));
What is the reason for this behaviour?
Normally when I want to extract RGB from a BufferedImage I do something like this:
File img_file = new File("../foo.png");
BufferedImage img = ImageIO.read(img_file);
Color color = new Color(img.getRGB(i,j));
int red = color.getRed();
Based on the JavaDocs
An IllegalArgumentException is thrown if pixel values for this
ColorModel are not conveniently representable as a single int
It would suggest that the underlying color model is representable by a single int value
You may also want to take a look at this answer for some more details
Typically, you would simply take the int packed pixel from the image and use Color to generate a Color representation and then extract the values from there...
First, get the int packed value of the pixel at x/y...
int pixel = img.getRGB(i, j);
Use this to construct a Color object...
Color color = new Color(pixel, true); // True if you care about the alpha value...
Extract the R, G, B values...
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
Now you could simply do some bit maths, but this is simpler and is more readable - IMHO

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