我可以看到很多答案,并没有真正解决 OP 的三个问题。
1) 关于性能的一句话:除非您可以使用与您的显示适配器当前分辨率和颜色深度相匹配的精确像素字节顺序,否则字节数组可能效率不高。
要获得最佳的绘图性能,只需将您的图像转换为 BufferedImage,该图像的生成类型与您当前的图形配置相对应。请参阅https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html 上的 createCompatibleImage
这些图像在绘制几次后会自动缓存在显卡内存中,无需任何编程工作(这是自 Java 6 以来 Swing 中的标准),因此实际绘制所需的时间可以忽略不计 - 如果 你没有改变图像。
更改图像会带来主内存和 GPU 内存之间的额外内存传输 - 这很慢。因此,避免将图像“重绘”到 BufferedImage 中,尽量避免执行 getPixel 和 setPixel 。
例如,如果您正在开发一个游戏,而不是将所有游戏 actor 绘制到 BufferedImage 然后再绘制到 JPanel,将所有 actor 加载为较小的 BufferedImage 并在您的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 方法) - 然后将 this 添加到您的 GUI 组件布局中.
4)如何将数组转换为Bufferedimage
将您的字节数组转换为 PNG,然后加载它是非常耗费资源的。更好的方法是将现有的字节数组转换为 BufferedImage。
为此:不要使用 for 循环并复制像素。这是非常非常缓慢的。而是:
- 了解 BufferedImage 的首选字节结构(现在可以安全地假定 RGB 或 RGBA,即每像素 4 个字节)
- 了解正在使用的扫描线和扫描尺寸(例如,您可能有一个 142 像素宽的图像 - 但在现实生活中,它将存储为 256 像素宽的字节数组,因为它可以更快地处理它并通过以下方式屏蔽未使用的像素GPU 硬件)
- 那么一旦您根据这些原则构建了一个数组,BufferedImage 的 setRGB 数组方法就可以将您的数组复制到 BufferedImage。