이번에 작업한 부분
포토샷의 어두운 영역·중간톤·밝은 영역 색상 균형을 한 레이어에 묶었습니다.
포토샷의 어두운 영역·중간톤·밝은 영역 색상 균형을 한 레이어에 묶었습니다.
개발 기록 재구성 · 공개 코드 v0.16.0 기준 / 2026.10.13
구현 과정 읽기 ↓
Development journal / 08
기존 개발 기록과 공개 코드를 바탕으로 구현 과정을 정리했습니다. 아래 인물 사진은 2026.10.13에 새로 제작한 동작 예시입니다.
포토샷의 어두운 영역·중간톤·밝은 영역 색상 균형을 한 레이어에 묶었습니다.
세 영역의 설정을 따로 저장하고, 명도 유지 옵션과 계산 버전에 따라 처리 경로를 나눴습니다.
전체 사진에 같은 색을 더하면 그림자와 밝은 피부를 따로 다루기 어렵습니다. 계산을 개선할 때 이전 프로젝트의 색이 바뀌는 문제도 함께 고려해야 했습니다.
초기에는 GIMP 문서의 세 명암 영역과 명도 유지 기능을 참고했습니다. 공개본은 자체 채널 계산·측정 응답 경로를 사용하고, 이전 파일에는 예전 계산을 남겼습니다.
GIMP 코드를 복사한 기록은 없습니다. 문서의 기능 구분을 참고했고, 포토샷의 계산은 자체 구현입니다.
이번에는 중간톤의 Red +12, Blue −10과 밝기 유지를 적용했습니다. 현재 사진의 수치와 과거 개발기의 계산 예시는 구분해 두었습니다.

AFTERBEFORE포토샷 색상균형에서 중간톤을 조절하고 밝기 유지 옵션을 함께 확인했습니다. 각 밝기 영역이 겹치는 방식과 색상 계산을 작업기에 담았습니다.
사진 위를 좌우로 움직여 비교하세요. 키보드로는 비교 막대에 초점을 맞춘 뒤 방향키를 사용하면 됩니다.
인물 사진은 새로 생성한 AI 이미지입니다. 편집 결과는 실제 Photoshot에서 적용하고 내보냈습니다. 아래 값은 이 사진의 실습값이며 모든 사진에 맞는 권장값은 아닙니다.
STEP 01 / 도구 찾기
사진을 연 뒤 상단 Add Adjustment에서 Color Balance를 선택합니다. 아래는 실제 편집기에서 해당 도구의 위치를 확인한 화면입니다.

STEP 02 / 직접 조절
Midtones에서 Cyan ↔ Red 12, Yellow ↔ Blue −10을 입력합니다. Preserve Luminosity를 켠 상태로 색의 균형을 살펴봅니다.

