正确使用SetDeviceGammaRamp

Dam*_*mon 8 winapi gamma

我想在应用程序启动时添加调整屏幕gamma的功能,并在退出时重置它.虽然人们是否应该篡改伽玛是有争议的(个人我发现它毫无用处和有害),但是嘿,有些人希望能够做那种事情.

这只是一个简单的API调用,所以这很容易,对吧?

MSDN说:"伽马斜坡在三个256个WORD元素阵列中指定,每个值必须存储在每个WORD的最高有效位中,以增加DAC的独立性." .在我的理解中,这意味着,word_value = byte_value<<8听起来很奇怪,但这就是我读它的方式.

Doom3源代码包含一个函数,它接受三个char值数组并将它们转换为一个uint16_t值数组,这些值在上半部分和下半部分具有相同的字节值.换句话说就像word_value = (byte_value<<8)|byte_value.这同样很奇怪,但更糟糕的是它与上面的不一样.

互联网上还有一些代码片段在各种爱好程序员网站上(显然是一个从另一个被盗,因为它们与字母相同),这些代码片段做了一些模糊的数学运算,将线性指数乘以一个值,偏差为128,并且夹到65535.我不太确定这是什么,但对我来说这看起来完全是胡说八道,而且它与上述两者中的任何一个都不一样.

是什么赋予了?必须明确定义 - 不要猜测 - 您提供的数据必须如何?最后,人们会做的是读取原始值并让用户无论如何调整一些滑块(并且可选地使用用户的配置将该blob保存到磁盘),但仍然......为了修改这些值,需要知道他们是什么,期待什么.

有人做过(并经过测试!)之前知道哪一个是对的吗?

Ric*_*ers 7

在研究以编程方式更改屏幕亮度的能力时,我遇到了这篇文章,通过编程方式更改屏幕亮度 - 使用Gama Ramp API.

使用调试器,我看了一下GetDeviceGamaRamp()函数提供的值.输出是一个二维数组,定义为类似的WORD GammaArray[3][256];,是一个256个值的表,用于修改显示像素的红色,绿色和蓝色值.我看到的值在索引0处以值零(0)开始,并且添加值256以计算下一个值.因此,对于索引0,1,2,...,254,255,序列是0,256,512,...,65024,65280.

我的理解是这些值用于修改每个像素的RGB值.通过修改表值,您可以修改显示亮度.然而,该技术的有效性可能根据显示硬件而变化.

您可能会发现这篇简短的文章Gamma Controls,因为它描述了从Direct3D角度来看伽马斜率水平.关于Gamma Ramp Levels的文章有这个说法.

在Direct3D中,术语伽马斜坡描述了一组值,它们将帧缓冲区中所有像素的特定颜色分量(红色,绿色,蓝色)的电平映射到DAC接收的新电平以进行显示.通过三个查找表执行重新映射,每个查找表用于每个颜色分量.

以下是它的工作原理:Direct3D从帧缓冲区中获取一个像素,并评估其各自的红色,绿色和蓝色分量.每个组件由0到65535之间的值表示.Direct3D获取原始值并使用它来索引256个元素的数组(渐变),其中每个元素包含一个替换原始数组的值.Direct3D对帧缓冲区中每个像素的每个颜色分量执行此查找和替换处理,从而更改所有屏幕像素的最终颜色.

根据对在线文档GetDeviceGamaRamp()SetDeviceGamaRamp()这些功能在Windows API都支持在Windows 2000 Professional开始.

我使用他们的源缩小到以下示例插入到Windows应用程序中,以使用引用文章中的值来测试效果.我的测试是使用Windows 7和AMD Radeon HD 7450图形适配器完成的.

通过此测试,我的两个显示器都受到了影响.

//Generate the 256-colors array for the specified wBrightness value.
WORD  GammaArray[3][256];
HDC   hGammaDC = ::GetDC(NULL);
WORD  wBrightness;

::GetDeviceGammaRamp (hGammaDC, GammaArray);

wBrightness = 64;     // reduce the brightness
for (int ik = 0; ik < 256; ik++) {
    int iArrayValue = ik * (wBrightness + 128);
    if (iArrayValue > 0xffff) iArrayValue = 0xffff;
    GammaArray[0][ik] = (WORD)iArrayValue;
    GammaArray[1][ik] = (WORD)iArrayValue;
    GammaArray[2][ik] = (WORD)iArrayValue;
}

::SetDeviceGammaRamp (hGammaDC, GammaArray);
Sleep (3000);

wBrightness = 128;    // set the brightness back to normal
for (int ik = 0; ik < 256; ik++) {
    int iArrayValue = ik * (wBrightness + 128);
    if (iArrayValue > 0xffff) iArrayValue = 0xffff;
    GammaArray[0][ik] = (WORD)iArrayValue;
    GammaArray[1][ik] = (WORD)iArrayValue;
    GammaArray[2][ik] = (WORD)iArrayValue;
}

::SetDeviceGammaRamp (hGammaDC, GammaArray);
Sleep (3000);

::ReleaseDC(NULL, hGammaDC);
Run Code Online (Sandbox Code Playgroud)

作为补充说明,我对上面的源稍作修改,以便不是同等地修改每个RGB值,而是注释掉前两个赋值,以便仅GammaArray[2][ik]修改.结果是显示器偏黄.

我也试图把上面的源代码在一个循环中,检查显示如何变化,它是从相当差wBrightness=0wBrightness=128.

for (wBrightness = 0; wBrightness <= 128; wBrightness += 16) {
    for (int ik = 0; ik < 256; ik++) {
        int iArrayValue = ik * (wBrightness + 128);
        if (iArrayValue > 0xffff) iArrayValue = 0xffff;
        GammaArray[0][ik] = (WORD)iArrayValue;
        GammaArray[1][ik] = (WORD)iArrayValue;
        GammaArray[2][ik] = (WORD)iArrayValue;
    }

    ::SetDeviceGammaRamp (hGammaDC, GammaArray);
    Sleep (3000);
}
Run Code Online (Sandbox Code Playgroud)

Microsoft提供了一篇在线MSDN文章,使用gamma校正,这是Direct3D文档的一部分,该文档描述了gamma的基本知识,如下所示:

在图形管道的末端,只是图像离开计算机以沿着监视器电缆行进的位置,有一小块硬件可以动态地转换像素值.此硬件通常使用查找表来转换像素.此硬件使用来自曲面的红色,绿色和蓝色值来查找表中的伽马校正值,然后将校正后的值发送到监视器而不是实际表面值.因此,此查找表可以用任何其他颜色替换任何颜色.虽然表具有这样的功率水平,但典型的用法是巧妙地调整图像以补偿显示器响应的差异.监视器的响应是与红色的数值相关的函数,

此外,软件应用程序Redshift有一个页面Windows伽玛调整,这有关于Microsoft Windows的说法.

将Redshift移植到Windows时,在设置低于约4500K的色温时遇到了麻烦.问题在于Windows对可以进行何种伽玛调整设置了限制,可能是为了保护用户免受恶意程序的影响,这些程序会反转颜色,使显示消隐,或者使用伽马斜坡播放其他令人烦恼的技巧.这种限制可能是可以理解的,但问题是完全缺乏此功能的文档(MSDN上的SetDeviceGammaRamp).试图设置不允许的伽玛斜坡的程序将会失败并出现一般错误,让程序员不知道出了什么问题.