c# - 在 PNG 中将 16 位灰度映射到 8 位

标签 c# png

我正在尝试用 C# 为灰度图像解码每 channel 16 位 (bpc) 的 PNG。我相信我正在解码正确的原始值,但是当我转换为 8bpc 以返回值时,我计算的值与 System.Drawing、Gimp 或 SixLabors.ImageSharp.

给定单个灰度像素的以下字节值:

byte b0 = data[index];
byte b1 = data[index + 1];

我尝试了以下映射:

byte result = b0;
byte result = (byte)(255 * (((b0 << 8) + b1)/ushort.MaxValue));
byte result = (byte)(((b0 << 8) + b1)/256.0);

但这些方法似乎都不符合其他软件为以下值预测的值:

b0   b1   expected
55   186  55
67   135  67
35   241  36

我确定我误解了将正常化回 8 bpc 值的正确方法。

有问题的图片是这样的:

A 16 by 16 pixel Grayscale image with 16 bpc

最佳答案

这里是官方转换位深度的方法:

https://www.w3.org/TR/2003/REC-PNG-20031110/#13Sample-depth-rescaling

output = floor((input * MAXOUTSAMPLE / MAXINSAMPLE) + 0.5)

where

MAXINSAMPLE = (2^sampledepth)-1
MAXOUTSAMPLE = (2^desired_sampledepth)-1

所以如果我以你的最后一个例子为例:

35 << 8 | 241 == 8960 | 241 == 9201
9201 * 255 / 65535 == 2346255 / 65535 == 35
floor(35 + 0.5) == 35

为什么不是36

There might gamma being involved .

结论:

首先检查您的内部实现是否正确遵循规范,然后进行相应调整。

https://www.w3.org/TR/2003/REC-PNG-20031110/

关于c# - 在 PNG 中将 16 位灰度映射到 8 位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55543203/

相关文章:

haskell - 创建单色 PNG 图像时堆栈溢出

svg - 将一堆图像从 svg 转换为 png

c# - .NET 中的 UDP 套接字客户端

C# 方法重载与接口(interface)参数

c# - 从密码短语派生公钥/ key 对

java - 将 JPanel 上绘制的图片保存在文件中 [java]

c# - 如何使用 C# 从 PNG 文件中获取字节

cocoa - 将 CVImageBufferRef 转换为 PNG

c# - Visual Studio 2010 Red 网友点评

c# - 如何将 COM 对象从 VBA 传递到 C++ DLL