我看到了很多答案,但并没有真正解决OP的三个问题。
1)关于性能的一个字眼:字节阵列可能效率不高,除非您可以使用与显示适配器当前分辨率和颜色深度相匹配的精确像素字节顺序。
为了获得最佳的绘图性能,只需将图像转换为BufferedImage即可,该BufferedImage的生成类型与您当前的图形配置相对应。请参阅https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html上的 createCompatibleImage
绘制几次后,这些图像将自动缓存在显示卡的内存中,而无需进行任何编程工作(这是Java 6之后在Swing中的标准操作),因此,实际的绘制将花费很少的时间- 如果您不更改图像。
更改图像会在主内存和GPU内存之间进行额外的内存传输-这很慢。避免将图像“重绘”到BufferedImage中,因此,绝对不要执行getPixel和setPixel。
例如,如果您正在开发游戏,而不是将所有游戏角色都先绘制到BufferedImage然后再绘制到JPanel,则将所有角色加载为较小的BufferedImages并在JPanel代码中逐个绘制它们的速度要快得多。它们的正确位置-这样,除了用于缓存的图像的初始传输外,在主内存和GPU内存之间没有其他数据传输。
ImageIcon将在幕后使用BufferedImage-但是从根本上分配具有适当图形模式的BufferedImage 是关键,并且无需为此做任何努力。
2)这样做的通常方法是在JPanel的重写paintComponent方法中绘制BufferedImage。尽管Java支持大量其他功能,例如控制在GPU内存中缓存的VolatileImages的缓冲区链,但由于Java 6在不暴露所有GPU加速细节的情况下表现出色,因此无需使用其中的任何功能。
请注意,GPU加速可能不适用于某些操作,例如拉伸半透明图像。
3)不要添加。只需如上所述将其绘制:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
如果图像是布局的一部分,则“添加”才有意义。如果需要将其用作填充JPanel的背景图像或前景图像,则只需绘制paintComponent。如果你喜欢酝酿一个通用的Swing组件,可以显示您的图片,那么它是同样的故事(你可以使用一个JComponent并覆盖其的paintComponent方法) -然后添加这个到您的GUI组件的布局。
4)如何将数组转换为Bufferedimage
将字节数组转换为PNG,然后加载它会占用大量资源。更好的方法是将现有的字节数组转换为BufferedImage。
为此:请勿用于循环和复制像素。那非常非常慢。代替:
- 了解BufferedImage的首选字节结构(现在可以安全地假设RGB或RGBA,每个像素4个字节)
- 了解使用中的扫描线和scansize(例如,您可能具有142像素宽的图像-但在现实生活中将以256像素宽的字节数组存储,因为这样可以更快地处理该图像并通过GPU硬件掩盖未使用的像素)
- 然后,一旦根据这些原理构建了数组,则BufferedImage的setRGB array方法可以将您的数组复制到BufferedImage中。
MemoryImageSource
比将它们转换为JPEG或PNG格式然后以ImageIO
大多数答案所建议的方式读取更为有效。您可以使用来Image
从MemoryImageSource
包含您的图像数据的结构中获取createImage
,并按照答案之一的建议进行显示。