读取灰度PNG图像文件而不会变形 [英] Reading Grayscale PNG image files without distortion

查看:122
本文介绍了读取灰度PNG图像文件而不会变形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要读取和处理大量的灰度PNG文件。我的意思是,如果它们是在Photoshop或GIMP中打开的,则图像模式是灰度-而不是具有灰度值的RGB图像。



ImageIO似乎无法实现这个。似乎将所有图像文件都视为sRGB。这会破坏灰度值。我需要读取和处理这些PNG文件,其中(在我的代码中)每个像素具有与在Photoshop或GIMP中打开灰度文件完全相同的值。请问有人知道可以实现此目的的一些开源软件吗?或更佳的方法是使用ImageIO实现此目的。



其他信息:



我在a上使用getRGB() BufferedImage。图像文件中的基础像素为0x86。我知道这不一定与包含0xFF868686的ARGB像素相对应,因为这取决于亮度/伽玛。但是,在没有带有伽玛类型参数的吸气剂的情况下,我希望默认映射为ARGB = 0xFF868686。如果我使用GIMP或Photoshop将包含值为0x86的像素的灰度图像转换为RGB,则该像素变为0xFF868686。这是显而易见的默认设置。



但是,ImageIO似乎对灰度图像文件使用了奇怪的伽玛(无论您是否喜欢),这使得灰度像素非常非常映射到ARGB后发出的光。在这种情况下,0x86映射到0xFFC0C0C0。这不仅非常轻,而且还可以导致大量数据丢失,因为许多灰度值可以映射到更少的ARGB值。这种失真不会导致数据丢失的唯一时间是针对非常暗的灰度图像。适当的Gamma取决于上下文,不同的物理媒体将不同地扭曲亮度。但是,在没有上下文的情况下,映射是最有意义的:0x86-> 0xFF868686-见证为GIMP和Photoshop所做的选择。



保留getRGB()一方面,已经加载了灰度图像(使用ImageIO.read(imageFile)),然后BufferedImage的getType()方法返回Type = 0(自定义)而不是Type = 10(TYPE_BYTE_GRAY),就像我期望的那样。简而言之,ImageIO似乎没有提供一种很好的,简单的高级方式来读取和操作现有的灰度图像。我本来希望不必在光栅,ICC,采样等的幕后打乱。我也不希望必须将所有灰度图像文件都物理转换为RGB。我只想要一个用于BufferedImage的API load()方法,就像在GIMP或Photoshop中打开文件一样工作。我无法实现这一目标。我希望这是我的无知,而不是Java ImageIO的限制。



可能的解决方案:



之后挖掘一下,我提供以下作为访问底层灰度值的可能技术:

 最终文件imageFile = new File(  test.png); 
final BufferedImage image = ImageIO.read(imageFile);
// ---确认图像的ColorSpace Type为GREY并且PixelSize == 16
final Raster raster = image.getData();
// ---确认:raster.getTransferType()== DataBuffer.TYPE_BYTE

for(int x = 0,xLimit = image.getWidth(); x< xLimit; x ++){
for(int y = 0,yLimit = image.getHeight(); y< yLimit; y ++){

最终对象dataObject = raster.getDataElements(x,y,空值 );
// ---确认dataObject是byte []的实例
最后一个byte [] pixelData =(byte [])dataObject;
// ---确认:pixelData.length == 2

final int grayscalePixelValue = pixelData [0]& 0xFF;
final int grayscalePixelAlpha = pixelData [1]& 0xFF;

// ---使用灰度像素数据
}
}

javadoc不好,所以我不能保证这是正确的,但是它似乎对我有用。

解决方案

如果您想尝试第三方(我的)lib: https:// github .com / leonbloy / pngj /



如果您确定图像是纯灰度(8位,无alpha,无调色板,无配置文件),这很简单:

  PngReaderByte pngr = new PngReaderByte(new File(filename)); // 
if(pngr.imgInfo.channels!= 1 || pngr.imgInfo.bitDepth!= 8 || pngr.imgInfo.indexed)
抛出new RuntimeException(此方法用于灰色图像 );
for(int row = 0; row< pngr.imgInfo.rows; row ++){
ImageLineByte line = pngr.readRowByte();
字节[] buf = line.getScanlineByte();
//做你想做的事
}
pngr.end();


