LCD背光控制 brightness control

在显示器的校正中常常会涉及Gamma值、白点坐标、色温、三原色、荧光剂色度值等参数。不同的gamma值会使显示器的亮度和颜色有较大差别。gamma值较小时亮调的等级差比较大,对表现亮度的颜色有利,反之,gamma值较大时对暗调的等级差拉的很大,对表现暗色有利。人的视觉对RGB三色信号的感觉大致成对数变化而不是线性变化,gamma校正正是为了克服这种非线性。gamma值的选取应该使整个亮度级别变化均匀。 

notebook的背光控制是通过EC完成的,EC可以通过调节电源电压来实现LCD亮度调节。应用层如果要实现这个功能是通过显卡的RAMP值来实现的。C#中可以调用gdi32.dll提供的函数SetDeviceGammaRamp 和 GetDeviceGammaRamp来实现。但在操作之前要使用GetHdc()得到显卡的句柄。

        [DllImport("gdi32.dll")]
        private unsafe static extern bool SetDeviceGammaRamp(Int32 hdc, void* ramp);

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);

        private static bool initialized = false;
        private static Int32 hdc;

         private static void InitializeClass()
        {
            if (initialized) return;
            hdc = Graphics.FromHwnd(IntPtr.Zero).GetHdc().ToInt32();
            initialized = true;
        }       

        public static unsafe bool SetBrightness(short brightness)
        {
            InitializeClass();
            if (brightness > 255) brightness = 255;
            if (brightness < 0) brightness = 0;

            short* gArray = stackalloc short[3 * 256];
            short* idx = gArray;
            for (int j = 0; j < 3; j++)
            {
                for (int i = 0; i < 256; i++)
                {
                    int arrayVal = i * (brightness + 128);
                    if (arrayVal > 65535) { arrayVal = 65535; }
                    *idx = (short)arrayVal;
                    idx++;
                }
            }
            //For some reason, this always returns false?
            bool retVal = SetDeviceGammaRamp(hdc, gArray);
            //Memory allocated through stackalloc is automatically free'd by the CLR.
            return retVal;
        }

程序运行后确实可以调整背光,功能没问题。这里有两个问题:

一个是SetDeviceGammaRamp返回值总是false ,另一个是gArray的计算,为什么是arrayVal = i * (brightness + 128);?

 

另一个版本:

        [DllImport("gdi32.dll")]
        public static extern int GetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);       

        [DllImport("gdi32.dll")]
        public static extern int SetDeviceGammaRamp(IntPtr hDC, ref RAMP lpRamp);

        [DllImport("user32.dll")]
        static extern IntPtr GetDC(IntPtr hWnd);

        private static RAMP s_ramp = new RAMP();       

        private static RAMP ramp = new RAMP();

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct RAMP
        {
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Red;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Green;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public UInt16[] Blue;
        }

       

        public static unsafe void SetGamma(int gamma)
        {
            InitializeClass();
            ramp.Red = new ushort[256];
            ramp.Green = new ushort[256];
            ramp.Blue = new ushort[256];

            for (int i = 1; i < 256; i++)
            {
                // gamma 必须在3和44之间
                ramp.Red[i] = ramp.Green[i] = ramp.Blue[i] = (ushort)(Math.Min(65535, Math.Max(0, Math.Pow((i + 1) / 256.0, gamma * 0.1) * 65535 + 0.5)));
            }
            SetDeviceGammaRamp(GetDC(IntPtr.Zero), ref ramp);
           
        }

         public static unsafe int GetBrightness()
        {       
           
            int gamma = 0;           
            s_ramp.Red = new ushort[256];
            s_ramp.Green = new ushort[256];
            s_ramp.Blue = new ushort[256];
            GetDeviceGammaRamp(GetDC(IntPtr.Zero), ref s_ramp);            
            return gamma;
        }

运行后会改变gamma的值而不是背光。两个版本看起来是ramp算法不同其他都一样。而ramp是一个3*256的矩阵 用来代表RGB的修正值。

使用using System.Management;空间提供的类和物件实现:

using System.Management;       

static void SetBrightness(byte targetBrightness)
        {
            ManagementScope scope = new ManagementScope("root\\WMI");
            SelectQuery query = new SelectQuery("WmiMonitorBrightnessMethods");
            using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
            {
                using (ManagementObjectCollection objectCollection = searcher.Get())
                {
                    foreach (ManagementObject mObj in objectCollection)
                    {
                        mObj.InvokeMethod("WmiSetBrightness",
                            new Object[] { UInt32.MaxValue, targetBrightness });
                        break;
                    }
                }
            }
        }

   编译时总是提示找不到   ManagementScope ,没办法执行。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Sets a monitor's brightness value. Increasing the brightness value makes the display on the monitor brighter, and decreasing it makes the display dimmer.

Vista下如何用软件控制屏幕高层的API可以方便地控制屏幕的亮度、色温、对比度、显示区等。

#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
#pragma comment(lib,"dxva2.lib")

void FreePhysicalMonitor(DWORD npm, LPPHYSICAL_MONITOR ppm)
{
        DestroyPhysicalMonitors(npm, ppm);
        // Free the array.
       free(ppm);
}

