views:

5709

answers:

3

I have been searching the web for this, but I havent found any decent help.

I have a BufferedImage, which I have read in with ImageIO. Now I would like to make a certain color in that image to transparent, and save the image as PNG.

I know I cannot just "paint" the transparent color for obvious reasons, so I am guessing I need some kind of a filter.

Anyone got some sample code for this?

+7  A: 

I did that recently, to answer a question of my project manager.
The function transforming gray to transparency is:

  private Image TransformGrayToTransparency(BufferedImage image)
  {
    ImageFilter filter = new RGBImageFilter()
    {
      public final int filterRGB(int x, int y, int rgb)
      {
        return (rgb << 8) & 0xFF000000;
      }
    };

    ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
    return Toolkit.getDefaultToolkit().createImage(ip);
  }

Actually, it acts on a gray-level image, so I just copy a RGB component (the R one) to alpha, discarding the others which are identical in my case.
You can adapt it to filter a specific color, eg. with a test of equality or range, etc.
Of course, the BufferedImage must be of BufferedImage.TYPE_INT_ARGB type.

I don't address the question of saving, as it is pretty trivial, but I can add this code page too.

[EDIT] To convert Image to BufferedImage:

BufferedImage dest = new BufferedImage(
    imageWidth, imageHeight,
    BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();

[EDIT 2] I come after Christoffer posted his complete solution, but here is mine, I show how to make a range of colors transparent. Can be improved, eg. using HSB components instead.

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;
import java.io.*;

import javax.imageio.ImageIO;

public class AddTransparency
{
  AddTransparency() throws IOException
  {
    String imagePath = "E:/Documents/images/";
    File inFile = new File(imagePath, "map.png");
    BufferedImage image = ImageIO.read(inFile);

    Image transpImg1 = TransformGrayToTransparency(image);
    BufferedImage resultImage1 = ImageToBufferedImage(transpImg1, image.getWidth(), image.getHeight());

    File outFile1 = new File(imagePath, "map_with_transparency1.png");
    ImageIO.write(resultImage1, "PNG", outFile1);

    Image transpImg2 = TransformColorToTransparency(image, new Color(0, 50, 77), new Color(200, 200, 255));
    BufferedImage resultImage2 = ImageToBufferedImage(transpImg2, image.getWidth(), image.getHeight());

    File outFile2 = new File(imagePath, "map_with_transparency2.png");
    ImageIO.write(resultImage2, "PNG", outFile2);
  }

  private Image TransformGrayToTransparency(BufferedImage image)
  {
    ImageFilter filter = new RGBImageFilter()
    {
      public final int filterRGB(int x, int y, int rgb)
      {
        return (rgb << 8) & 0xFF000000;
      }
    };

    ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
      return Toolkit.getDefaultToolkit().createImage(ip);
  }

  private Image TransformColorToTransparency(BufferedImage image, Color c1, Color c2)
  {
    // Primitive test, just an example
    final int r1 = c1.getRed();
    final int g1 = c1.getGreen();
    final int b1 = c1.getBlue();
    final int r2 = c2.getRed();
    final int g2 = c2.getGreen();
    final int b2 = c2.getBlue();
    ImageFilter filter = new RGBImageFilter()
    {
      public final int filterRGB(int x, int y, int rgb)
      {
        int r = (rgb & 0xFF0000) >> 16;
        int g = (rgb & 0xFF00) >> 8;
        int b = rgb & 0xFF;
        if (r >= r1 && r <= r2 &&
            g >= g1 && g <= g2 &&
            b >= b1 && b <= b2)
        {
          // Set fully transparent but keep color
          return rgb & 0xFFFFFF;
        }
        return rgb;
      }
    };

    ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
      return Toolkit.getDefaultToolkit().createImage(ip);
  }

  private BufferedImage ImageToBufferedImage(Image image, int width, int height)
  {
    BufferedImage dest = new BufferedImage(
        width, height, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = dest.createGraphics();
    g2.drawImage(image, 0, 0, null);
    g2.dispose();
    return dest;
  }

  public static void main(String[] args) throws IOException
  {
    AddTransparency at = new AddTransparency();
  }
}
PhiLho
Hi PhiLho. Does that means you now can answer http://stackoverflow.com/questions/266486/in-java-how-do-you-write-a-java-awt-image-bufferedimage-to-an-8-bit-png-file ? Or are those two questions unrelated ?
VonC
Ok, so I get an Image, but I cannot save Images with ImageIO.write. I have to convert an Image to BufferedImage?There must be a more simple way.
corgrath
If you have any example code on how to save the Image, or any other fancy stuff you can do with the Image, that would be awesome.
corgrath
OK, I added code to convert Image to BufferedImage, I will show how to save as well, to be complete.
PhiLho
Awesome, thanks. I got it working :) thanks.
corgrath
+2  A: 

Thanks to PhilLo here is a complete solution of my demo application.

public static void main(String[] args) throws Exception {

     File in = new File("C:\\Users\\Christoffer\\Desktop\\christoffer.jpg");
     BufferedImage source = ImageIO.read(in);

     int color = source.getRGB(0, 0);

     Image image = makeColorTransparent(source, new Color(color));

     BufferedImage transparent = imageToBufferedImage(image);

     File out = new File("C:\\Users\\Christoffer\\Desktop\\trans.PNG");
     ImageIO.write(transparent, "PNG", out);

    }

    private static BufferedImage imageToBufferedImage(Image image) {

     BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
     Graphics2D g2 = bufferedImage.createGraphics();
     g2.drawImage(image, 0, 0, null);
     g2.dispose();

     return bufferedImage;

    }

    public static Image makeColorTransparent(BufferedImage im, final Color color) {
     ImageFilter filter = new RGBImageFilter() {

      // the color we are looking for... Alpha bits are set to opaque
      public int markerRGB = color.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);
    }
corgrath
Great. You should select PhiLho's answer as the "official" one though (or at least give him an upvote ;) )
VonC
Good, I posted my own demo code, showing an alternative filter.
PhiLho
Done. I think ive selected philhos answer as the correct one.
corgrath
A: 

Hi there. Thank you for the solution. It makes complete sense and works perfectly for the application I'm developing (2d pokemon graphics for a mmo).

Is there any materials you would recommend to me to improve my 2dgraphics abilities in java?

Damien Stevens (Computer Science Student, United Kingdom)