Winapi 正确使用SetDeviceGammaRamp

Winapi 正确使用SetDeviceGammaRamp,winapi,gamma,Winapi,Gamma,我想添加在应用程序启动时调整屏幕gamma并在退出时重置它的功能。虽然人们是否应该篡改gamma还有争议(我个人认为这是无用的和有害的),但是,嘿,有些人希望能够做到这一点 这也只是一个简单的API调用,所以一切都很简单,对吗 MSDN说:“伽马斜率在256字元素的三个数组中指定,每个[…]值必须存储在每个字的最高有效位,以增加DAC独立性。”。这意味着,在我的理解中,类似于word\u value=byte\u value的东西我还没有测试过,但是如果我不得不猜测的话,早期的图形卡在编写Doo

我想添加在应用程序启动时调整屏幕gamma并在退出时重置它的功能。虽然人们是否应该篡改gamma还有争议(我个人认为这是无用的和有害的),但是,嘿,有些人希望能够做到这一点

这也只是一个简单的API调用,所以一切都很简单,对吗


MSDN说:“伽马斜率在256字元素的三个数组中指定,每个[…]值必须存储在每个字的最高有效位,以增加DAC独立性。”。这意味着,在我的理解中,类似于
word\u value=byte\u value的东西我还没有测试过,但是如果我不得不猜测的话,早期的图形卡在编写Doom时在SetDeviceGammaRamp()的实现中是非标准的,有时使用LOBYTE,有时使用word value的HIBYTE。大家一致同意只使用HIBYTE,因此使用
word\u value=byte\u value在研究以编程方式更改屏幕亮度的能力时,我偶然发现了这篇文章

使用调试器,我查看了
GetDeviceGamaRamp()
函数提供的值。输出是一个二维数组,定义为类似于
字GammaArray[3][256]和是一个包含256个值的表,用于修改显示像素的红色、绿色和蓝色值。我看到的值从索引0处的0(0)开始,然后加上256来计算下一个值。所以索引0,1,2,…,254,255的顺序是0,256,512,…,65024,65280

我的理解是,这些值用于修改每个像素的RGB值。通过修改表格值,可以修改显示亮度。然而,该技术的有效性可能因显示硬件而异

您可能会发现这篇简短的文章很有趣,因为它从Direct3D的角度描述了gamma渐变级别。这篇文章是关于伽马渐变级别的

在Direct3D中,术语gamma渐变描述映射的一组值 特定颜色分量的级别—红色、绿色、蓝色代表所有颜色分量 帧缓冲区中的像素恢复到DAC接收的新级别 用于显示。通过三次查找执行重新映射 表,每个颜色组件一个

其工作原理如下:Direct3D从帧缓冲区中提取一个像素,然后 评估其单独的红色、绿色和蓝色组件。每个 组件由0到65535之间的值表示。Direct3D需要 原始值,并将其用于索引256元素数组( 渐变),其中每个元素都包含一个替换原始元素的值 一个。Direct3D为每种颜色执行此查找和替换过程 帧缓冲区中每个像素的分量,从而更改 所有屏幕像素的最终颜色

根据
GetDeviceGamaRamp()
SetDeviceGamaRamp()
的联机文档,从Windows 2000 Professional开始,Windows API支持这些函数

我使用了他们的源代码,将其压缩为插入Windows应用程序中的以下示例,以使用参考文章中的值测试效果。我的测试是用Windows7和AMD Radeon HD7450图形适配器完成的

通过此测试,我的两个显示器(我有两个显示器)都受到影响

//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);
Microsoft提供了一篇联机MSDN文章,这是Direct3D文档的一部分,该文档描述了gamma的基本知识,如下所示:

在图形管道的末尾,图像离开 电脑沿着显示器电缆行进时,有一个小问题 一块可以动态转换像素值的硬件。这 硬件通常使用查找表来变换像素。这 硬件使用来自 要显示的曲面,以在表中查找伽马校正值 然后将校正后的值发送到监视器,而不是 实际曲面值。因此,这个查找表是一个 用任何其他颜色替换任何颜色。而这张桌子有那个级别 对于电源,典型的用法是巧妙地调整图像以进行补偿 查看监视器响应中的差异。监视器的响应是 将红色、绿色和黄色的数值关联起来的函数 具有像素显示亮度的像素的蓝色分量

另外,微软的Windows也有这样的说法

在将Redshift移植到Windows时,我在设置 色温低于4500K左右。问题是Windows 设置可以进行哪种伽马调整的限制, 可能是为了保护用户免受恶意程序的攻击 反转颜色、空白显示或播放其他令人讨厌的内容 使用伽马斜坡的技巧。这种限制也许是不合理的 可以理解,但问题是完全缺乏文档 此功能的名称()。一种试图 设置一个不允许的gamma渐变将简单地以一个通用的方式失败 错误使程序员不知道出了什么问题


应该注意的是,“gamma”与“亮度”(如果有的话)关系不大。Gamma是指在设备显示和人眼感知的内容以及计算机在另一侧看到的线性RGB值之间进行非线性每分量变换(非线性,除非γ=1)。然而,您提供了一个官方来源(DX手册页),它似乎表明0到65535的范围确实是正确的。因此,我接受你的回答。@Damon,我对这一切的感觉是,通过修改gamma渐变,你基本上是通过对每个像素的RGB值进行转换,从而将颜色范围移向黑色或白色,从而使显示输出倾斜。用这个反式
//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);
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);
}