0

I'm trying to figure out how to detect if a PNG with alpha channel is opaque or not. If it's opaque, all the pixels have a transparency channel at 100%, hence it should be possible to convert to formats like JPEG which doesn't support transparency.

This answer shows how to detect alpha channel, but not if the image is opaque.

ImageMagick can apparently do it with -format %[opaque], but i would like to be able to do it in pure Java.

Do you know if it's possible to perform this opaque detection with ImageIO?

gotson
  • 3,613
  • 1
  • 23
  • 40
  • 1
    In ImageMagick, I do that by getting the average (mean) value of the alpha channel in the range 0 to 1 (or 0 to 255). If the average is exactly 1 (or equivalently 255), then it is fully opaque. Otherwise, there is some transparency in the image. – fmw42 May 09 '20 at 04:06

1 Answers1

1

A thing possible is to use BufferedImage#getData and brute force going over all the pixels and checking their alpha. If one pixel doesn't have the alpha 1.0, the image isn't opaque. Here you can find a nice example of the how but by using BufferedImage directly rather than getting a Raster first.

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class DetectImageTransparency {

    public static void main(String... args) throws IOException {

        File pngInput = new File("/tmp/duke.png");
        BufferedImage pngImage = ImageIO.read(pngInput);
        checkTransparency(pngImage);

        File jpgInput = new File("/tmp/duke.jpg");
        BufferedImage jpgImage = ImageIO.read(jpgInput);
        checkTransparency(jpgImage);
    }

    private static void checkTransparency(BufferedImage image){
        if (containsAlphaChannel(image)){
            System.out.println("image contains alpha channel");
        } else {
            System.out.println("image does NOT contain alpha channel");
        }

        if (containsTransparency(image)){
            System.out.println("image contains transparency");
        } else {
            System.out.println("Image does NOT contain transparency");
        }
    }

    private static boolean containsAlphaChannel(BufferedImage image){
        return image.getColorModel().hasAlpha();
    }

    private static boolean containsTransparency(BufferedImage image){
        for (int i = 0; i < image.getHeight(); i++) {
            for (int j = 0; j < image.getWidth(); j++) {
                if (isTransparent(image, j, i)){
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean isTransparent(BufferedImage image, int x, int y ) {
        int pixel = image.getRGB(x,y);
        return (pixel>>24) == 0x00;
    }
}

NOTE: This is not my work. I've added the code to make the answer independent of the link. Here is the reference to the source.

akuzminykh
  • 4,522
  • 4
  • 15
  • 36
  • I tried the first method you mentioned, but it returns `TRANSLUCENT` while ImageMagick says it's opaque. – gotson May 08 '20 at 03:08
  • 1
    @Gauthier Yes, you are right. I've checked again and the returned value depends on the image format, not on the actual image data. Anyways, I've added a link where it is explained how to go over the pixels and check for transparency. – akuzminykh May 08 '20 at 03:24