G-Cam
G-Cam

Reputation: 291

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:

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!

Upvotes: 1

Views: 1554

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347214

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...

Upvotes: 2

Related Questions