I've tried to create colored gray image with given colour but I always failed. I know I have to use BufferedImage and load all pixels of source image into array, but I don't know how to work with color value, so there always were some weird colors after multiplying source color and given color (for the record I've got code to get int of color).
Thanks for any help.
e.g. http://dl.dropbox.com/u/17664230/ruka.png
Are you trying to change image gray channel (white-black) to (some_color-black) ?
public void recolor(BufferedImage source, BufferedImage destination, int color) {
WritableRaster destinationRaster = destination.getRaster();
Raster sourceRaster = source.getRaster();
//red, green, blue
int channels = new int[]{color & 0xFF0000, color & 0xFF00, color & 0xFF};
for (int channel=0; channel<3; channel++){
for (int y=0; y<sourceRaster.getHeight(); y++) {
for (int x=0; x<rangeSlicer.getWidth(); x++) {
pixel = sourceRaster.getSample(x, y, channel);
pixel = Math.round((double)pixel/255.0 * channels[channel]);
destinationRaster.setSample(x, y, channel, pixel);
}
}
}
}
Not sure if this compiles, but idea is that. For more effective program check RescaleOp.
I would define some alpha = 0.2 and do:
given gray #777777
make redder with:
new red = 77 * (1.0 + alpha)
new green = blue = 77 * (1.0 - alpha)
Actually, you have to be careful and make sure to truncate (1 + alpha) and (1 - alpha) such that you only use values between 0 and 1.0.
Use Math.min(0.0, 1.0 - alpha) instead of (1.0 - alpha) and Math.max(1.0, 1.0 + alpha) instead of (1.0 + alpha).
With this formula, if you are given black (#000000), it stays black. If you are given white (#FFFFFF), it ends up pink (#FFCCCC). If you set alpha = 1.0, white would end up pure red (#FF0000).
You could come up with different color scaling formulas, but I guess you should make sure that your transformation always keeps black as pure black.
Related
I have an application that requires me to mix two colors subtractively (as in mix them to get a result as if I has mixed two pigments). Just adding the RGB's doesn't work as RGB values operate additively, whereas pigments operate subtractively.
So what I'm trying to do is use HSL values. I convert the RGB to HSL using one of Java's Color Methods. I'm seeing colors as degrees on a wheel. Red has a hue value of 0, Green is 0.333, and Blue is 0.666. Since this is a wheel Red can also be 1, and green can also be 1.333.
So what I'm doing is averaging the hue values (as I'm mixing the "pigments" in equal ratios) along the shortest distance on the wheel. To explain, mixing blue (0.666) and red (0 or 1) would evaluate to 0.833, not 0.666. In my implementation, I account for this or at least try to, but there are some bugs...
public static Color addColors(Color a, Color b) {
float[] aHSB = toHSB(a);
float[] bHSB = toHSB(b);
double aHue = aHSB[0];
double bHue = bHSB[0];
System.out.println(aHue * 360 + ", " + bHue * 360);
double c = 0;
if (Math.abs(Math.abs(aHue - bHue) - 0.5) < 0.01) {
return Color.BLACK; //to account for complimentary colors
}
if (Math.abs(aHue - bHue) > 0.51) {
c = 0.5;
}
float temp = (float) (((aHue + bHue) / 2) % 1 + c);
Color d = new Color(Color.HSBtoRGB(temp,
(aHSB[1] + bHSB[1]) / 2,
(aHSB[2] + bHSB[2]) / 2));
return d;
}
When I mix Blue and Yellow, I get a green-ish tint. When I mix Red and Yellow, I get an orange, but when I mix orange and blue, I get a pink. I imagine there a problems with what I'm doing.
Are there better ways to mix colors given RGB values that yield results that match pigment mixing? Or am I on a (semi) right track and have just made a mistake?
I am currently creating a small 2d-game with lwjgl.
I tried to figure out a way of implementing a Fog-Of-War.
I used a black backgound with alpha set to 0.5.
Then I added a Square, to set alpha to 1 for each tile, which is lit, ending up having a black Background with differend Alpha values.
Then I rendered my Background using the blendfunction:
glBlendFunc(GL_ZERO, GL_SRC_ALPHA)
This works well, but now I have a problem with adding a second layer with transparent parts and apply the Fog-Of-War on them, too.
I've read something about FrameBufferObjects, but I don't know how to use them and if they are the right choice.
Later on I want to lit tiles with an texture/Image to give it a smoother look. So these textures may overlap. This is the reason why I chose to first render the Fog-Of-War.
Do you have an idea how to fix this problem?
Thanks to samgak.
Now I try to render a dark square on each dark tile exept the lit tiles.
I divided each tile in an 8x8 grid for more details. This is my method:
public static void drawFog() {
int width = map.getTileWidth()>>3; //Divide by 8
int height = map.getTileHeight()>>3;
int mapWidth = map.getWidth() << 3;
int mapHeight = map.getHeight() << 3;
//background_x/y is the position of the background in pixel
int mapStartX = (int) Math.floor(background_x / width);
int mapStartY = (int) Math.floor(background_y / height);
//Multiply each color component with 0.5 to get a darker look
glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
glBegin(GL_QUADS);
//RENDERED_TILES_X/Y is the amount of tiles to fill the screen
for(int x = mapStartX; x < (RENDERED_TILES_X<<3) + mapStartX
&& x < mapWidth; x++){
for(int y = mapStartY; y < (RENDERED_TILES_Y<<3) + mapStartY
&& y < mapHeight; y++){
//visible is an boolean-array for each subtile
if(!visible[x][y]){
float tx = (x * width) - background_x;
float ty = (y * height) - background_y;
glVertex2f(tx, ty);
glVertex2f(tx+width, ty);
glVertex2f(tx+width, ty+height);
glVertex2f(tx, ty+height);
}
}
}
glEnd();
}
I set the visible array to false except for an small square.
It will render fine, but if I move the background the whole screen except the visible square turns black.
One approach is to render the Fog-of-War layer last, using an untextured black square rendered over the top of all the other layers after they have been rendered.
Use this blend function:
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA)
and set the Fog-of-War alpha per-vertex so that when it is 1.0 the black overlay is transparent, and when it is 0.0, it is entirely black. (If you want the alpha to have the opposite meaning, just swap the arguments).
To make it more smooth you can set the alpha per vertex at each of the corners of the square to vary smoothly across it. You could also use a texture with varying alpha values instead of a plain black square, or subdivide the square into 4 or 16 squares to allow finer control.
I am looking to replace pixels in an image that are black to some degree (semi-black) to become fully black.
The method to do this is setRGB(int x, int y, int rgb). I know this. What I do not know is how to detect pixels that are semi-black.
I have tried (i is a BufferedImage):
final int rgb = i.getRGB(x, y);
if (rgb == -16777216) {
i.setRGB(x, y, -16777216);
}
To do this, but it only replaces the pixels that are pure black with pure black.
I have also tried dimming the image, but that does not work either.
Any ideas on how I test for generic blackness?
My goal: the image I am reading is thin text. I wish to make this bolder text by this.
The integer that you receive represents the combined red, green, blue and alpha values. Essentially, you need to:
break that integer down into its component red, green, blue values
from those values, assess the overall "brightness" of the pixel
As a rough implementation, you could do something like this:
int pixVal = ... getRGB() as you have
int red = (pixVal >>> 16);
int green = (pixVal >>> 8) & 0xff;
int blue = pixVal & 0xff;
int brightness = (red + green + blue) / 3;
if (brightness < 16) {
// pixel is black
}
Now, the value 16 is a rough value: ideally, you would tailor this to the particular image.
Purists might also whinge that the perceived "brightness" of a pixel isn't literally the mean of the red/green/blue pixels (because the human eye is not equally sensitive to these components). But that's the rough idea to work from.
I have a colour #6A8F6509
I wish to remove the Alpha part of that colour and be left with only RGB components (i.e. #RRGGBB).
The resulting colour must look identical to the initial one without the transparency.
How do I go about this on Android's Java?
Update: The initial background is always white (#FFF)
int newColor = oldColor | 0xFF000000;
If you want to do it with the code you can try following code:
static int stripAlpha(int color){
return Color.rgb(Color.red(color), Color.green(color), Color.blue(color));
}
For each color:
C' = C(a/255) + 255(1-(a/255))
So for #6A8F6509:
R' = 143(106/255) + 255(1-(106/255) = (approx) 208
G' = 101(106/255) + 255(1-(106/255) = (approx) 191
B' = 9(106/255) + 255(1-(106/255) = (approx) 153
So your answer should be: #D0BF99, if my math is correct. This only applies to an all white background as well - for a non-white background, the second addend should have the appropriate corresponding color value of the background instead of 255.
-- EDIT --
Looking at the formula again, I'm not entirely sure whether the formula gets applied to each color or the entire color (a quick visual test should be able to tell you - I'm guessing per color). I should point out that this is the formula direct from the Alpha Compositing wiki page:
http://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
try
#FF8F6509
the first two digits indicate the alpha value of any color.
Calculate the way a semi-transparent color will look when placed on top of another color.
Kotlin color extension:
#ColorInt
fun #receiver:ColorInt Int.removeAlpha(#ColorInt underlyingColor: Int): Int {
return ColorUtils.blendARGB(this, underlyingColor, alpha / 255F)
}
Usage:
Color.parseColor("#6A8F6509").removeAlpha(underlyingColor = Color.WHITE)
Jetpack Compose version is
Color(0x6A8F6509).compositeOver(Color.White)
I'll admit to not knowing Android's Java, but can't you just change the color from #6A8F6509 to #FF8F6509? The in most modern programming languages, color is typically encoded as ##AARRGGBB.
AA = Hex of the Alpha, ranging from 0 (hex 00), full transparent, to 255 (hex FF), no transparency.
RR = Hex of the red part of the color. Similar to above, 0 is no red, 255 is full red.
GG = Hex of green.
BB = Hex of blue.
-Edit-
Based on your update, you can do this to get the color:
For each of the red, green, and blue:
get the difference between the transparent color and the background color and multiply that by the alpha value. Divide that by 255 (hex FF, if you prefer). Finally, add that number to the transparent color's value.
In your case:
int transparentR = 0x8F;
int transparentG = 0x65;
int transparentB = 0x09;
int backgroundR = 0xFF;
int backgroundG = 0xFF;
int backgroundB = 0xFF;
int alpha = 0x6A;
int newR = transparentR + ( ( (backgroundR - transparentR) * alpha ) / 255 );
int newG = transparentR + ( ( (backgroundG - transparentG) * alpha ) / 255 );
int newB = transparentR + ( ( (backgroundB - transparentB) * alpha ) / 255 );
-Edit, again-
Ok, I've redone the formula based on LJ2's answer using Wikipedia's Alpha Blending function. and had a colleague confirm this with Paint.Net. This is the version where the background Color is fully opaque, and it's in C#, sorry:
int transparentColor2(int intFgColor, int intBgColor, int intAlpha)
{
double dAlpha = (Convert.ToDouble(intAlpha)/255.0);
double dFirst = Convert.ToDouble(intFgColor) * dAlpha;
double dSecond = Convert.ToDouble(intBgColor) * (1 - dAlpha);
return Convert.ToInt32(dFirst + dSecond);
}
do this for each R, G, and B value, and you should get the right answer. Incase Android's Java has different, double could be Double/Single/Float, and int could be Int32/Int16/Int64/Byte. I don't remember how to Convert between the two in Java, unfortunately.
Is there an easy way to convert between color models in Java (RGB, HSV and Lab).
Assuming RGB color model:
How do I calculate black body spectrum color palette? I want to use it for a heatmap chart.
How about single-wavelength spectrum?
Edit: I found that the ColorSpace class can be used for conversions between RGB/CIE and many other color models.
Java has built-in RGB to HSB conversion. Whenever I need a quick pallet of colors in Java I just do this:
public Color[] generateColors(int n)
{
Color[] cols = new Color[n];
for(int i = 0; i < n; i++)
{
cols[i] = Color.getHSBColor((float) i / (float) n, 0.85f, 1.0f);
}
return cols;
}
It is a quick and dirty hack (I would tweak the 'magic' numbers for your app), but for my simple uses it generates a nice bright pleasant pallet.
Maybe I'm not understanding your question, but you can't really generate a true black-body spectrum from an RGB output device. Limited color gamut would be an issue, if nothing else. If all you want is something that visually resembles a black-body spectrum, that's probably a lot easier.
As an approximation, ramp from (R,G,B) (0,0,0) to (255,0,0), then to (255,255,0), then to (255,255,255). That'd give you the dull-red to orange, to yellow, to white transition.
If you want something more scientific, the Wikipedia article on black body radiation has some plots of color vs temperature. Once you figure out the CIE coordinates, you can translate those to RGB in your favorite color space.
Edit: found some other online references:
What color is the Sun?
What color is a blackbody?
You can build such a palette using the HSV color-model. That's easy once you have the HSV to RGB code in place and play around with the numbers for some minutes.
However, I think it's not worth it to add the code to your project just to generate a little palette.
It's much easier and less work to extract the palettes you need from a file and add them as a static array.
Photoshop let's you edit palettes and comes with a very nice black body palette as a preset.
You can simply save these as a .act file. The file itself is just a simple 256 color รก 3 byte file (order is read, green, blue. 8 bits per channel).
You can generate this color spectrum https://i.stack.imgur.com/ktLmt.jpg
using the following code:
public void render(Screen screen) {
int green = 255;
int red = 0;
for (int i = 0; i <= 255 * 2; i++) {
int rate = i / 255;
screen.fillRect((x + (i * width)/6), y, width, height, new Color(red, green, 0));
red += 1 - rate;
green -= rate;
}
}
This is a nice way to make a HSL color square in AS3.
/**
* Generate a BitmapData HSL color square (n x n) of hue
* At a low n dimension you get cool blocky color palettes (e.g. try n=10)
*/
function generateColorSquare(n:uint, hue:uint):BitmapData
{
var bd:BitmapData = new BitmapData(n, n, false, 0xFFFFFF);
for (var i:uint=n*n; i > 0; i--)
{
bd.setPixel(i % n, Math.floor(i / n), HSBColor.convertHSBtoRGB(hue, i / (n*n), (1/n) * (i % n) ));
}
return bd;
}