How to set RGB pixel in a BufferedImage to display a 16-bit-depth PNG?(如何在BufferedImage中设置RGB像素以显示16位深度的PNG?)
问题描述
我正在尝试读取并显示PNG文件。 我可以轻松处理8位深度的图像。 我按如下方式进行:
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
然后我读取每个像素的3*8=24位,将它们保存在一个字节数组data中,并使用:
for (int y = 0; y < height; y++)
   for (int x = 0; x < width; x++)
     result.setRGB(x, y, ((data[x * 3 + 0] & 0xff) << 16)
                       + ((data[x * 3 + 1] & 0xff) << 8)
                       + ((data[x * 3 + 2] & 0xff)));
现在问题出在16位深度图像上。当然,data现在更大了,它包含48位,分为6个字节,每个RGB三元组:来自调试器的data具有我期望的值。
如何设置RGB像素?我必须更改BufferedImage声明吗?可以使用:
BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_565_RGB);
提前表示感谢!
附注:按照PNG标准,图像的颜色类型为2(不含Alpha的RGB)。也许我将不得不使用http://docs.oracle.com/javase/7/docs/api/java/awt/image/ColorModel.html
推荐答案
@haraldK指向了正确的方向。我提供了一些来自"icafe"Java图像库的PNGReader的工作代码。
if(bitsPerPixel == 16) {
    if(interlace_method==NON_INTERLACED)
       spixels = generate16BitRGBPixels(compr_data, false);
    else {
       spixels = generate16BitRGBInterlacedPixels(compr_data, false);
               }
    int[] off = {0, 1, 2}; //band offset, we have 3 bands
    int numOfBands = 3;
    boolean hasAlpha = false;
    int trans = Transparency.OPAQUE;
    int[] nBits = {16, 16, 16}; 
    if(alpha != null) { // Deal with single color transparency
       off = new int[] {0, 1, 2, 3}; //band offset, we have 4 bands
       numOfBands = 4;
       hasAlpha = true;
       trans = Transparency.TRANSLUCENT;
       nBits = new int[] {16, 16, 16, 16};                      
    }
    db = new DataBufferUShort(spixels, spixels.length);
    raster = Raster.createInterleavedRaster(db, width, height, width*numOfBands, numOfBands, off, null);
    cm = new ComponentColorModel(colorSpace, nBits, hasAlpha, false, trans, DataBuffer.TYPE_USHORT);
}
return new BufferedImage(cm, raster, false, null);
以下是Generate16BitRGBPixels()方法:
private short[] generate16BitRGBPixels(byte[] compr_data, boolean fullAlpha) throws Exception {
     //
     int bytesPerPixel = 0;
     byte[] pixBytes;
     if (fullAlpha)
         bytesPerPixel = 8;
     else 
         bytesPerPixel = 6;
     bytesPerScanLine = width*bytesPerPixel;         
     // Now inflate the data.
     pixBytes = new byte[height * bytesPerScanLine];
     // Wrap an InflaterInputStream with a bufferedInputStream to speed up reading
     BufferedInputStream bis = new BufferedInputStream(new InflaterInputStream(new ByteArrayInputStream(compr_data)));
     apply_defilter(bis, pixBytes, height, bytesPerPixel, bytesPerScanLine);
     short[] spixels = null;
     if(alpha != null) { // Deal with single color transparency
         spixels = new short[width*height*4];
         short redMask = (short)((alpha[1]&0xff)|(alpha[0]&0xff)<<8);
         short greenMask = (short)((alpha[3]&0xff)|(alpha[2]&0xff)<<8);;
         short blueMask = (short)((alpha[5]&0xff)|(alpha[4]&0xff)<<8);
         for(int i = 0, index = 0; i < pixBytes.length; index += 4) {
             short red = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff));
             short green = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff));
             short blue = (short)((pixBytes[i++]&0xff)<<8|(pixBytes[i++]&0xff));
             spixels[index] = red;
             spixels[index + 1] = green;
             spixels[index + 2] = blue;
             if(spixels[index] == redMask && spixels[index + 1] == greenMask && spixels[index + 2] == blueMask) {
                 spixels[index + 3] = (short)0x0000;                               
             } else {
                 spixels[index + 3] = (short)0xffff;
             }
         }
     } else
         spixels = ArrayUtils.toShortArray(pixBytes, true);
     return spixels;         
 }
和ArrayUtils.toShortArray()方法:
public static short[] toShortArray(byte[] data, int offset, int len, boolean bigEndian) {
    ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, len);
    if (bigEndian) {
        byteBuffer.order(ByteOrder.BIG_ENDIAN);
    } else {
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
    }
    ShortBuffer shortBuf = byteBuffer.asShortBuffer();
    short[] array = new short[shortBuf.remaining()];
    shortBuf.get(array);
    return array;
}
                        这篇关于如何在BufferedImage中设置RGB像素以显示16位深度的PNG?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在BufferedImage中设置RGB像素以显示16位深度的PNG?
				
        
 
            
        基础教程推荐
- 不推荐使用 Api 注释的描述 2022-01-01
 - 验证是否调用了所有 getter 方法 2022-01-01
 - Java Swing计时器未清除 2022-01-01
 - Java 实例变量在两个语句中声明和初始化 2022-01-01
 - 如何在 Spring @Value 注解中正确指定默认值? 2022-01-01
 - 大摇大摆的枚举 2022-01-01
 - 多个组件的复杂布局 2022-01-01
 - 在 Java 中创建日期的正确方法是什么? 2022-01-01
 - 如何在 JFrame 中覆盖 windowsClosing 事件 2022-01-01
 - 从 python 访问 JVM 2022-01-01
 
    	
    	
    	
    	
    	
    	
    	
    	
						
						
						
						
						
				
				
				
				