【问题标题】:Write in 5-5-5 RGB and read in RGBA, BufferedImage写入 5-5-5 RGB 并读取 RGBA、BufferedImage
【发布时间】:2016-03-08 18:57:25
【问题描述】:

我想做什么可以很快解释。让我们考虑一个数字“x”。我使用 TYPE_USHORT_555_RGB 对图像进行操作。我使用 setRGB(x),保存图像。不幸的是,Java 要求我通过 getRGB 读取带有 TYPE_INT_ARGB 的结果图像。如何找到我的初始 x? 最让我担心的是,虽然通过 getRGB 读取的一些数字在它们之间是相等的,但这种等价模式在源代码中并未得到尊重,这就是我的意思:

阅读: -16777216 -16777216 -16777216 -16777183 -16777117 -16777101 -16777093 -16777101

来源: 00 00 00 20 66 74 79 70(十六进制)

位置 6 和 8 的数字在读取文件中相等,但在源中不同 (74 != 70)

//Write part:
BufferedImage img=new BufferedImage(8, 1, BufferedImage.TYPE_USHORT_555_RGB);
      for(int q=0;q<8;q++)
          img.setRGB(q,0,realVal[q]);//realVal contains the hex values
  File f= new File("randomfile.bmp");
  ImageIO.write(img, "bmp", f);

//Read part:
BufferedImage img;
        try{
        img=ImageIO.read(new File("randomfile.bmp"));
        for(int q=0;q<8;q++)
            System.out.println(img.getRGB(q,0));
        }catch(Exception e){}

【问题讨论】:

  • 你的十六进制值可能是红绿蓝;写下一些代码,看看你在做什么
  • 555_RGB 是一个非常复杂的模型,它几乎肯定会扭曲数值——如果你真的需要,你需要得到方程——为什么需要 555?你不能用普通的RGB吗?您希望对此图像进行什么样的处理 - 您不妨使用数组
  • 刚刚意识到您源中的十六进制值拼写为“ftyp”。你确定那是你的像素值吗?或者您是否在十六进制编辑器中查看 文件,期望文件的字节等于图像中的像素值???

标签: java image rgb bufferedimage


【解决方案1】:

BufferedImage.TYPE_USHORT_555_RGB 类型使用压缩的 15 位(或 16 位,但不使用第 16 位)表示像素,其中每个 R、G 和 B 样本使用 5 位。

另一方面,BufferedImage.getRGB(...) 方法是方便的方法,用于获取/设置单个或一组像素的颜色,并且始终在压缩的 32 位 ARGB 表示上运行,其中每个 A、R、G 和 B 样本使用 8 位(并且颜色模型始终为 sRGB),就像您所说的 TYPE_INT_ARGB。由于这种表示形式的差异,需要将 5 位样本“缩放”到 8 位(并返回)以进行检索/存储,这很慢并且可能会产生舍入/截断错误。

但是,如果您不喜欢,则无需使用此表示。相反,您可以直接通过Raster/DataBuffer 访问“ushort”(Java 没有无符号整数类型,因此它们存储为shorts):

DataBufferUShort dataBuffer = (DataBufferUShort) image.getRaster().getDataBuffer();
short[] data = dataBuffer.getData(); // Get the backing array

对支持数组的任何更改都将反映在图像中(这是一个“实时”视图)。此外,访问后备数组很可能会禁用硬件加速的任何机会,但这可能不是问题(它不在您发布的代码中,因为它只读取/写入图像,没有显示)。


也就是说,您应该考虑@gpasch 的评论,看看您是否可以只使用TYPE_INT_RGBTYPE_INT_ARGB 模型,因为它们通常更容易使用(尤其是如果您不喜欢小玩意)。

最后一个警告:并非所有文件格式都支持TYPE_USHORT_555_RGB 像素布局。 BMP 确实如此。

【讨论】:

  • 我可以使用的其他模型是 TYPE_BYTE_INDEXED 和 TYPE_BYTE_GRAY,我会尝试这些。
  • @Christian 重点不是避免使用TYPE_USHORT_555_RGB,而是TYPE_INT_RGBTYPE_INT_ARGB 是唯一可以依赖getRGB(...) 的方法返回的值与由setRGB(...) 设置。在这方面使用TYPE_BYTE_INDEXEDTYPE_BYTE_GRAY 无济于事。如果您说明为什么需要使用这些“特殊”类型,这可能有助于我们理解问题?
  • 原因很简单,我想了解为什么 JavaDoc 说 TYPE_BYTE_INDEXED 和 TYPE_BYTE_GRAY 是 1 字节编码的,但是当我尝试使用 q 从 0 到 255 进行 putRGB(q,0,q) ,然后我用油漆打开图像并读取 rgb,我注意到很多像素都是四舍五入的,因此从 0 到 20(例如)(如 int rgb)我得到相同的像素。这意味着那些编码不使用 1 个字节,但 Java 这么说,我很困惑。
  • @Christian 这些类型的 in-memory storage 是 1 个字节(正如 JavaDoc 所说)。 编码 取决于文件格式。 setRGB(...)/getRGB(...) 方法使用 32 位压缩 表示,但这并不是实际存储在任何地方的内容,这些值会为您转换,因为它是一种方便使用的格式。
  • 另外,来自BufferedImage.TYPE_BYTE_INDEXED JavaDoc:[w]当颜色数据存储在这种类型的图像中时,颜色图中最接近的颜色由IndexColorModel 和结果索引被存储。 可能会导致 alpha 或颜色分量的近似和丢失 [...](强调我的)。所以,这符合预期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-17
  • 2011-06-13
  • 2014-01-22
  • 2016-03-29
相关资源
最近更新 更多