STEP 03 / 레이어 표시를 껐다 켜거나 Hold to Compare로 원본을 비교한 뒤 File → Export As… → Download로 결과를 저장합니다. 위 전후 비교의 AFTER는 이 편집기에서 직접 내보낸 이미지입니다. 화면을 누르면 원본 크기로 확대됩니다.
02 / Behind the tool
아래는 기존 작업기의 공개 코드 v0.16.0 기준 설명과 계산 예제입니다. 2026.10.01 기록의 수치·검증 설명을 보존했습니다. 위의 2026.10.13 새 사진 실습과 설정값은 다를 수 있으며, 현재 편집기의 모든 기능을 이 버전의 코드와 동일하다고 설명하는 것은 아닙니다.
릴스에서는 중간톤의 빨강을 +14, 파랑을 −12로 바꿨습니다. 어두운 영역은 빨강 −6·파랑 +10, 밝은 영역은 빨강 +8·파랑 −6입니다. 초록은 세 영역 모두 0으로 두었습니다.
화면에서 명암 영역을 바꾸면 해당 영역의 설정을 불러옵니다. 코드에는 shadowsR, midtonesR, highlightsR처럼 영역과 채널을 붙인 이름으로 저장했습니다. 각 값의 범위는 −100~100입니다.
영역 선택은 편집할 설정 묶음을 고르는 기능입니다. 얼굴이나 배경을 직접 선택하는 것은 아니므로, 특정 피사체에만 적용하려면 마스크를 함께 사용합니다.
| 영역 | 빨강 | 초록 | 파랑 |
|---|---|---|---|
| 어두운 영역 | -6 | 0 | 10 |
| 중간톤 | 14 | 0 | -12 |
| 밝은 영역 | 8 | 0 | -6 |
현재 새 레이어는 revision 2 계산을 사용합니다. 명도 유지가 켜져 있으면, 각 채널의 어두운 영역 설정을 검정점으로, 밝은 영역 설정을 흰색점으로 바꿉니다. 중간톤 설정은 감마에 들어갑니다.
이때 슬라이더값을 그대로 픽셀에 더하지 않습니다. 어두운 영역의 최댓값, 밝은 영역의 최솟값, 중간톤의 최댓값과 최솟값 사이 중심을 먼저 구합니다. 다른 채널과 얼마나 차이가 나는지가 계산에 반영됩니다.
black = shMax - v['shadows' + key];
white = 255 - v['highlights' + key] + hiMin;
gamma = 2 ** (
(v['midtones' + key] - midCenter) / 100
);예제의 중간톤 중심은 (14 + −12) ÷ 2 = 1입니다. 따라서 빨강 감마는 2의 0.13제곱, 파랑 감마는 2의 −0.13제곱이 됩니다. 표의 감마는 소수 넷째 자리까지 표시했습니다.
| 채널 | 검정점 | 흰색점 | 감마 |
|---|---|---|---|
| R | 16 | 241 | 1.0943 |
| G | 10 | 249 | 0.9931 |
| B | 0 | 255 | 0.9138 |
구한 검정점과 흰색점으로 채널의 범위를 다시 잡고, 감마를 적용합니다. 아래 x는 0~1로 바꾼 채널값입니다. 분모는 최소 1로 제한해 0으로 나누는 경우를 막았습니다.
const normalized = clamp(
(x * 255 - black) / Math.max(1, white - black)
);
const result = normalized ** (1 / gamma);오른쪽은 서로 다른 밝기의 회색 세 개를 같은 설정으로 처리한 결과입니다. 회색이기 때문에 입력의 R·G·B는 같지만, 출력에서는 각 채널의 곡선에 따라 차이가 생깁니다.
‘명도 유지’라는 이름만 보고 밝기 수치가 항상 정확히 같다고 해석하면 안 됩니다. 이 분기는 채널 간 상대값으로 검정점·흰색점·감마를 조정하며, 매 픽셀의 휘도를 일정하게 고정하는 별도 보정은 하지 않습니다.
명도 유지 옵션을 끄면, 미리 측정해 둔 색 변화 데이터를 적용합니다. 코드의 순서는 밝은 영역 → 중간톤 → 어두운 영역입니다. 앞 단계의 출력이 다음 단계의 입력으로 들어갑니다.
for (let zone = 2; zone >= 0; zone--) {
out[c] = sampleResponse(
balanceResponse[zone],
v[['shadows', 'midtones', 'highlights'][zone]
+ key],
-100, out[c]
);
}응답 자료 파일의 주석에는 Photoshop 27.3.1의 합성 밝기 단계 이미지를 측정한 RGB8 응답이라고 기록되어 있습니다. Adobe가 공개한 내부 알고리즘이 아니라 이 프로젝트에 저장된 측정 자료입니다.
Adobe 문서에서는 명암 영역별 색 조절과 명도 유지 옵션의 목적을 확인했습니다. 포토샷의 계산식은 저장소의 구현을 기준으로 설명했습니다. 같은 이름의 옵션이라도 내부 계산과 모든 색 공간에서의 결과까지 같다는 뜻은 아닙니다.
예전 프로젝트를 열 때는 기존 계산을 사용하도록 revision 분기를 남겼습니다. 조정 레이어의 계산을 개선하더라도 저장해 둔 사진이 갑자기 다른 색으로 보이지 않도록 하기 위한 구조입니다.
이번 글의 표본은 새 레이어를 만드는 함수로 생성해 계산했습니다. 원래 구현과 측정 자료의 위치를 아래에 연결해 두었으니, 식과 표본을 함께 확인할 수 있습니다.
| 구분 | 코드에서 확인할 부분 |
|---|---|
| 설정 | 세 영역 × RGB = 9개 값 |
| 명도 유지 켬 | 채널별 검정점·흰색점·감마 |
| 명도 유지 끔 | 영역별 측정 응답표 |
| 이전 파일 | revision에 따른 기존 계산 유지 |