使用没有BufferedImage的PNGJ读取PNG像素

时间:2015-11-17 09:18:48

标签: java image png bufferedimage javax.imageio

我一直在努力尝试使用PNGJ来执行等效代码。我不想使用ImageIO.readBufferedImage.getRGB。相反,我想纯粹使用PNGJ获得像素。下面的代码是我的ImageIO + BufferedImage版本。

BufferedImage bi = ImageIO.read( imageFile );
...
int[] pixels = new int[arrSize];
bi.getRGB( 0, 0, width, height, pixels, 0, width );

我想要像PNGJ的那样

lint = (ImageLineInt) reader.readRow();
scanLine = lint.getScanline();
...
???

以下是我的测试图像细节:
ImageInfo [cols = 1530,rows = 1980,bitDepth = 8,channels = 3,bitspPixel = 24,bytesPixel = 3,bytesPerRow = 4590,samplesPerRow = 4590,samplesPerRowP = 4590,alpha = false,greyscale = false,indexed = false,填充=假]

3 个答案:

答案 0 :(得分:4)

正如泽克的答案指出的那样,PNGJBufferedImage不同:它更低级别,因为它不会尝试在抽象中表示图像像素一般格式(独立于具体的PNG格式),而是以格式直接映射到PNG格式和颜色模型的值。

这意味着,例如,如果PNG图像是RGB,您将获得三个RGB分量作为连续(整数)值。如果PNG图像被编入索引,您将获得索引(指向调色板的整数值)。如果PNG图像是灰度,则您将灰度值作为单个整数。等

如果你想以更一般的方式处理像素值(给我RGB值,无论底层颜色模型如何),你可以自己进行转换,或者利用{{3}中的辅助方法} 类。具体来说,请查看方法convert2rgba()getPixelARGB8()

但请记住,这个类只是一堆辅助方法,可能对你有用 - 或者不是。很难有一个完全一般的RGB转换,因为有许多复杂性和启发式 - PNG允许几种透明模式,深度,色彩空间......(如果图像是2位深度怎么办?如果它&#39怎么办? ; s 16位?如果它有非标准的颜色配置文件或伽马校正,或者它有一个单一的透明块,或者......等等)?如果您想支持全套PNG图像,几乎需要了解基础格式和复杂性。

(但是...... BufferedImage这样做,完全具有普遍性,没有歧义,没有问题,你说?ImageLineHelper

如果您可以限制颜色模型(RGB,8位,没有alpha)(并且您没有透明度TRNS块或伽玛特性,或者不关心)那么它非常简单:

 for (int i = 0,j=0 ; i <  reader.imgInfo.cols; i++, j+=channels ) {
      int r = scanLine[j];
      int g = scanLine[j+1];
      int b = scanLine[j+2];
     // ...
 }

免责声明:我是PNGJ编码员。

答案 1 :(得分:2)

到目前为止,我发现了什么。 https://code.google.com/p/pngj/wiki/FAQ

  

如何读取/写入像素值?每个PngReader的readRow()调用   返回一个IImageLine,表示一个PNG图像行;混凝土   实现是可扩展的。但默认包括实施   (PngReader或PngReaderInt)返回ImageLineInt。这个课程包装   scaline(getScanline()),它是一个int []数组。每个元素   该数组对应于图像样本;所以,数组长度为(at   列x通道。

     

另一种格式是ImageLineByte,除了它之外是相同的   它将每个样本存储在一个字节中(优点:内存使用量减少,最佳   8bits图像的速度;缺点:图像失去分辨率   每通道16位,并且执行算术字节更麻烦   在Java中签名)。

     

扫描线内的样本值布局如下:

     

对于真彩色图像,RGB / RGBA样本按RGB(A)顺序:R G   B R G B ...(无alpha)或R G B A R G B A ...(带alpha);价值   未缩放:仅当bitdepth = 8时,它们才会在0-255范围内   (如果bitdepth = 16则为0-65535,如果bitdepth = 4则为0-15,等等)。对于索引图像,   每个样本值对应于我的调色板索引....对于   灰度G / GA图像是灰度值G G G ...(无alpha)或G A.   G A ......(带alpha)。

以下是我使用的代码,可以在以后提供给BufferedImage(使用Transparency.TRANSLUCENT):

PngReader reader = new PngReader( inputPNGFile );
arrSize = (int) reader.imgInfo.getTotalPixels();

width = reader.imgInfo.cols;
height = reader.imgInfo.rows;
channels = reader.imgInfo.channels;    

ImageLineInt lint;
while ( reader.hasMoreRows() ) {
    lint = (ImageLineInt) reader.readRow();
    scanLine = lint.getScanline();

    for ( i = 0; i < width; i++ ) {
        offset = i * channels;

        // Adjust the following code depending on your source image.
        // I need the to set the alpha channel to 0xFF000000 since my destination image
        // is TRANSLUCENT : BufferedImage bi = CONFIG.createCompatibleImage( width, height, Transparency.TRANSLUCENT );
        // my source was 3 channels RGB without transparency
        nextPixel = ( scanLine[offset] << 16 ) | ( scanLine[offset + 1] << 8 ) | ( scanLine[offset + 2] ) | 0xFF000000;

        // I'm placing the pixels on a memory mapped file
        mem.putInt( nextPixel ); 
     }

}

答案 2 :(得分:0)

您可以使用BufferedImage完全使用像素。获取RGB是访问像素值的最慢方式之一。你想要的是访问DataBuffer。

document.pdf

您只需要注意图像编码(Byte,Int或Short)。