모니터의 밝기나 감마값, 대비값을 조절해야 하는 경우가 종종 있습니다.
그래픽 작업을 위해 출력물과 모니터 색감을 맞춘다거나, 게임 중 어두운 곳을 상대적으로 밝게 보이게 한다거나…
모니터에서 밝기, 대비를 조정하는 경우도 있고, 윈도우 제어판에서 조정하는 경우, 게임상 옵션에서 조정하는 경우도 있습니다.
이 소스는 윈도우의 GDI 를 이용해 감마, 밝기, 대비 를 조절하는 소스이며, 딱 한줄이 핵심 부분입니다만, 용도에 따라 수정할 수 있도록 간단히 이론을 설명합니다.
물론 저도 이론은 모르지만, 제가 이해한 범위 내에서 설명하겠습니다.
먼저 아래 그래프를 보겠습니다.
캡처를 잘못해 마우스 커서가 나왔지만… 중요한건 박스에서 정확히 대각선을 그리게 되었다는걸 보시면 됩니다.
이것이 윈도우에서 디스플레이 설정을 건들지 않았을 때 나오는 기본 값입니다.
X 좌표는 0 에서 255 까지, Y 좌표는 0 에서 65535 까지 이며, 이 범위를 벗어날 수 없습니다.
위 기본 상태에서 감마를 높일 경우 선이 곡선 형태로 휘어집니다.
아래로 휘어지면 감마값이 낮아지겠지요?
기본 상태에서 밝기를 조절해 보겠습니다.
왼쪽 그림은 밝기를 밝게, 오른쪽 그림은 밝기를 어둡게 한 그래프 입니다.
기본 상태에서 대각선의 기울기는 고정된 채로 상, 하 이동을 하게 됩니다.
이제 기본 값에서 대비를 조정해 보겠습니다.
대비를 높이면 대각선의 기울기가 변한다는 것을 알 수 있네요. 대각선의 기울기가 커지면 대비가 커지고, 대각선의 기울기가 작아지면 대비는 낮아집니다.
자… 그럼 이제 이런걸 어디서 볼 수 있느냐…. 알려 드리겠습니다.
인텔 내장 그래픽 카드를 사용한다면, ‘디스플레이 등록정보’ 에 ‘고급’으로 들어가면 ‘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. 저도 구글신의 도움으로 기본 골격을 해외 커뮤니티에서 퍼왔습니다. 맘대로 퍼나르고 쓰셔도 무관합니다. 출처 밝히지 않으셔도 됩니다. ^^