我可以看到很多答案,但并没有真正解决OP的三个问题。
1)关于性能的一个词:字节数组可能是低效的,除非你可以使用与显示适配器当前分辨率和颜色深度匹配的精确像素字节排序。
要获得最佳的绘图性能,只需将图像转换为BufferedImage,该BufferedImage生成的类型与当前图形配置相对应。参见https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html上的createCompatibleImage
在绘制几次之后,这些图像将自动缓存到显卡内存中,而不需要任何编程工作(这是Java 6以来Swing中的标准),因此实际绘制所花费的时间可以忽略不计——如果您没有更改图像的话。
改变图像将带来主存和GPU内存之间的额外内存传输,这是缓慢的。避免将图像“重绘”到BufferedImage中,因此,避免使用getPixel和setPixel。
例如,如果你正在开发一个游戏,而不是将所有的游戏角色绘制到一个BufferedImage,然后再绘制到一个JPanel,它会更快地将所有的角色加载为更小的BufferedImage,并在你的JPanel代码中一个一个地在它们适当的位置绘制它们——这样在主存和GPU内存之间就没有额外的数据传输,除了用于缓存的图像的初始传输。
ImageIcon将在底层使用BufferedImage -但基本上分配一个具有适当图形模式的BufferedImage是关键,并且没有努力做到这一点。
2)通常的方法是在JPanel的一个重写的paintComponent方法中绘制一个BufferedImage。虽然Java支持大量额外的功能,比如控制GPU内存中缓存的volatile image的缓冲链,但是没有必要使用这些功能,因为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。
为此:不要使用For循环和复制像素。这是非常非常慢的。而不是:
learn the preferred byte structure of the BufferedImage (nowadays it is safe to assume RGB or RGBA, which is 4 bytes per pixel)
learn the scanline and scansize in use (e.g. you might have a 142 pixels wide image - but in the real life that will be stored as a 256 pixel wide byte array since it is faster to process that and mask the unused pixes by the GPU hardware)
then once you have an array build according to these principles, the setRGB array method of the BufferedImage can copy your array to the BufferedImage.