在Java中以自下而上的顺序存储图像像素的最佳方法
-
20-09-2019 - |
题
我有一个字节数组,表示 Windows BMP 格式的图像,我希望我的库将其作为 Java 应用程序呈现 BufferedImage
, 没有 复制像素数据。
主要问题是所有的实现 Raster
在 JDK 中,图像像素以自上而下、从左到右的顺序存储,而 BMP 像素数据则以自下而上、从左到右的顺序存储。如果不对此进行补偿,则生成的图像将垂直翻转。
最明显的“解决方案”是设置 SampleModel
的 scanlineStride
属性设置为负值并更改带偏移(或 DataBuffer
的数组偏移量)指向左上角像素,即数组中最后一行的第一个像素。不幸的是这不起作用,因为所有的 SampleModel
如果给定负数,构造函数会抛出异常 scanlineStride
争论。
我目前正在通过强制解决这个问题 scanlineStride
使用反射将字段设置为负值,但如果可能的话,我想以更干净、更便携的方式来实现。例如还有其他方法可以愚弄 Raster
或者 SampleModel
按自下而上的顺序排列像素但不破坏封装?或者是否有一个图书馆可以包装 Raster
和 SampleModel
, ,以相反的顺序呈现像素行?
我宁愿避免以下方法:
- 复制整个图像(出于性能原因。该代码必须每秒处理数百个大型(>= 1Mpixels)图像,尽管整个图像必须可供应用程序使用,但它通常只会访问图像的一小部分(但难以预测)。)
- 修改
DataBuffer
执行坐标转换(这实际上有效,但这是另一个“脏”解决方案,因为缓冲区不需要知道扫描线/像素布局。) - 重新实施
Raster
和/或SampleModel
从头开始接口(由于兼容性检查的实现方式(至少在 Sun JDK 中),需要特定的子类SampleModel
所以一个通用的BottomUpSampleModel
包装类将不起作用。)
解决方案
我发现我可以只使用一个新类来实现这一点,我将其命名为 BottomUpComponentSampleModel
. 。它延伸 ComponentSampleModel
并否定了 scanlineStride
场(幸运的是,是 protected
而不是 private
) 在调用超类构造函数之后。所有像素地址计算工作正常,尽管验证在 Raster.createWritableRaster
不会(如果你给它的数组太小,它可能无法检测到),但这不是一个严重的问题。
这不是必需的 MultiPixelPackedSampleModel
或者 SinglePixelPackedSampleModel
, ,因为他们确实接受负面的 scanlineStride
. 。它们没有频带偏移,但这可以通过在频带上设置偏移来解决 DataBuffer
.
其他提示
当访问图像的微小(但难以预测)部分时,让应用程序(或访问层)对其副本进行转换和翻转工作怎么样?
更好的是,听起来应用程序不需要实际显示图像?为什么要费心去翻转它,以便它在屏幕上看起来是正确的呢?只需编写逻辑即可在您拥有的版本上工作?也不需要这样的 BufferedImage,直接在数组上工作。