2011-12-02 298 views
7

我想添加在应用程序启动时调整屏幕灰度并在退出时重置它的功能。尽管人们是否应该篡改伽马(个人认为它是无用的和有害的)是有争议的,但是,嘿,有些人希望能够做这种事情。正确使用SetDeviceGammaRamp

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

MSDN说:“伽玛斜坡由256个WORD元素的三个数组指定,每个值必须存储在每个WORD的最高有效位中,以提高DAC独立性。。这意味着,根据我的理解,像word_value = byte_value<<8这听起来很奇怪,但它是我读的。

的毁灭战士源代码包含一个函数,它char值的三个阵列并将其转换成具有相同的字节值在上部和下部半二者uint16_t值的阵列。换句话说就是word_value = (byte_value<<8)|byte_value。这同样很奇怪,但更糟糕的是与上面的不一样。

此外,互联网上的各种爱好程序员网站(显然是从另一个偷来的,因为它们与该字母完全相同)中存在一些代码片段,它们将线性索引与数值相乘,偏置128,钳位到65535.我不太确定这是关于什么,但对我来说这看起来像是完全废话,而且它与上述两者中的任何一个都不一样。

什么给?它必须是明确的 - 无需猜测 - 您提供的数据的外观必须如何?最后,要做的是读取原始值并让用户调整一些滑块(并可选择将该blob用用户的配置保存到磁盘),但仍然...为了修改这些值,需要知道他们是什么以及期望的。

有没有人完成(并测试!)这之前,并知道哪一个是正确的?

回答

6

当调查以编程方式更改屏幕亮度的功能,我碰到这篇文章Changing the screen brightness programmingly - By using the 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的角度描述了伽玛斜坡水平。这篇文章有关伽马斜坡水平的说法。

在Direct3D,术语伽马斜坡描述了一组值的映射 特定颜色的水平组件的红,绿,蓝中的帧缓冲器,以由接收到的新级别的所有 像素用于显示的DAC 。重映射通过三个查询表 表执行,每个颜色分量一个表。

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

根据对GetDeviceGamaRamp()SetDeviceGamaRamp()这些功能的在线文档是在Windows API与Windows 2000专业版开始就支持。

我将他们的源代码压缩到插入到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); 

作为附加说明,我对上述源的微小变化,使得代替修改每个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); 
} 

微软提供的在线MSDN文章,Using gamma correction,这是描述伽马的基本如下Direct3D的文档的一部分:

在图形流水线的末端,就在那里该图像离开 计算机以沿着显示器电缆前进,还有一小块硬件可以实时转换像素值。这个硬件通常使用查找表来转换像素。此 硬件使用来自 表面的红色,绿色和蓝色值显示,以在表 中查找伽马校正值,然后将校正值发送到显示器,而不是实际表面值为 。所以,这个查找表是一个机会,以 取代任何其他颜色的颜色。虽然该表的功率级别为 ,但典型用法是巧妙地调整图像以补偿显示器响应差异 。显示器的响应是 这是将像素的红色,绿色和蓝色分量的数值与该像素的显示亮度相关联的功能。

此外,software application Redshift has a page Windows gamma adjustments其中有这么说微软Windows。

将Redshift移植到Windows时当设置 色温低于约4500K时,我遇到了麻烦。问题在于,Windows 对可以进行哪种伽玛调整设置了限制, 可能作为保护用户免受邪恶程序影响的一种手段,该程序可以反转颜色,使显示器空白或播放其他恼人的 技巧坡道。这种限制或许可以理解为 ,但问题是完全没有此功能的文档 (SetDeviceGammaRamp on MSDN)。一个程序尝试 设置不允许的伽马斜坡将仅仅失败,并且出现通用的 错误,使程序员不知道出了什么问题。

+0

应该指出,“伽玛”与“亮度”没有什么关系,如果有的话。 Gamma是关于做一个非线性的每分量变换(非线性,除非γ= 1),在设备可以显示的内容和人眼所感知的内容之间进行转换,以及计算机在另一侧看到的线性RGB值。尽管如此,你已经提供了一个官方消息来源(DX手册页),它合理地暗示了范围从0到65535是正确的。因此,我会接受你的回答。 – Damon

+1

@Damon,我的感觉是,通过修改伽玛斜坡,您基本上是通过对每个像素的RGB值执行平移来偏移显示输出,并因此将颜色范围移向黑色或朝向白色。通过此翻译,您正在修改显示图像的明亮度。从我可以告诉它看起来像一些屏幕显示亮度应用程序,如[Redshift](http://jonls.dk/redshift/)使用更改伽马斜坡。请参阅Redshift站点上的[Windows gamma调整](http://jonls.dk/2010/09/windows-gamma-adjustments/) –

2

我还没有测试过这个,但是如果我不得不猜测,早期的图形卡在执行SetDeviceGammaRamp()时是非标准的,当编写Doom时有时使用LOBYTE并且有时使用WORD值的HIBYTE 。共识转移到只使用HIBYTE,因此word_value = byte_value<<8

这是另一个数据点,从PsychoPy库(在python),这是刚刚换LOBYTE和HIBYTE:

"""Sets the hardware look-up table, using platform-specific ctypes functions. 
For use with pyglet windows only (pygame has its own routines for this). 
Ramp should be provided as 3x256 or 3x1024 array in range 0:1.0 
""" 
if sys.platform=='win32': 
    newRamp= (255*newRamp).astype(numpy.uint16) 
    newRamp.byteswap(True)#necessary, according to pyglet post from Martin Spacek 
    success = windll.gdi32.SetDeviceGammaRamp(pygletWindow._dc, newRamp.ctypes) 
    if not success: raise AssertionError, 'SetDeviceGammaRamp failed' 

还可以看出Windows不允许所有的伽玛设置,请参阅: http://jonls.dk/2010/09/windows-gamma-adjustments/

更新:

的第一个Windows API来提供伽玛控制都是Windows Graphi cs设备接口(GDI)的SetDeviceGammaRamp和GetDeviceGammaRamp。这些API与三个256条目的WORD数组一起工作,每个WORD编码为零,最高为1,由WORD值0和65535表示.WORD的额外精度通常在实际的硬件查找表中不可用,但是这些API是意图是灵活的。与本节后面介绍的其他API相比,这些API只允许从身份函数中稍微偏离。事实上,斜坡中的任何条目都必须在身份值的32768之内。此限制意味着没有应用程序可以将显示器完全变为黑色或其他不可读取的颜色。

http://msdn.microsoft.com/en-us/library/windows/desktop/jj635732(v=vs.85).aspx