PowerToys 颜色选择器浮动格式太精确(2位小数不够)

scyqe7ek  于 5个月前  发布在  其他
关注(0)|答案(1)|浏览(49)

Microsoft PowerToys版本
0.78.0

安装方法

WinGet

以管理员身份运行

存在问题的区域?

ColorPicker

重现问题的步骤

在颜色选择器中创建一个自定义的浮点颜色格式,例如:

如示例字符串所示,精度仅为2位小数。当将此值乘以255以返回字节值时,它应与字节颜色格式中显示的值相同。
假设您选择了这种红色:

如果您将浮点值乘以255,您将得到不同的颜色:
0.93 * 255 = 237.15 // 红色通道正确,但是...
0.16 * 255 = 40.8 // 如果四舍五入,蓝色通道是正确的,但如果向下取整,则是错误的!
0.22 * 255 = 56.1 // 绿色通道错误,无论您是否四舍五入或向下取整,都是错误的!

✔️ 预期行为

浮点颜色格式应该能够精确表示所有256种颜色通道。

❌ 实际行为

在许多情况下,所选颜色不能完全由当前浮点颜色格式的两位小数表示。
范围从0.00到1.00包含101个可能的值,而范围从0到255包含256个值。
无法将256个值唯一Map到仅101个值。
范围从0.000到1.000包含1001个值,因此可以进行精确Map。

s8vozzvw

s8vozzvw1#

我假设当前的实现是这样的:

var floatValue = Math.Round(byteValue * 100f / 255f) / 100f;

计算正确的浮点值并不是一件简单的事情(仅仅将上面的因子从100f更改为1000f是不够的)。仍然会有舍入误差。一种简单的实现方法是查找表。以下是一个查找表的示例实现,保留3位小数:

// Generate the lookup table
var lookupTable = new float[256];
var lastNewByteValue = -1;
for (int i = 0; i <= 1000; ++i)
{
	var value = i * 0.001f;
	var byteValue = (int)(value * 255f);
	if (byteValue != lastNewByteValue)
	{
		lookupTable[byteValue] = value;
		lastNewByteValue = byteValue;
	}
}

// Print the lookup table
for (int i = 0; i < 256; ++i)
{
	Console.WriteLine($"{i:000}=> {lookupTable[i]:0.000}");
}
Console.ReadKey(true);

在这个查找表中的浮点值可以安全地乘以255并向下取整,以获得颜色的确切字节值。代码基本上遍历所有1001个可能的浮点数,并将第一个可以安全向下取整的浮点数保存到查找表中。

相关问题