使用big-endian写入uint16,其中该对的最低有效字节为零

时间:2016-06-02 16:19:58

标签: c# endianness

[对于文本墙的道歉,我不太确定问题是我对以大端顺序写入值的误解,将源值转换为字节,还是对文件格式的误解,所以我'我试图包含足够的背景信息,有人可以告诉我我的愚蠢。]

前段时间我编写了一些可以读写Adobe Photoshop Color Swatch文件的代码(*.aco)。我编写了代码,我使用单元测试对其进行了测试,并通过在旧版本的Photoshop中实际打开生成的样本文件的简单方法,一切看起来都很好。

在ACO文件中(仅出于此问题的目的粘贴RGB颜色空间),每个颜色通道为uint16,使用0-65535的全范围作为值,并写入文件中大端订单。在我的代码的原始版本中,我使用的是System.Drawing.Color,当然只有0-255的范围,所以我会多次并且在适当的时候除以256.

这是我如何将值写入文件

的示例
private void WriteInt16(Stream stream, short value)
{
  stream.WriteByte((byte)(value >> 8));
  stream.WriteByte((byte)(value >> 0));
}

我将int16分成两个字节,并使用big-endian顺序编写它们。我想的很简单。

代码处于生产使用状态后,我收到错误报告,开始支持aco文件的第三方应用程序正在读取由我的代码创建的调色板为纯黑色。我仍然发现Photoshop本身对这些文件非常满意,但我确实找到了一个将它们变成黑色的第三方应用程序。所以问题肯定存在。

下面的屏幕截图来自一个诊断工具,我最终写到试图弄清楚发生了什么。 (我已经尝试了一下屏幕截图,试图让它适合这个狭窄的宽度,但它应该显示出足够的细节)

左侧的块是原始的aco文件。在使用我的代码重新保存后,右侧的块是同一个文件。除了苍白的鲑鱼是RGB颜色数据(加上第四个虚拟通道)之外,着色与这篇文章无关。

enter image description here

从这张图片看,这个问题很容易被发现。由于我转换了(byte)* 256,这意味着一个字节总是为零,当写出为零时,似乎现有的每个其他第三方应用程序都读错了文件,除了Photoshop中。

较新版本的代码如下所示

public static void WriteBigEndian(this Stream stream, ushort value)
{
  byte[] buffer;

  buffer = new byte[2];

  buffer[0] = (byte)(value >> 8);
  buffer[1] = (byte)value;

  if (buffer[1] == 0 && buffer[0] != 0)
  {
    buffer[1] = buffer[0];
  }

  stream.Write(buffer, 0, 2);
}

我“修复”改变0字节以匹配非零字节的问题。我还存储并使用原始uint16值,以避免因将它们转换为字节而返回精度而失去精确度,但这不是重点。

我的问题(最后)是为什么这样做。我不明白我偶然发现的修复(这是我第一次使用big-endian订购)。 uint16的big-endian顺序是否不支持非零字节后跟零字节,我是否误解了如何将uint16分解为其组件字节,我是否误解了{{3}或者只是所有这些程序读错文件的情况(这似乎有点不太可能!)。或者,我是否首先错误地诊断了问题?

我在其他地方使用了相同的转换/序列化代码,并担心我正在传播修复程序,以解决可能只与原始ACO方案相关的问题,从而在其他地方引入其他错误。

我试过寻找答案,但想出一个空白。实际上,由于我对根本原因的不确定性,我几个月都没有发布这个问题,但如果有人知道的话,我想要一个答案。

0 个答案:

没有答案