[对于文本墙的道歉,我不太确定问题是我对以大端顺序写入值的误解,将源值转换为字节,还是对文件格式的误解,所以我'我试图包含足够的背景信息,有人可以告诉我我的愚蠢。]
前段时间我编写了一些可以读写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颜色数据(加上第四个虚拟通道)之外,着色与这篇文章无关。
从这张图片看,这个问题很容易被发现。由于我转换了(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方案相关的问题,从而在其他地方引入其他错误。
我试过寻找答案,但想出一个空白。实际上,由于我对根本原因的不确定性,我几个月都没有发布这个问题,但如果有人知道的话,我想要一个答案。