모니터의 밝기나 감마값, 대비값을 조절해야 하는 경우가 종종 있습니다.
그래픽 작업을 위해 출력물과 모니터 색감을 맞춘다거나, 게임 중 어두운 곳을 상대적으로 밝게 보이게 한다거나…
모니터에서 밝기, 대비를 조정하는 경우도 있고, 윈도우 제어판에서 조정하는 경우, 게임상 옵션에서 조정하는 경우도 있습니다.
이 소스는 윈도우의 GDI 를 이용해 감마, 밝기, 대비 를 조절하는 소스이며, 딱 한줄이 핵심 부분입니다만, 용도에 따라 수정할 수 있도록 간단히 이론을 설명합니다.
물론 저도 이론은 모르지만, 제가 이해한 범위 내에서 설명하겠습니다.
먼저 아래 그래프를 보겠습니다.
![](http://10.42.1.54:20080/wp-content/uploads/2017/03/Gamma1.jpg)
캡처를 잘못해 마우스 커서가 나왔지만… 중요한건 박스에서 정확히 대각선을 그리게 되었다는걸 보시면 됩니다.
이것이 윈도우에서 디스플레이 설정을 건들지 않았을 때 나오는 기본 값입니다.
X 좌표는 0 에서 255 까지, Y 좌표는 0 에서 65535 까지 이며, 이 범위를 벗어날 수 없습니다.
위 기본 상태에서 감마를 높일 경우 선이 곡선 형태로 휘어집니다.
![](http://10.42.1.54:20080/wp-content/uploads/2017/03/Gamma2.jpg)
아래로 휘어지면 감마값이 낮아지겠지요?
기본 상태에서 밝기를 조절해 보겠습니다.
![]() |
![]() |
왼쪽 그림은 밝기를 밝게, 오른쪽 그림은 밝기를 어둡게 한 그래프 입니다.
기본 상태에서 대각선의 기울기는 고정된 채로 상, 하 이동을 하게 됩니다.
이제 기본 값에서 대비를 조정해 보겠습니다.
![](http://10.42.1.54:20080/wp-content/uploads/2017/03/Gamma5.jpg)
대비를 높이면 대각선의 기울기가 변한다는 것을 알 수 있네요. 대각선의 기울기가 커지면 대비가 커지고, 대각선의 기울기가 작아지면 대비는 낮아집니다.
자… 그럼 이제 이런걸 어디서 볼 수 있느냐…. 알려 드리겠습니다.
인텔 내장 그래픽 카드를 사용한다면, ‘디스플레이 등록정보’ 에 ‘고급’으로 들어가면 ‘Intel(R) Graphics Media Accelertor Driver’ 에서 ‘그래픽 속성’ 그리고 ‘색 보정’ 을 보시면 이 그래프를 볼 수 있습니다.
S3 그래픽 카드도, 라데온, 지포스도 비슷한 방법으로 찾아들어가면 다 있습니다.
그럼 이제 감마, 밝기, 대비 조정을 소프트웨어적으로 처리하는 방법은 뭐가 있을까요.
GDI 를 사용하는 방법이 제일 무난합니다. 그냥 Windows API 를 사용하면 되니까요.
DirectX, OpenGL 의 경우 좀더 고급스럽게 함수를 지원하지만, 지원한다는 것만 알아두시고, 아래 소스에서 사용하는 GDI 사용 방법을 보도록 하겠습니다.
아래 소스에서 사용하는 API 는 SetDeviceGammaRamp() 입니다. 자매품으로 GetDeviceGammaRamp() 도 제공하구요, Delphi, VC++, VB 등에서도 사용 가능하며, C# 도 사용할 수 있다고 합니다.(아직 C# 쪽에서는 직접 테스트해보지 확실하진 않습니다.)
중요한건 WinAPI 기 때문에 따로 선언이 필요 없다는 점과, 프로그램 시작시 GetDeviceGammaRamp() 로 값을 가져와 저장하고, 프로그램 종료시 저장해 놓은 값을 SetDeviceGammaRamp() 로 복원해야 중간에 가지고 놀다가 화면이 새하얗게 되거나 깜깜해져 낭패를 겪는 일을 방지해야 합니다. ^^;
아래 코드를 넣기 전에 상단에 type 로 record 타입을 미리 선언해 둡니다.
1 2 3 4 5 6 |
type TGammaRamp = record R : Array[0..255] of Word; G : Array[0..255] of Word; B : Array[0..255] of Word; end; |
VC++ 에서는 선언 안하고 사용하긴 합니다만….
구조체로 선언한다면 좀 깔끔해지겠죠?
인터넷에 나뒹구는 VC++ 소스들은 아래 TempGamma 와 동일한 용도의 선언을
unsigned short TempGamma[768];
이라 선언하고, 아래의
1 2 |
Result.R, ResultG, ResultB 에 값을 넣을 때 TempGamma[i] = TempGamma[256+i] = TempGamma[512+1] = f; |
이런 형태로 사용합니다.
물론 속도는 이게 좋다할 수 있지만, 보기좋은 떡이 먹기도 좋으니 구지 실시간으로 아주 빠르게 처리하는 경우가 아니라면 보기 좋게 하는게 좋겠지요. ^^
아래 코드를 보면
1 |
f := Min(65535, Round(Max(0, 65535 * Power(I / 255, Gamma) + ((overbright - 1.0) * 32767 )))); |
라는 아주 중요한 식이 있습니다. 요게 바로 배열에 곡선 그리기를 하기 위한 연산을 하는 녀석입니다.
대비 부분은 빠졌지만, 밝기와 감마는 조절할 수 있고, 밝기의 경우 너무 밝아지지 않도록 조정을 해두었습니다.
또 아까 말씀드렸듯이 0 ~ 65535 까지의 범위를 사용하기 때문에 Max 함수와 Min 함수로 이 값이 넘지 못하도록 해두었습니다.
자 그럼 이제 아래 소스를 분석해서 모니터 밝기를 조절해 보세요!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
function SetGamma(Gamma : single; overbright : single) : TGammaRamp; var f : integer; i : integer; DC : HDC; TempGamma : TGammaRamp; begin DC := GetDC(0); GetDeviceGammaRamp( DC, TempGamma ); for i := 0 to 255 do begin f := Min(65535, Round(Max(0, 65535 * Power(I / 255, Gamma) + ((overbright - 1.0) * 32767 )))); Result.R[I] := f; Result.G[I] := f; Result.B[I] := f; end; SetDeviceGammaRamp( DC, Result ); ReleaseDC(0, DC); end; |
ps1. 인터넷에 널려있는 함수들은 감마만 되길래 밝기 부분을 추가했습니다.
ps2.추가로 이 함수의 인자가 받을 수 있는 범위(권장)는 다음과 같습니다.
Gamma = 0.10 ~ 2.00 까지 (기본값 1.0)
overbright = 0.10 ~ 2.00 까지 (기본값 1.0)
ps3. 저도 구글신의 도움으로 기본 골격을 해외 커뮤니티에서 퍼왔습니다. 맘대로 퍼나르고 쓰셔도 무관합니다. 출처 밝히지 않으셔도 됩니다. ^^