SLOHERO
09

PHOTOSHOT / DEVELOPMENT JOURNAL

따뜻한 색을 더하는
필터의 계산 순서

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

조정 레이어 09 · 포토필터
2026.10.01 · SLOHERO · 공개 코드 v0.16.0 기준
보정 전포토필터 보정 전 AI 생성 인물 예시
보정 후포토필터 보정 후 AI 생성 인물 예시
사진과 패널은 기존 릴스 제작 자료입니다. AI 생성 인물 사진을 사용했으며, 계산 도표와 수치는 공개 코드 v0.16.0을 별도로 실행해 확인했습니다.

09편에서는 같은 필터의 강도를 조절하는 두 숫자를 비교합니다. 농도를 낮추는 것과 레이어를 투명하게 만드는 것이 왜 다른지, 픽셀 세 개로 확인해 봅니다.

  1. 01필터색·농도·명도 유지 저장하기
  2. 02화면의 RGB를 변환한 뒤 행렬 적용하기
  3. 03명도 유지는 색상 혼합으로 처리합니다
  4. 04농도 55와 불투명도 85%를 곱하면 될까
  5. 05필터색은 설정, 픽셀 계산은 엔진에 두기
01

필터색·농도·명도 유지 저장하기

릴스에서는 Warming (85)에 해당하는 색 #ec8a00을 사용했습니다. 농도를 35에서 55로 올린 뒤, 레이어 불투명도를 85%로 낮춰 마무리했습니다. 명도 유지는 켜 두었습니다.

필터 목록은 이름과 HEX 색상값을 연결한 배열입니다. 목록에서 고르면 색상값이 레이어에 저장되고, 사용자가 직접 색을 골라도 같은 계산을 거칩니다. 화면에 ‘사용자 정의 색상’이라고 보여도 저장된 필터색은 유지됩니다.

농도는 0~100, 기본값은 25입니다. 이름이 붙은 필터와 직접 고른 색을 구분해 서로 다른 알고리즘을 적용하는 구조는 아닙니다.

필터 이름과 색상값 목록 확인 ↗

농도55 명도 유지 켬 주황색 포토필터 조작 패널
실제 조작 화면 · 최종 사진에는 패널의 농도 55와 별도로 레이어 불투명도 85%가 적용되어 있습니다.
02

화면의 RGB를 변환한 뒤 행렬 적용하기

새 포토필터는 먼저 sRGB 채널값을 선형 값으로 바꿉니다. 어두운 값은 나누기로, 나머지는 거듭제곱으로 처리하는 구간별 변환입니다. 필터색에도 같은 변환을 적용합니다.

const linear = s => s <= 0.04045
  ? s / 12.92
  : ((s + 0.055) / 1.055) ** 2.4;

필터색을 XYZ 변환 행렬에 넣어 세 축의 반응을 구하고, 농도에 따라 변화량을 정합니다. 이 값을 다시 RGB로 돌아오는 행렬과 곱해 3 × 3 변환 행렬을 만듭니다. 픽셀마다 이 행렬을 적용한 뒤 sRGB로 돌아옵니다.

색 공간 변환에는 코드에 정의한 고정 행렬을 사용합니다. 모든 ICC 프로파일을 읽어 처리하는 색 관리 시스템이나 실제 렌즈 필터의 분광 특성을 재현한 모델은 아닙니다.

  1. 선형 RGB로 변환사진의 채널값과 필터색을 같은 기준으로 바꿉니다.
  2. 농도로 행렬 구성XYZ 축별 반응과 농도를 반영해 변환 행렬을 구합니다.
  3. 픽셀에 행렬 적용입력 R·G·B를 함께 사용해 출력 세 채널을 계산합니다.
  4. sRGB로 복귀화면에 표시할 채널값으로 되돌립니다.
03

명도 유지는 색상 혼합으로 처리합니다

행렬을 적용한 결과에 명도 유지 옵션이 켜져 있으면 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에 더하는 방식과 비교할 때 이 차이를 바로 확인할 수 있습니다.

포토필터 적용 전후와 불투명도85퍼센트 RGB 비교
필터색 #ec8a00 · 명도 유지 켬. 가운데는 농도 55, 오른쪽은 그 레이어의 불투명도를 85%로 적용한 결과입니다.
04

농도 55와 불투명도 85%를 곱하면 될까

농도와 레이어 불투명도는 적용되는 위치가 다릅니다. 농도는 색 변환 행렬을 만들 때 들어가고, 불투명도는 필터 결과와 원본을 마지막에 섞을 때 사용합니다.

amount = opacity * maskAlpha;
result = before + (filtered - before) * amount;

위 코드는 표준 혼합의 마지막 단계를 간단히 정리한 것입니다. 마스크가 없으면 maskAlpha는 1입니다. 원본에 변화량의 85%를 더하는 계산과, 농도를 55 × 0.85 = 46.75로 바꿔 처음부터 처리하는 계산은 일반적으로 다릅니다.

색 공간 변환과 범위 제한, 명도 유지가 중간에 들어가기 때문입니다. 표는 같은 입력을 두 방식으로 처리한 결과입니다. 아주 가까운 값이 나올 수 있지만 서로 같은 설정은 아닙니다.

왼쪽 결과는 농도 55·불투명도 85%, 오른쪽은 농도 46.75·불투명도 100%. 표의 RGB는 정수로 반올림했습니다.
입력 RGB55 / 85%46.75 / 100%
128 · 128 · 128143 · 123 · 113142 · 123 · 114
170 · 130 · 110180 · 127 · 101179 · 127 · 102
40 · 85 · 15569 · 76 · 12469 · 76 · 125
05

필터색은 설정, 픽셀 계산은 엔진에 두기

필터 목록은 adjustment-presets.ts, 색 변환은 adjustments.ts, 명도 유지에 쓰는 혼합은 blend.ts에 나눠 두었습니다. 새 필터 이름과 색을 추가할 때 픽셀 계산을 새로 작성할 필요가 없습니다.

예전 파일에서는 RGB를 필터색과 직접 섞는 계산을 사용합니다. 새 방식과 구분하는 기준은 revision입니다. 같은 농도라도 계산 경로가 달라지므로, 저장한 파일의 결과를 유지하려면 이 구분이 필요합니다.

Adobe 문서는 필터색·농도·명도 유지의 기능을 설명하는 참고 자료로 사용했습니다. 위의 행렬과 혼합 코드는 포토샷 저장소의 실제 구현입니다. 설명용 표본도 그 코드를 실행해 만들었습니다.

각 역할을 분리해 필터 목록과 계산 구현을 따로 확인할 수 있습니다.
파일담당하는 부분
adjustment-presets.ts필터 이름과 HEX 색상
adjustments.ts행렬 구성과 픽셀 변환
blend.ts색상 혼합과 밝기 기준
adjustPixels레이어 불투명도·마스크 합성

구현 코드와 참고 자료

공개 코드는 구현을 설명하기 위한 참조입니다. 사용·배포 조건은 저장소의 라이선스 표기를 확인하세요. 사진·패널은 자체 제작 자료, 장식 이미지는 AI 생성 이미지입니다.