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