PHOTOSHOT / DEVELOPMENT JOURNAL
따뜻한 색을 더하는
필터의 계산 순서
따뜻한 필터를 골랐을 때 사진 전체가 같은 주황색으로 덮이지 않도록, 원래 RGB를 변환하는 방식으로 만들었습니다. 필터 농도는 변환 과정에, 레이어 불투명도는 마지막 합성에 적용합니다.


09편에서는 같은 필터의 강도를 조절하는 두 숫자를 비교합니다. 농도를 낮추는 것과 레이어를 투명하게 만드는 것이 왜 다른지, 픽셀 세 개로 확인해 봅니다.
필터색·농도·명도 유지 저장하기
릴스에서는 Warming (85)에 해당하는 색 #ec8a00을 사용했습니다. 농도를 35에서 55로 올린 뒤, 레이어 불투명도를 85%로 낮춰 마무리했습니다. 명도 유지는 켜 두었습니다.
필터 목록은 이름과 HEX 색상값을 연결한 배열입니다. 목록에서 고르면 색상값이 레이어에 저장되고, 사용자가 직접 색을 골라도 같은 계산을 거칩니다. 화면에 ‘사용자 정의 색상’이라고 보여도 저장된 필터색은 유지됩니다.
농도는 0~100, 기본값은 25입니다. 이름이 붙은 필터와 직접 고른 색을 구분해 서로 다른 알고리즘을 적용하는 구조는 아닙니다.
화면의 RGB를 변환한 뒤 행렬 적용하기
새 포토필터는 먼저 sRGB 채널값을 선형 값으로 바꿉니다. 어두운 값은 나누기로, 나머지는 거듭제곱으로 처리하는 구간별 변환입니다. 필터색에도 같은 변환을 적용합니다.
const linear = s => s <= 0.04045
? s / 12.92
: ((s + 0.055) / 1.055) ** 2.4;필터색을 XYZ 변환 행렬에 넣어 세 축의 반응을 구하고, 농도에 따라 변화량을 정합니다. 이 값을 다시 RGB로 돌아오는 행렬과 곱해 3 × 3 변환 행렬을 만듭니다. 픽셀마다 이 행렬을 적용한 뒤 sRGB로 돌아옵니다.
색 공간 변환에는 코드에 정의한 고정 행렬을 사용합니다. 모든 ICC 프로파일을 읽어 처리하는 색 관리 시스템이나 실제 렌즈 필터의 분광 특성을 재현한 모델은 아닙니다.
- 선형 RGB로 변환사진의 채널값과 필터색을 같은 기준으로 바꿉니다.
- 농도로 행렬 구성XYZ 축별 반응과 농도를 반영해 변환 행렬을 구합니다.
- 픽셀에 행렬 적용입력 R·G·B를 함께 사용해 출력 세 채널을 계산합니다.
- sRGB로 복귀화면에 표시할 채널값으로 되돌립니다.
명도 유지는 색상 혼합으로 처리합니다
행렬을 적용한 결과에 명도 유지 옵션이 켜져 있으면 color 혼합 함수를 호출합니다. 원본의 밝기 기준에 맞춰 필터 결과를 조정하는 단계입니다.
if (v.preserve) {
scratch[0] = r;
scratch[1] = g;
scratch[2] = b;
blendRGB(scratch, out, 'color', out);
}이 혼합 함수에서 밝기는 0.3R + 0.59G + 0.11B로 구합니다. 필터 결과가 원본과 같은 기준 밝기를 갖도록 채널을 이동하고, 허용 범위를 넘는 색은 다시 조정합니다. 단순히 세 채널을 개별적으로 잘라내는 것과는 다릅니다.
검정 픽셀은 행렬을 통과해도 검정입니다. 일정한 주황색을 RGB에 더하는 방식과 비교할 때 이 차이를 바로 확인할 수 있습니다.
농도 55와 불투명도 85%를 곱하면 될까
농도와 레이어 불투명도는 적용되는 위치가 다릅니다. 농도는 색 변환 행렬을 만들 때 들어가고, 불투명도는 필터 결과와 원본을 마지막에 섞을 때 사용합니다.
amount = opacity * maskAlpha;
result = before + (filtered - before) * amount;위 코드는 표준 혼합의 마지막 단계를 간단히 정리한 것입니다. 마스크가 없으면 maskAlpha는 1입니다. 원본에 변화량의 85%를 더하는 계산과, 농도를 55 × 0.85 = 46.75로 바꿔 처음부터 처리하는 계산은 일반적으로 다릅니다.
색 공간 변환과 범위 제한, 명도 유지가 중간에 들어가기 때문입니다. 표는 같은 입력을 두 방식으로 처리한 결과입니다. 아주 가까운 값이 나올 수 있지만 서로 같은 설정은 아닙니다.
| 입력 RGB | 55 / 85% | 46.75 / 100% |
|---|---|---|
| 128 · 128 · 128 | 143 · 123 · 113 | 142 · 123 · 114 |
| 170 · 130 · 110 | 180 · 127 · 101 | 179 · 127 · 102 |
| 40 · 85 · 155 | 69 · 76 · 124 | 69 · 76 · 125 |
필터색은 설정, 픽셀 계산은 엔진에 두기
필터 목록은 adjustment-presets.ts, 색 변환은 adjustments.ts, 명도 유지에 쓰는 혼합은 blend.ts에 나눠 두었습니다. 새 필터 이름과 색을 추가할 때 픽셀 계산을 새로 작성할 필요가 없습니다.
예전 파일에서는 RGB를 필터색과 직접 섞는 계산을 사용합니다. 새 방식과 구분하는 기준은 revision입니다. 같은 농도라도 계산 경로가 달라지므로, 저장한 파일의 결과를 유지하려면 이 구분이 필요합니다.
Adobe 문서는 필터색·농도·명도 유지의 기능을 설명하는 참고 자료로 사용했습니다. 위의 행렬과 혼합 코드는 포토샷 저장소의 실제 구현입니다. 설명용 표본도 그 코드를 실행해 만들었습니다.
| 파일 | 담당하는 부분 |
|---|---|
| adjustment-presets.ts | 필터 이름과 HEX 색상 |
| adjustments.ts | 행렬 구성과 픽셀 변환 |
| blend.ts | 색상 혼합과 밝기 기준 |
| adjustPixels | 레이어 불투명도·마스크 합성 |
구현 코드와 참고 자료
- 포토필터 변환 행렬 구성
Photoshot v0.16.0 · 실제 구현과 테스트 - 선형 RGB 변환과 명도 유지
Photoshot v0.16.0 · 실제 구현과 테스트 - 색상 혼합과 밝기 계산
Photoshot v0.16.0 · 실제 구현과 테스트 - 이름별 필터 색상 목록
Photoshot v0.16.0 · 실제 구현과 테스트 - Adobe · Photo Filter의 필터색, 농도, 명도 유지
기능 의미를 비교하기 위한 참고 문서입니다. Adobe의 내부 구현 코드 출처는 아닙니다.
