我可以看到很多答案,并没有真正解决 OP 的三个问题。
1)关于性能的一句话:除非您可以使用与您的显示适配器当前分辨率和颜色深度相匹配的精确像素字节顺序,否则字节数组可能效率不高。
To achieve the best drawing performance, simply convert your image to a BufferedImage which is generated with a type corresponding to your current graphics configuration. See createCompatibleImage at https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
These images will be automatically cached on the display card memory after drawing a few times without any programming effort (this is standard in Swing since Java 6), and therefore the actual drawing will take negligible amount of time - if you did not change the image.
Altering the image will come with an additional memory transfer between main memory and GPU memory - which is slow. Avoid "redrawing" the image into a BufferedImage therefore, avoid doing getPixel and setPixel at all means.
例如,如果您正在开发一个游戏,而不是将所有游戏 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 方法) - 然后将其添加到您的 GUI 组件布局中。
4)如何将数组转换为 Bufferedimage
将字节数组转换为 PNG,然后加载它是非常耗费资源的。更好的方法是将现有的字节数组转换为 BufferedImage。
为此:不要使用 for 循环和复制像素。这是非常非常缓慢的。反而:
- 学习 BufferedImage 的首选字节结构(现在可以安全地假设 RGB 或 RGBA,即每个像素 4 个字节)
- 学习使用中的扫描线和扫描大小(例如,您可能有一个 142 像素宽的图像 - 但在现实生活中,它将存储为 256 像素宽的字节数组,因为它可以更快地处理它并通过 GPU 硬件屏蔽未使用的像素)
- 那么一旦你根据这些原则构建了一个数组,BufferedImage 的 setRGB 数组方法就可以将你的数组复制到 BufferedImage 中。