1

I have a problem with regards to changing my PNG image to grayscale. I wanted to make a method that would accept byte[] image as a parameter and return back as a newly modified grayscale image as byte[] also.

I found some links that make images grayscale with JPEG images using below snippet.

private byte[] makeItGray(byte[] img, String contentType) throws IOException, Exception{


    InputStream in = new ByteArrayInputStream(img);
    BufferedImage bimg = ImageIO.read(in);

    for(int y=0; y < bimg.getHeight(); y++){
        for(int x=0; x < bimg.getWidth(); x++){
            Color color = new Color(bimg.getRGB(x,y));
            int graylevel = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
            int r = graylevel;
            int g = graylevel;
            int b = graylevel;
            int rgb = ( r<<16 ) | ( g<<8 ) | b;
            bimg.setRGB(x, y, rgb);
        }
    }

    in.close();


    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    if(contentType.equals(MediaType.IMAGE_PNG_VALUE)){
        ImageIO.write(bimg, "png", baos);
        System.out.println("PNG!!!");
    }
    else if(contentType.equals(MediaType.IMAGE_JPEG_VALUE)){
        ImageIO.write(bimg, "jpg", baos);
    }
    else
        throw new Exception();



    baos.flush();
    byte[] grayImage = baos.toByteArray();
    baos.close();

    return grayImage;
}

My references were on below : How can I use ImageJ as a library for a separate Java application? https://www.mkyong.com/java/how-to-convert-byte-to-bufferedimage-in-java/

It works on JPEG images but on PNG, it sends me a transparent image.

// converting orig image to grayscale in byte[] 
imageBytes = makeItGray(imageBytes, file.getContentType());
Path path = Paths.get("some path here that would overwrite existing image");
Files.write(path, imageBytes);

When I try to open the image manually to check if it is grayscale, it gives me transparent image or no image is showing but not null since it returns byte[] data. I was wondering if the above method is ok with PNG formats?

Please let me know for any questions. Thanks!

rushi
  • 132
  • 1
  • 12
bpunzalan
  • 328
  • 1
  • 5
  • 23
  • What do you mean by "open the image manually" and how do you know it is transparent? – Mike Nakis Jul 05 '17 at 07:21
  • just to check if the image is in grayscale, i open it manually and it shows transparent?? because there is no error on my application and whenever my program make a GET request on the image (png) it fills the tag with base64 data. But, there is no image, its like transparent. – bpunzalan Jul 05 '17 at 07:25

2 Answers2

1

Actually, the getRGB and setRGB methods, despite their names, actually returns and accepts a pixel in 32 bit packed ARGB format. That means that if the color model of your BufferedImage actually contains an alpha channel, leaving the alpha values of the pixel empty (0x00) as you do, will result in an all transparent image...

The PNG format supports alpha, while JPEG normally don't use it, that is why you see the results you do, and why it seems to work different for the different formats.

The fix is simple though, just prepend the pixel value with all opaque alpha:

int rgb = 0xff000000 | (r << 16) | (g << 8) | b;
bimg.setRGB(x, y, rgb);

If you want to retain the alpha of the original, you can do that too (I simpliedfied the code a little):

int oldrgb = bimg.getRGB(x,y);
Color color = new Color(oldrgb);
int gray = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
int rgb = (oldrgb & 0xff000000) | (gray << 16) | (gray << 8) | gray;
bimg.setRGB(x, y, rgb);

PS: Note that your way of computing gray values by averaging isn't the recommended way to convert RGB to grayscale, so your images may look off compared to other tools. See for example Converting color to grayscale.

Harald K
  • 23,992
  • 6
  • 49
  • 97
  • Wow! This works like a charm! :) Thank you for a detailed answer and explanation to the problem. May be I could also do this on my issue in imagej whenever I add a string in the image with ARGB values. – bpunzalan Jul 05 '17 at 08:58
0
public class GrayScaleImage{
    public static void main(String[]args)throws IOException{

        BufferedImage img = null;
        File f = null;
        try{
            f = new File("D:\\Image\\image.jpg");
            img = ImageIO.read(f);
        } catch(IOExeption e){
            System.out.println(e);
        }

        int width = img.getWidth();
        int height = img.getHeight();
        for(int y = 0; y < height; y++){
            for(int x = 0; x < width; x++){
                int p = img.getRGB(x,y);
                int a = (p>>24)&0ff;
                int r = (p>>16)&0ff;
                int g = (p>>8)&0ff;
                int b = p&0ff;
                int avg = (r + g + b)/3;
                p = (a<<24) | (avg<<16) | (avg<<8) |  avg;
                img.setRGB(x, y, p);
            }
        }
        try{
            f = new File("D:\\Image\\output.jpg");
            ImageIO.write(img, "jpg", f);
        } catch(IOException e){
            System.out.println(e);
        }