LPPHYSICAL_MONITOR GetPhysicalMonitor(DWORD *pnpm)
{
        HMONITOR hMon = NULL;
        hMon = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
	LPPHYSICAL_MONITOR ppm = NULL;
	DWORD npm = 0;
	BOOL bRet = GetNumberOfPhysicalMonitorsFromHMONITOR(hMon, &npm);
	if (bRet) 
	{	ppm = (LPPHYSICAL_MONITOR)malloc(npm * sizeof(PHYSICAL_MONITOR));
		if (ppm) 
		{bRet = GetPhysicalMonitorsFromHMONITOR(hMon, npm, ppm);
			if (!bRet) {
		    	FreePhysicalMonitor(npm, ppm);
		    	ppm = NULL;
		    	npm = 0;
			}
		}
	}
	*pnpm = npm;
	return  ppm;
}

 

返回的是PHYSICAL_MONITOR数组,以下示例只是使用了第一个PHYSICAL_MONITOR元素。

1、调整屏幕前我们可以看看显示器支持什么功能,Vista提供的API是GetMonitorCapabilities(在有些显示器上虽然GetMonitorCapabilities调用失败,但仍然可以调整亮度等;在有些显示器上,从GetMonitorCapabilities返回的值看可以支持某些功能,但实际又不能。这些都另当别论)。

LPPHYSICAL_MONITOR ppm = 0;
ppm = GetPhysicalMonitor();
if (ppm) {
DWORD nmc = 0, nct = 0;
GetMonitorCapabilities(ppm->hPhysicalMonitor, &nmc, &nct);
CString str = _T("");
if (nmc & MC_CAPS_BRIGHTNESS) {
str += _T("Support brightness control\n");
}
if (nmc & MC_CAPS_COLOR_TEMPERATURE) {
str += _T("Support color temperature\n");
}
if (nmc & MC_CAPS_CONTRAST) {
str += _T("Support contrast\n");
}
.........
if (str == _T(""))
str = _T("Support None");
MessageBox(str);
FreePhysicalMonitor(npm, ppm);
}

2、如何调整亮度
LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);    

 //这一步可以得到ppm ,并且szPhysicalMonitorDescription中有显示器的描述。但ppm->hPhysicalMonitor一直是NULL.

//有人知道原因吗?帮忙留言告知下
if (ppm) {
DWORD nMin = 0, nCur = 0, nMax = 0;
GetMonitorBrightness(ppm->hPhysicalMonitor, &nMin, &nCur, &nMax);
CString str;
str.Format(_T("Min:%d, Cur:%d, Max:%d"), nMin, nCur, nMax);
MessageBox(str);
SetMonitorBrightness(ppm->hPhysicalMonitor, nMin);
Sleep(1000);
SetMonitorBrightness(ppm->hPhysicalMonitor, nMax);
Sleep(1000);
SetMonitorBrightness(ppm->hPhysicalMonitor, nCur);
Sleep(1000);
FreePhysicalMonitor(npm, ppm);
}

3、调色温

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
SetMonitorRedGreenOrBlueGain(ppm->hPhysicalMonitor, MC_RED_GAIN, 50);
Sleep(500);
SetMonitorRedGreenOrBlueGain(ppm->hPhysicalMonitor, MC_GREEN_GAIN, 49);
Sleep(500);
SetMonitorRedGreenOrBlueGain(ppm->hPhysicalMonitor, MC_BLUE_GAIN, 52);
MessageBox(_T("Set color temperature => Done"));

FreePhysicalMonitor(npm, ppm);
}

4、调对比度

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
DWORD nMin, nCur, nMax;
GetMonitorContrast(ppm->hPhysicalMonitor, &nMin, &nCur, &nMax);
CString str;
str.Format(_T("Min:%d, Cur:%d, Max:%d"), nMin, nCur, nMax);
MessageBox(str);
SetMonitorContrast(ppm->hPhysicalMonitor, nMin);
Sleep(1000);
SetMonitorContrast(ppm->hPhysicalMonitor, nMax);
Sleep(1000);
SetMonitorContrast(ppm->hPhysicalMonitor, nCur);
Sleep(1000);
FreePhysicalMonitor(npm, ppm);
}

5、查看显示器类型

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
TCHAR *descs[] = {
_T("Shadow-mask cathode ray tube (CRT)"),
_T("Aperture-grill CRT"),
_T("Thin-film transistor (TFT) display"),
_T("Liquid crystal on silicon (LCOS) display"),
_T("Plasma display"),
_T("Organic light emitting diode (LED) display"),
_T("Electroluminescent display"),
_T("Microelectromechanical display"),
_T("Field emission device (FED) display")
};
MC_DISPLAY_TECHNOLOGY_TYPE dtt;
GetMonitorTechnologyType(ppm->hPhysicalMonitor, &dtt);
CString str;
str.Format(_T("Technology type: %s"), descs[(int)dtt]);
MessageBox(str);
FreePhysicalMonitor(npm, ppm);
}

6、恢复出厂设置

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
RestoreMonitorFactoryDefaults(ppm->hPhysicalMonitor);
FreePhysicalMonitor(npm, ppm);
}

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(VC#,硬体相关)