我一直在努力尝试使用PNGJ来执行等效代码。我不想使用ImageIO.read
和BufferedImage.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,填充=假]
答案 0 :(得分:4)
正如泽克的答案指出的那样,PNGJ与BufferedImage
不同:它更低级别,因为它不会尝试在抽象中表示图像像素一般格式(独立于具体的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)。