Two similar methods with BufferedImage, one working, one not. Why? - java

I have tried to make method which changes one color of BufferedImage to be invisible.
I can't find solution myself so I ask for your help.
Here is method made by me:
public static BufferedImage makeWithoutColor(BufferedImage img, Color col)
{
BufferedImage img1 = img;
BufferedImage img2 = new BufferedImage(img1.getWidth(), img1.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img2.createGraphics();
g.setComposite(AlphaComposite.Src);
g.drawImage(img1, null, 0, 0);
g.dispose();
for(int i = 0; i < img2.getWidth(); i++)
{
for(int j = 0; i < img2.getHeight(); i++)
{
if(img2.getRGB(i, j) == col.getRGB())
{
img2.setRGB(i, j, 0x8F1C1C);
}
}
}
return img2;
}
And here is one from tutorial i read.
public static BufferedImage makeColorTransparent(BufferedImage ref, Color color) {
BufferedImage image = ref;
BufferedImage dimg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = dimg.createGraphics();
g.setComposite(AlphaComposite.Src);
g.drawImage(image, null, 0, 0);
g.dispose();
for(int i = 0; i < dimg.getHeight(); i++) {
for(int j = 0; j < dimg.getWidth(); j++) {
if(dimg.getRGB(j, i) == color.getRGB()) {
dimg.setRGB(j, i, 0x8F1C1C);
}
}
}
return dimg;
}

Your mistake is this line:
for(int j = 0; i < img2.getHeight(); i++)
should be:
for(int j = 0; j < img2.getHeight(); j++)
// ^ ^ as Ted mentioned...

I assume that by "invisible" you mean that you want to make one color transparent. You aren't going to be able to do it using this approach, because setRGB doesn't affect the alpha channel. You are better off using an image filter. Here's an approach taken from this thread:
public static Image makeWithoutColor(BufferedImage img, Color col)
{
ImageFilter filter = new RGBImageFilter() {
// the color we are looking for... Alpha bits are set to opaque
public int markerRGB = col.getRGB() | 0xFF000000;
public final int filterRGB(int x, int y, int rgb) {
if ((rgb | 0xFF000000) == markerRGB) {
// Mark the alpha bits as zero - transparent
return 0x00FFFFFF & rgb;
} else {
// nothing to do
return rgb;
}
}
};
ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
This will turn any pixel with the indicated RGB color and any transparency to a fully transparent pixel of the same color.

Related

Change the color of each pixel in an image java

I wanna change different pixel to different color. Basically, change part of pixel to transparent.
for(int i = 0; i < image.getWidth();i++)
for(int j = 0; j < image.getHeight(); j ++)
{
image.setRGB(i,j , 0);
}
//I aslo change the third parameter 0 to another attribute. but it still does not work. it all show black. do you have some ideas?
yin.
thanks
class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel(int width, int height, BufferedImage image) {
this.image = image;
image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
repaint();
}
/**
* Draws the image.
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < image.getWidth(); i++) {
for (int j = 0; j < image.getHeight(); j++) {
image.setRGB(i, j, 0);
}
}
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
The third parameter is ARGB value in 32 bits. This is laid out in bit form as:
AAAAAAAA|RRRRRRRR|GGGGGGGG|BBBBBBBBB
See the javadoc for BufferedImage.setRGB (assuming your using BufferedImage, your question doesn't actually say...)
Sets a pixel in this BufferedImage to the specified RGB value. The
pixel is assumed to be in the default RGB color model, TYPE_INT_ARGB,
and default sRGB color space. For images with an IndexColorModel, the
index with the nearest color is chosen
If you're using an image type that supports transparency it is important you set alpha 255 means fully opaque, 0 is fully transparent.
You can create such a value using bit shifting.
int alpha = 255;
int red = 0;
int green = 255;
int blue = 0;
int argb = alpha << 24 + red << 16 + green << 8 + blue
image.setRGB(i, j, argb);
Luckily there is a getRGB() method on java.awt.Color instances, so you could use
image.setRGB(i, j, Color.green.getRGB());
Here's a full working example, perhaps you can compare to your code:
public class StackOverflow27071351 {
private static class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel(int width, int height, BufferedImage image) {
this.image = image;
image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < image.getWidth(); i++) {
for (int j = 0; j < image.getHeight(); j++) {
image.setRGB(i, j, new Color(255, 0, 0, 127).getRGB());
}
}
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
int width = 640;
int height = 480;
frame.setSize(width, height);
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(new ImagePanel(width, height, image));
frame.setVisible(true);
}
}
Well, 3rd parameter is the color in RGB, so it will be black if you set it to 0.
here is a sample code:
private int colorToRGB(int alpha, int red, int green, int blue) {
int newPixel = 0;
newPixel += alpha;
newPixel = newPixel << 8;
newPixel += red;
newPixel = newPixel << 8;
newPixel += green;
newPixel = newPixel << 8;
newPixel += blue;
return newPixel;
}
then
image.setRGB(i, j, colorToRGB(alpha, 0, 0, 0))
I use the following form:
int[] pixel = new int[4];
// the following four ints must range 0..255
pixel[0] = redValue;
pixel[1] = greenValue;
pixel[2] = bluleValue;
pixel[3] = alphaValue;
raster.setPixel(x, y, pixel);
To get a raster for a BufferedImage, I do this:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
WritableRaster raster = image.getRaster();
I've done some performance testing, and have not found that stuffing all the bytes of color values into a single number to make much of a difference.
It is also good to know the technique where one can draw an opaque image (e.g., RGB rather than an ARGB) with an alpha value.
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) (yourAlpha)));
g2d.drawImage(...);

Java ImageIO.write is Colorizing a Greyscale Image

I'm having a problem that's been driving me crazy for days. Hopefully, someone here can help me understand what's happening. I'm trying to write a simple Java program that will take a directory of JPEGs, convert them to greyscale, and save them to the same folder.
My procedure is to set the red, green, and blue components of each pixel to that pixel's luminance value. The code runs fine and seems to do what I want. If I view the completed image in a JFrame, it shows up black and white. However, when I save the image (using ImageIO.write()), for some reason, it becomes colorized and looks rather red. I'd love to post the images but I guess my reputation is not good enough...
Since I can't put the images, I'll try to explain it as well as I can. Here's what I know:
If I view the newly created image using the Java program, it appears black and white as I desire.
If I save the image and try to view it using an external program, it does not appear black and white at all and just looks like a watered down version of the original image.
If I open that same saved image (the one that should be black and white but is not) using the Java program, it does indeed appear black and white.
If I save the file as a png instead, everything works fine.
Here's the relevant code I'm using if anyone would like to see it:
import java.io.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.*;
public class ImageEZ {
public static void displayImage(BufferedImage img) {
class ImageFrame extends JFrame {
ImageFrame(BufferedImage img) {
super();
class ImagePanel extends JPanel {
BufferedImage image;
ImagePanel(BufferedImage image) {
this.image = ImageEZ.duplicate(image);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), this);
}
}
ImagePanel panel = new ImagePanel(img);
add(panel);
}
}
JFrame frame = new ImageFrame(img);
frame.setSize(img.getWidth(), img.getHeight());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static BufferedImage duplicate(BufferedImage img) {
BufferedImage dup = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
dup.setRGB(0, 0, img.getWidth(), img.getHeight(), ImageEZ.getRGB(img), 0, img.getWidth());
return dup;
}
public static int[] getRedArray(BufferedImage img) {
int[] tArray = ImageEZ.getRGB(img);
for (int i = 0; i < tArray.length; i++) {
tArray[i] = tArray[i] << 8;
tArray[i] = tArray[i] >>> 24;
}
return tArray;
}
public static int[] getRedArray(int[] tArray) {
int[] nArray = new int[tArray.length];
for (int i = 0; i < tArray.length; i++) {
nArray[i] = tArray[i] << 8;
nArray[i] = nArray[i] >>> 24;
}
return nArray;
}
public static int[] getGreenArray(BufferedImage img) {
int[] tArray = ImageEZ.getRGB(img);
for (int i = 0; i < tArray.length; i++) {
tArray[i] = tArray[i] << 16;
tArray[i] = tArray[i] >>> 24;
}
return tArray;
}
public static int[] getGreenArray(int[] tArray) {
int[] nArray = new int[tArray.length];
for (int i = 0; i < tArray.length; i++) {
nArray[i] = tArray[i] << 16;
nArray[i] = nArray[i] >>> 24;
}
return nArray;
}
public static int[] getBlueArray(BufferedImage img) {
int[] tArray = ImageEZ.getRGB(img);
for (int i = 0; i < tArray.length; i++) {
tArray[i] = tArray[i] << 24;
tArray[i] = tArray[i] >>> 24;
}
return tArray;
}
public static int[] getBlueArray(int[] tArray) {
int[] nArray = new int[tArray.length];
for (int i = 0; i < tArray.length; i++) {
nArray[i] = tArray[i] << 24;
nArray[i] = nArray[i] >>> 24;
}
return nArray;
}
public static int[] YBRtoRGB(int[] ybr) {
int[] y = getRedArray(ybr);
int[] r = getBlueArray(ybr);
int[] b = getGreenArray(ybr);
int[] red = new int[y.length];
int[] green = new int[y.length];
int[] blue = new int[y.length];
for (int i = 0; i < red.length; i++) {
red[i] = (int) (y[i] + 1.402*r[i]);
green[i] = (int) (y[i] + -.344*b[i] + -.714*r[i]);
blue[i] = (int) (y[i] + 1.772*b[i]);
}
int[] RGB = new int[red.length];
for (int i = 0; i < red.length; i++) {
RGB[i] = red[i] << 16 | green[i] << 8 | blue[i] | 255 << 24;
}
return RGB;
}
public static int[] getLumArray(BufferedImage img) {
int[] red = getRedArray(img); //Returns an array of the red values of the pixels
int[] green = getGreenArray(img);
int[] blue = getBlueArray(img);
int[] Y = new int[red.length];
for (int i = 0; i < red.length; i++) {
Y[i] = (int) (.299*red[i] + .587*green[i] + .114*blue[i]);
}
return Y;
}
// Converts an image to greyscale using the luminance of each pixel
public static BufferedImage deSaturate(BufferedImage original) {
BufferedImage deSaturated = new BufferedImage(original.getWidth(),
original.getHeight(),
BufferedImage.TYPE_INT_ARGB);
int[] Y = ImageEZ.getLumArray(original); //Returns an array of the luminances
for (int i = 0; i < Y.length; i++) {
Y[i] = 255 << 24 | Y[i] << 16;
}
int[] rgb = ImageEZ.YBRtoRGB(Y); //Converts the YCbCr colorspace to RGB
deSaturated.setRGB(0, 0, original.getWidth(), original.getHeight(),
rgb, 0, original.getWidth());
return deSaturated;
}
// Takes a folder of JPEGs and converts them to Greyscale
public static void main(String[] args) throws Exception {
File root = new File(args[0]);
File[] list = root.listFiles();
for (int i = 0; i < list.length; i++) {
BufferedImage a = ImageEZ.deSaturate(ImageIO.read(list[i]));
displayImage(a); //Displays the converted images.
boolean v = ImageIO.write(a, "jpg", new File(list[i].getParent() + "\\" + i + ".jpg"));
}
// Displays the first newly saved image
displayImage(ImageIO.read(new File(list[0].getParent() + "\\" + 0 + ".png")));
}
}
I just want to stress, this is not a question about alternative methods for turning making an image black and white. What I really want to know is why it works as a png but not as a jpg. Thanks a lot to all who read this far!
This is a known issue with ImageIO.
When saved/loaded as jpeg, the API doesn't know how to handle the alpha component (as I understand the problem).
The solution is to not write images with an alpha component to jpg format, or use a non-alpha based image, such as TYPE_INT_RGB instead...

Converting Colors

I'm trying to write a method for my game that will take an image, the hex value for the old color, and the hex value for the new color and then convert all pixels of the old color to the new color. Right now, the method paints the entire image the new color, as if the if statement is not working at all. This the method:
private void convertColors(BufferedImage img, int oldColor, int newColor)
{
Graphics g = img.getGraphics();
g.setColor(new Color(newColor));
Color old = new Color(oldColor);
for(int x = 0; x < img.getWidth(); x++)
{
for(int y = 0; y < img.getHeight(); y++)
{
Color tmp = new Color(img.getRGB(x, y));
if(tmp.equals(old));
{
System.out.println("Temp=" + tmp.toString() + "Old=" + old.toString() + "New=" + g.getColor().toString());
g.fillRect(x, y, 1, 1);
}
}
}
g.dispose();
}
*The hex for oldColor is 0xFFFFFF (white) and for newColor is 0xFF0000 (red).
Using the println method I get these kind of results:
Temp=java.awt.Color[r=0,g=0,b=0]Old=java.awt.Color[r=255,g=255,b=255]New=java.awt.Color[r=255,g=0,b=0]
Temp=java.awt.Color[r=255,g=255,b=255]Old=java.awt.Color[r=255,g=255,b=255]New=java.awt.Color[r=255,g=0,b=0]
The scond line looks correct, the temp color and the old are the same, but that is obviously not the case with the first. I have also tried creating a new BufferedImage and copy over the pixels but that leaves the same result... Does the equals method not work as I think it does or does this entire method just not work and there's a better way to do this? Thanks for you help in advance.
Just remove the ; after if(tmp.equals(old)).
Otherwise you compare the colors and do nothing after the comparsion and always choose the new color.
Besides that you need to reorganize your code a little bit to make it slightly more efficient:
Graphics g = img.getGraphics();
g.setColor(new Color(newColor));
for(int x = 0; x < img.getWidth(); x++) {
for(int y = 0; y < img.getHeight(); y++) {
if(img.getRGB(x, y) == oldColor) {//check if pixel color matches old color
g.fillRect(x, y, 1, 1);//fill the pixel with the right color
}
}
}
g.dispose();
Just because i was interested in the topic: relying on image filters you could do all that via:
class ColorSwapFilter extends RGBImageFilter {
int newColor, oldColor;
public ColorSwapFilter(int newColor, int oldColor) {
canFilterIndexColorModel = true;
this.newColor = newColor;
this.oldColor = oldColor;
}
#Override
public int filterRGB(int x, int y, int rgb) {
return rgb == oldColor ? newColor : oldColor;
}
}
which should be called via
BufferedImage img;//your image
ColorSwapFilter filter = new ColorSwapFilter(...,...);//your colors to be swapped.
ImageProducer producer = img.getSource();
producer = new FilteredImageSource(producer, filter);
Image im = Toolkit.getDefaultToolkit().createImage(producer);
You have a semicolon direct after your if statement if(tmp.equals(old));
This esentially tells Java that your if statement has only one command associated with it, and that command is a single semicolon, effectively meaning "do nothing". If you remove it, it will restore the condition on the block of code beneath it, which right now is just running every time regardless of the condition.
I got it to work; this is the working convertColors method:
private BufferedImage convertColors(BufferedImage img, int oldColor, int newColor)
{
int [] pixels = new int [img.getWidth() * img.getHeight()];
img.getRGB(0, 0, img.getWidth(), img.getHeight(), pixels, 0, img.getWidth());
Color old = new Color(oldColor);
Color newC = new Color(newColor);
for(int x = 0; x < img.getWidth(); x++)
{
for(int y = 0; y < img.getHeight(); y++)
{
Color tmp = new Color(pixels[x + y * img.getWidth()]);
if(tmp.equals(old))
{
pixels[x + y * img.getWidth()] = newC.getRGB();
}
}
}
img.setRGB(0, 0, img.getWidth(), img.getHeight(), pixels, 0, img.getWidth());
return newImg;
}

Change color of non-transparent parts of png in Java

I am trying to automatically change the color for a set of icons.
Every icon has a white filled layer and the other part is transparent.
Here is an example: (in this case it's green, just to make it visible)
I tried to do the following:
private static BufferedImage colorImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy++) {
Color originalColor = new Color(image.getRGB(xx, yy));
System.out.println(xx + "|" + yy + " color: " + originalColor.toString() + "alpha: "
+ originalColor.getAlpha());
if (originalColor.equals(Color.WHITE) && originalColor.getAlpha() == 255) {
image.setRGB(xx, yy, Color.BLUE.getRGB());
}
}
}
return image;
}
The problem I have is that every pixel I get has the same value:
32|18 color: java.awt.Color[r=255,g=255,b=255]alpha: 255
So my result is just a colored square.
How can I achieve to change the color of the non-transparent parts only? And why is it, that all pixels have even the same alpha value? I guess that's my main problem: That the alpha value isn't read correctly.
Why it doesn't work, I don't know, this will.
This changes all the pixles to blue, maintaining their alpha values...
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class TestColorReplace {
public static void main(String[] args) {
try {
BufferedImage img = colorImage(ImageIO.read(new File("NWvnS.png")));
ImageIO.write(img, "png", new File("Test.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
private static BufferedImage colorImage(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
WritableRaster raster = image.getRaster();
for (int xx = 0; xx < width; xx++) {
for (int yy = 0; yy < height; yy++) {
int[] pixels = raster.getPixel(xx, yy, (int[]) null);
pixels[0] = 0;
pixels[1] = 0;
pixels[2] = 255;
raster.setPixel(xx, yy, pixels);
}
}
return image;
}
}
The problem is, that
Color originalColor = new Color(image.getRGB(xx, yy));
discards all the alpha values. Instead you have to use
Color originalColor = new Color(image.getRGB(xx, yy), true);
to keep alpha values available.
If your bitmap is already set in an ImageView, just do :
imageView.setColorFilter(Color.RED);
to set all non transparent pixels to red.
Since we will always be replacing only the first three bands of the RGB pixel, more effective way to achieve the same without unnecessary allocation of new arrays would be:
private static void colorImageAndPreserveAlpha(BufferedImage img, Color c) {
WritableRaster raster = img.getRaster();
int[] pixel = new int[] {c.getRed(),c.getGreen(),c.getBlue()};
for (int x = 0; x < raster.getWidth(); x++)
for (int y = 0; y < raster.getHeight(); y++)
for (int b = 0; b < pixel.length; b++)
raster.setSample(x,y,b,pixel[b]);
}

convert color image to grayscale

I want to convert a color image to grayscale.First I getting the data of color image and change this data but when I want to create a gary image from this data I have a error like this...
getData() maethod:
public double[] getData(BufferedImage a){
double[] data2=new double[h*w];
int red=0,green=0,blue=0;
int counter=0;
for(int w1=0;w1<w;w1++){
for(int h1=0;h1<h;h1++){
int rgb=a.getRGB(w1,h1);
red=(rgb)>> 16;
green=(rgb)>>8;
blue=(rgb);
data2[counter]=(red+green+blue)/3;
counter++;
}
}
return data2;
}
createimage() method:
void createImage(){
double[] data1=getData(colorImage);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
WritableRaster raster = image.getRaster();
int counter = 0 ;
for(int i = 0; i<h; i++){
for(int j = 0; j<w; j++){
raster.setSample(i, j, 0, data1[counter]);
counter++;
}
}
}
as it looks for me, the i and j in the setSample call must be swapped. (or w and h in BufferedImage)

Categories

Resources