28

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?

Spoike
  • 119,724
  • 44
  • 140
  • 158
corgrath
  • 11,673
  • 15
  • 68
  • 99

2 Answers2

45

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
  • 40,535
  • 6
  • 96
  • 134
  • 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 Mar 20 '09 at 09:14
  • 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 Mar 20 '09 at 09:19
  • 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 Mar 20 '09 at 09:23
  • OK, I added code to convert Image to BufferedImage, I will show how to save as well, to be complete. – PhiLho Mar 20 '09 at 09:25
  • +1, what is idea behind `filterRGB`? How can I specify an arbitrary color to be converted to transparent? – Nikolay Kuznetsov Feb 20 '13 at 07:53
  • @NikolayKuznetsov the "idea behind `filterRGB`" is explained at http://docs.oracle.com/javase/7/docs/api/java/awt/image/RGBImageFilter.html ... You can check if the rgb parameter is equal to the color you need to convert, and return a fully transparent color in this case, or the unchanged rgb parameter otherwise. – PhiLho Feb 20 '13 at 09:50
  • Yes, I saw the docs. But not clear whether `rgb` parameter is 4 meaningful bytes or just 3. And where transparency comes from, from magic number within 3 bytes or value in the 4th byte? – Nikolay Kuznetsov Feb 20 '13 at 10:10
  • 1
    The alpha channel is indeed the fourth byte. In doubt, experimentations (and debug) is the best way forward... :-) – PhiLho Feb 20 '13 at 10:14
  • Hi, is your return statement correct here : `return rgb & 0xFFFFFF;` I think it should be `return rgb & 0xFFFFFFFF;` regarding your first code block. Cheers ;-) – kisp Apr 08 '14 at 08:42
  • @kisp I fear you don't understand the point of these binary operations... The `& 0xFF000000` isolates the alpha channel value; the `& 0xFFFFFF` cuts out this alpha channel (sets it to zero). – PhiLho Jul 11 '14 at 10:51
  • Hi @PhiLho thanks for your answer. It's OK to you to understand well your own code. On the other hand I just suggested a much better understandable way to write the alpha channels zeroes on the front. In case when you are not 100% sure about the filter API you use... in case when this page could help someoneelse... So my question in the correct form is an analogue of this : does alpha 0 means transparent and FF is fully opaque? Then why dont you name your first filter to 'transform red to opaque' instead of TransformGrayToTransparency? – kisp Jul 15 '14 at 12:49
20

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
  • 11,673
  • 15
  • 68
  • 99