在 Windows 上运行的一些 Java 代码中,我正在从磁盘读取一些大块 RGB 数据,并希望尽快将其显示到屏幕上。 RGB 数据为每通道 8 位,没有任何 Alpha。目前我有如下代码来创建 BufferedImage。
BufferedImage getBufferedImage(File file, int width, int height) {
byte[] rgbData = readRGBFromFile(file);
WritableRaster raster = Raster.createInterleavedRaster(
rgbData, width, height,
width * 3, // scanlineStride
3, // pixelStride
new int[]{0, 1, 2}, // bandOffsets
null);
ColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[]{8, 8, 8}, // bits
false, // hasAlpha
false, // isPreMultiplied
ComponentColorModel.OPAQUE,
DataBuffer.TYPE_BYTE);
return new BufferedImage(colorModel, raster, false, null);
}
问题在于将其渲染到屏幕的性能非常慢。大约 250 - 300 毫秒。我读过,为了获得最佳性能,您需要在与屏幕兼容的 BufferedImage 中显示。为此,我将从上述方法返回的缓冲图像传递给这样的方法。
BufferedImage createCompatibleImage(BufferedImage image)
{
GraphicsConfiguration gc = GraphicsEnvironment.
getLocalGraphicsEnvironment().
getDefaultScreenDevice().
getDefaultConfiguration();
BufferedImage newImage = gc.createCompatibleImage(
image.getWidth(),
image.getHeight(),
Transparency.TRANSLUCENT);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
该方法本质上是在 Windows 上将其从 RGB 转换为 ARGB,并且确实加快了显示速度,但对于 1600 x 1200 RGB 数据块,该方法大约需要 300 毫秒。所以现在我基本上已经将绘图问题的性能影响换成了转换问题。
300 毫秒大约与从磁盘加载 RGB 数据所需的时间相同。我想我可以做得更快。
有更好的方法可以进行转换吗?或者如果我事先修改 RGB 数据并添加 alpha 通道会有帮助吗?如果是这样,我的 Raster 和 ColorModel 会是什么样子。另外,由于我的 RGB 数据不包含透明度,我可以通过使用预乘 alpha 或其他东西来提高性能吗?
抱歉,我对 ColorModel、Raster 的东西有点迷失了。
谢谢!
In some Java code running on Windows, I'm reading some large blocks of RGB data from disk and want to display this to screen as quickly as possible. The RGB data is 8 bits per channel without any alpha. Currently I have code like the following to create the BufferedImage.
BufferedImage getBufferedImage(File file, int width, int height) {
byte[] rgbData = readRGBFromFile(file);
WritableRaster raster = Raster.createInterleavedRaster(
rgbData, width, height,
width * 3, // scanlineStride
3, // pixelStride
new int[]{0, 1, 2}, // bandOffsets
null);
ColorModel colorModel = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
new int[]{8, 8, 8}, // bits
false, // hasAlpha
false, // isPreMultiplied
ComponentColorModel.OPAQUE,
DataBuffer.TYPE_BYTE);
return new BufferedImage(colorModel, raster, false, null);
}
The problem is that the performance of rendering this to the screen is pretty slow. Around 250 - 300 ms. I've read that for the best performance you need to display in a BufferedImage that's compatible with the screen. To do that, I pass the buffered image returned from the above method to a method like this.
BufferedImage createCompatibleImage(BufferedImage image)
{
GraphicsConfiguration gc = GraphicsEnvironment.
getLocalGraphicsEnvironment().
getDefaultScreenDevice().
getDefaultConfiguration();
BufferedImage newImage = gc.createCompatibleImage(
image.getWidth(),
image.getHeight(),
Transparency.TRANSLUCENT);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
That method essentially converts it from RGB to ARGB on Windows and it really speeds up the displaying, but this method takes ~300 ms for a 1600 x 1200 RGB data block. So now I've basically traded the performance hit of the drawing problem to a converting problem.
300ms is about the same time as it takes to load the RGB data from disk. I would think I could do something faster.
Is there a better way I can do the conversion? Or would it help if I modified the RGB data and added an alpha channel myself beforehand? If so what would my Raster and ColorModel look like. Also, since my RGB data doesn't contain transparency can I get any performance improvements by using pre multiplied alpha or something?
Sorry, bit I'm a little lost on this ColorModel, Raster stuff.
Thanks!
发布评论
评论(2)
我意识到这是一个非常老的问题,我只是将这个问题发布给其他可能偶然发现这个问题并寻求更多选择的人。我最近遇到一个问题,我试图获取一个大的 (720p) RGB 字节 [] 并将其渲染为
BufferedImage
。我使用的原始实现看起来像这样(此处简化):即使进行了诸如创建 BufferedImage 和 ComponentSampleModel 一次并重用它们之类的优化,调用
BufferedImage
上的 >setData 仍然需要 50-60 毫秒的时间,这是不可接受的。我最终意识到,至少对于我的场景,您实际上可以直接写入 BufferedImage 的支持字节数组并绕过大部分中间处理(假设图像的支持元数据是已经正确了)。因此,我将代码更改为如下所示:
通过这样做,我的性能提高了约 20 倍。我现在可以在 3-5 毫秒内处理相同的帧,而不是 50-60 毫秒。
这可能并不适用于所有情况,但我想我会分享以防其他人发现它有用。
I realize this is a really old question, I'm just posting this for anybody else who might stumble upon this question looking for more options. I had an issue recently where I was attempting to take a large (720p) RGB byte[] and render it to a
BufferedImage
. The original implementation I was using looked something like this (simplified here):Even with optimizations like creating the
BufferedImage
andComponentSampleModel
once and reusing them, the final step of callingsetData
on theBufferedImage
was still taking on the order of 50-60 milliseconds, which is unacceptable.What I ended up realizing is that, at least for my scenario, you can actually write to the backing byte array of the
BufferedImage
directly and bypass most of the intermediate processing (assuming the backing metadata for the image is already correct). So I changed my code to look like this:Just by doing this, my performance improved by about a factor of 20. I now process the same frames in 3-5 milliseconds instead of 50-60 milliseconds.
This may not be applicable for all cases, but I thought I'd share in case someone else finds it useful.
经过尝试后,如果当前图形配置使用 ARGB 整数打包光栅,我有一个适用于 Windows 的不错的答案。
我所做的是首先创建兼容的 BufferedImage,然后手动将 RGB 字节数组转换为 ARGB int 数组。然后我从兼容的 BufferedImage 获取 Raster 并将我的 ARGB 整数写入其中。这要快得多。
我还有一个类,用于检查兼容的 BufferedImage 是否采用我期望的格式,如果不是,则默认采用较旧的较慢方法。
这是班级。希望对您有帮助。
After playing around with this I have a decent answer that works for Windows if the current graphics configuration is using ARGB integer packed rasters.
What I do is create the compatible BufferedImage first, then I manually convert my RGB bytes array to an ARGB int array. Then I get the Raster from the compatible BufferedImage and write my ARGB ints into it. This is much faster.
I also have a class that checks if the compatible BufferedImage is in the format I expect, if it isn't it defaults to the older slower approach.
Here is the class. Hope it helps you.