简体   繁体   中英

How to convert PNG image to grayscale using java?

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!

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 .

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);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM