简体   繁体   English

如何使用java将PNG图像转换为灰度?

[英]How to convert PNG image to grayscale using java?

I have a problem with regards to changing my PNG image to grayscale.我在将 PNG 图像更改为灰度时遇到问题。 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.我想制作一种方法,它可以接受 byte[] 图像作为参数,并作为新修改的灰度图像作为 byte[] 返回。

I found some links that make images grayscale with JPEG images using below snippet.我发现了一些使用以下代码段使图像灰度与 JPEG 图像的链接。

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?我的参考资料如下: 如何将 ImageJ 用作单独的 Java 应用程序的库? https://www.mkyong.com/java/how-to-convert-byte-to-bufferedimage-in-java/ 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.它适用于 JPEG 图像,但在 PNG 上,它向我发送了一个透明图像。

// 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?我想知道上述方法是否适用于 PNG 格式?

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.实际上, getRGBsetRGB方法尽管名称不同,但实际上返回并接受 32 位打包 ARGB 格式的像素。 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...这意味着,如果您的BufferedImage的颜色模型实际上包含一个 alpha 通道,那么将像素的 alpha 值保留为空( 0x00 ),将导致全透明图像...

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. PNG 格式支持 alpha,而 JPEG 通常不使用它,这就是为什么你会看到你所做的结果,以及为什么它似乎对不同的格式工作不同。

The fix is simple though, just prepend the pixel value with all opaque alpha:修复很简单,只需在像素值前面加上所有不透明的 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):如果你想保留原始的 alpha,你也可以这样做(我稍微简化了代码):

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. PS:请注意,您通过平均计算灰度值的方法不是将 RGB 转换为灰度的推荐方法,因此与其他工具相比,您的图像可能看起来不太好。 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);
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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