I need to read and process a large number of PNG files that are grayscale. By that I mean that if they are opened in either Photoshop or GIMP, the image mode is Grayscale - not an RGB image with grayscale values.

ImageIO does not seem to achieve this. It appears to treat all image files as sRGB. This mangles grayscale values. I need to read and process these PNG files where (in my code) each pixel has exactly the same value as if I had opened the grayscale file in Photoshop or GIMP. Does anybody know of some open source software that can achieve this, please? Or better how to achieve this using ImageIO.

Additional Information:

I am using getRGB() on a BufferedImage. The underlying pixel in the image file is 0x86. I understand that this does not necessarily correspond to an ARGB pixel containing 0xFF868686, as this depends upon luminance/gamma. However, in the absence of a getter with a gamma type argument, I would have expected the default mapping to be to ARGB=0xFF868686. If I use GIMP or Photoshop to convert a grayscale image containing a pixel with the value of 0x86 to RGB then the pixel becomes 0xFF868686. This is the obvious default.

However, ImageIO seems to use a weird gamma (whether you like it or not) with grayscale image files that makes the grayscale pixels very, very light after mapping to ARGB. In this case, 0x86 maps to 0xFFC0C0C0. This is not only very light, it can also result in considerable data loss as many grayscale values can be mapped to fewer ARGB values. The only time that this distortion will not result in data loss is for very dark grayscale images. An appropriate Gamma is context dependent, different physical media will distort luminance differently. However, in the absence of a context, the mapping: 0x86 --> 0xFF868686 makes most sense - witness the choices made for GIMP and Photoshop.

Leaving the getRGB() issue to one side, having loaded the grayscale image (using ImageIO.read( imageFile )), the getType() method of BufferedImage returns Type=0 (Custom) and not Type=10 (TYPE_BYTE_GRAY) as I would have expected.

In short, ImageIO does not seem to provide a nice and simple high level way of reading and manipulating existing grayscale images. I had hoped not to have to mess around under the covers with Rasters, ICC, sampling etc. Nor do I want to have to physically convert all the grayscale image files to RGB. All I wanted was an API load() method for BufferedImage that works just like open file does in GIMP or Photoshop. I have not been able to achieve this. I am hoping that this is my ignorance and not a limitation of Java ImageIO.

Possible Solution:

After digging around I have the following to offer as a possible technique for accessing the underlying grayscale values:

final File imageFile = new File( "test.png" );
final BufferedImage image = ImageIO.read( imageFile );
// --- Confirm that image has ColorSpace Type is GRAY and PixelSize==16
final Raster raster = image.getData();
// --- Confirm that: raster.getTransferType() == DataBuffer.TYPE_BYTE

for( int x=0, xLimit=image.getWidth(); x < xLimit; x++ ) {
    for( int y=0, yLimit=image.getHeight(); y < yLimit; y++ ) {

        final Object dataObject = raster.getDataElements( x, y, null );
        // --- Confirm that dataObject is instance of byte[]
        final byte[] pixelData = (byte[]) dataObject;
        // --- Confirm that: pixelData.length == 2

        final int grayscalePixelValue = pixelData[0] & 0xFF;
        final int grayscalePixelAlpha = pixelData[1] & 0xFF;

        // --- Do something with the grayscale pixel data
    }
}

The javadoc is not great, so I cannot guarantee that this is correct, but it seems to work for me.

解决方案

In case you want to try a third party (mine) lib: https://github.com/leonbloy/pngj/

If you are certain that the image is plain grayscale (8 bits, no alpha, no palette, no profile), it's quite simple:

    PngReaderByte pngr = new PngReaderByte(new File(filename)); // 
    if (pngr.imgInfo.channels!=1 || pngr.imgInfo.bitDepth != 8 || pngr.imgInfo.indexed)
        throw new RuntimeException("This method is for gray images");
    for (int row = 0; row < pngr.imgInfo.rows; row++) { 
        ImageLineByte line = pngr.readRowByte();
        byte [] buf = line.getScanlineByte();
        // do what you want
    }
    pngr.end(); 

这篇关于读取灰度PNG图像文件而不会变形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