Reputation: 70
I am trying to replace some pixels from my source image(PNG format). But i am end up with some confusing result. Basically i am replacing a particular RGB values with black and white colors. Here is my code,
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ChangePixel
{
public static void main(String args[]) throws IOException
{
File file = new File(System.getProperty("user.dir"), "D4635.png");
FileInputStream fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);
int[] replaceColors = new int[2];
replaceColors[0] = Color.BLACK.getRGB();
replaceColors[1] = Color.WHITE.getRGB();
Color src = new Color(133, 101, 51);
int srcRGBvalue = src.getRGB();
changeAlg2(image, srcRGBvalue, replaceColors);
}
private static void changeAlg2(BufferedImage image, int srcRGBvalue, int[] replaceColors) throws IOException
{
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (image.getRGB(width, height) == srcRGBvalue)
{
image.setRGB(width, height, ((width + height) % 2 == 0 ? replaceColors[0] : replaceColors[1]));
}
}
}
File file = new File(System.getProperty("user.dir"), "107.png");
ImageIO.write(image, "png", file);
}
}
It changes my source pixels to black and some other color, instead of white. Please advice me, what's going wrong here.
Since this is my first post, I can't able to attach my images. Sorry for the inconvenience.
Edit: I have uploaded the source and the output images in a site. Here is the URL, Source : http://s20.postimage.org/d7zdt7kwt/D4635.png Output : http://s20.postimage.org/kdr4vntzx/107.png Expected output : After the black pixel, white pixel has to come.
Edit : Resolved code as per Jan Dvorak advice,
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ChangePixel
{
public static void main(String args[]) throws IOException
{
File file = new File(System.getProperty("user.dir"), "D12014.gif");
FileInputStream fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);
Color src = new Color(223, 170, 66);
int srcRGBvalue = src.getRGB();
int[] replaceColors = new int[2];
replaceColors[0] = Color.MAGENTA.getRGB();
replaceColors[1] = Color.CYAN.getRGB();
changeAlg2(image, srcRGBvalue, replaceColors);
}
private static void changeAlg2(BufferedImage image, int srcRGBvalue, int[] replaceColors) throws IOException
{
BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
for (int width = 0; width < image.getWidth(); width++)
{
for (int height = 0; height < image.getHeight(); height++)
{
if (image.getRGB(width, height) == srcRGBvalue)
{
image2.setRGB(width, height, ((width + height) % 2 == 0 ? replaceColors[0] : replaceColors[1]));
}
else
{
image2.setRGB(width, height, image.getRGB(width, height));
}
}
}
File file = new File(System.getProperty("user.dir"), "110.gif");
ImageIO.write(image2, "gif", file);
}
}
Regards Raja.
Upvotes: 1
Views: 1633
Reputation: 27317
Since you are adding colors that are not present in the original image palette, the pixels you are trying to set are clipped to the nearest color in the palette. You need to set a new color mode. Either convert to 24bpp RGB (true-color) or extend the palette with the new colors.
It doesn't seem to be possible to modify an existing BufferedImage
ColorModel
or assign a new one, but you can create a new buffer and copy the data there. Creating a new BufferedImage
with the same Raster
might work as well (only if the bit depth does not change?).
If you don't mind, you can always create a True-color image. try:
{
BufferedImage old = image;
image = new BufferedImage(
old.getWidth(),
old.getHeight(),
BufferedImage.TYPE_INT_RGB
);
image.setData(old.getRaster());
} // old is no longer needed
API reference: http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html
You could try to detect if the image is already in true-color (image.getColorModel() instanceof ???
) to avoid having to copy the buffer when not needed.
You could try to extend the existing palette. If that is not possible (there is no palette to start with or there is not enough space), you have to fallback to RGB.
See:
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html (getColorModel and the constructor taking a ColorModel and type)
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/IndexColorModel.html (getMapSize, getRGBs and the corresponding constructor)
From seeing your actual palette, you'll need some sort of deduplication logic because your palette is already 256 bytes - the maximum size of a PNG palette. Note that you should not save the image with larger palette than there are colors in the image (especially when you want to add new colors later). your original file could have been saved with a 2-color palette, saving 762 bytes.
Note that you don't gain much from storing the image as indexed as opposed to true-color with the same number of colors. The reason is that the byte stream (palette = 1 byte per pixel, true-color = 3 or 4 bytes per pixel) is losslessly compressed (with DEFLATE) anyways. Indexed can save you a few bytes (or lose you a few bytes, if the palette is big), but it won't reduce the file size to one third.
Upvotes: 1