
무료 포토샵 개발기
노출 계산의 재설계
앞선 기능에서 마련한 조정 레이어와 조회표는 노출 기능에서도 재사용할 수 있었다. 무료 포토샵 개발에서 AI의 역할은 새 필터를 매번 따로 만드는 데 있지 않았다. 알려진 색 변환과 EV 계산을 기존 엔진에 연결하고, 새 계산과 예전 문서가 함께 동작하도록 코드를 수정하는 데 있었다.
AI 생성 시연용 사진. 편집 화면과 출력 이미지는 실제 포토샷에서 만들었습니다.
출처에서 시작하다.
한 번 연결한 코드는 다음 기능의 기반이 된다
흩어진 코드를 한 제품으로 묶으면 그 결과도 다시 재사용할 수 있는 기반이 된다. 노출 기능은 특정 외부 패키지를 새로 붙인 사례가 아니라, 앞선 GitHub 참고 작업과 자체 구현으로 마련한 엔진에 기능을 더한 사례다.
앞선 편에서는 Konva와 glfx.js의 실제 구현을 참고했다. 노출 편에서 확인되는 연결점은 그 과정을 거쳐 만든 포토샷의 compileAdjustment다. 아래 조건에 brightness, levels, curves와 함께 exposure가 들어 있다.
노출용 편집기를 처음부터 따로 만든 것이 아니라, 이미 있는 조정 레이어·조회표·마스크 흐름에 노출 계산을 추가했다. 외부 자료를 읽어 만든 기반 위에 AI가 작성한 새 코드를 조합하는 방식이 이어진 것이다.
처음에는 sRGB 변환을 거쳤다
화면에 저장되는 채널 값에 EV를 단순히 더하는 것으로는 노출을 설명할 수 없었다. 초기 경로에는 sRGB 값을 선형 공간으로 바꾸는 linear와 다시 화면 값으로 돌리는 srgb 함수가 들어갔다.
아래 두 함수는 포토샷 코드의 발췌다. 표준 색 변환식을 TypeScript로 표현한 것으로, 특정 GitHub 저장소에서 이 두 줄을 복사했다는 기록은 확인되지 않았다. AI가 새 코드를 작성했다는 말과 수학적 원리 자체를 발명했다는 말도 구분할 필요가 있다.
이미 있는 조정값 저장과 합성 흐름을 이용하면 새로 작성할 범위는 노출 계산과 그 연결에 집중된다. AI와 하는 개발이 효율적일 수 있는 이유도 이처럼 누적된 코드를 매번 다시 만들지 않고 확장할 수 있기 때문이다.
L493–493포토샷 구현 코드 ↗
if (['brightness', 'levels', 'curves', 'exposure', 'invert', 'posterize'].includes(t)) {L503–505포토샷 구현 코드 ↗
const tables = ['r', 'g', 'b'].map((channel) =>
Float64Array.from({ length: 256 }, (_, i) => {
let x = i / 255;L482–483포토샷 구현 코드 ↗
const linear = (s: number) => (s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4);
const srgb = (s: number) => (s <= 0.0031308 ? 12.92 * s : 1.055 * s ** (1 / 2.4) - 0.055);계산의
안쪽으로.
AI와 고친 노출·오프셋·감마 계산
핵심은 2 ** v.ev다. EV가 1이면 선형 쪽 값은 두 배, -1이면 절반이 된다. 이후 오프셋과 감마를 적용한다. 다만 어느 변환 공간에서 어떤 순서로 계산하느냐에 따라 결과는 달라진다.
비교 작업을 거친 revision 2는 2.2 거듭제곱 경로를 사용한다. 이전 작업은 기존 linear/srgb 경로를 유지한다. 아래 분기는 새 계산과 이전 계산이 같은 함수 안에 함께 남아 있는 실제 코드다.
좋아진 계산이 예전 작업을 바꾸지 않도록
계산을 고치는 것보다 까다로운 부분은 저장된 작업의 의미를 지키는 일이었다. 기존 조정 레이어를 읽었는데 갑자기 새 계산이 적용되면, 사용자는 아무것도 바꾸지 않았는데 사진의 색이 달라진다.
revision 분기는 이를 막기 위한 호환 규칙이다. 곡선 편에서 했던 선택이 노출에도 이어진다. AI에게 새 함수를 작성하게 한 뒤 끝내는 대신, 이전 데이터가 어떤 경로로 돌아가야 하는지까지 기존 코드와 함께 수정했다.
코드를 읽다.
L536–540포토샷 구현 코드 ↗
if (t === 'exposure')
x =
a.revision === 2
? clamp(x ** 2.2 * 2 ** v.ev + v.offset) ** (1 / (2.2 * v.gamma))
: srgb(clamp(linear(x) * 2 ** v.ev + v.offset) ** (1 / v.gamma));편집 화면에서.

노출 테스트와 사진 결과
사진 예시의 설정은 EV +0.35, 오프셋 -0.004, 감마 1.05다. 아래 실제 화면과 결과는 이 설정으로 만들었다. 인물 원본은 AI 생성 예시 이미지다.
과거 Photoshop 비교 차트에서 +1 / 0 / 1은 평균 차이 약 0.015, 최대 2였다. -0.7 / 0.015 / 1.2는 평균 약 0.015, 최대 1이었다. 이는 기록된 두 조건의 결과다. 사진 예시와 설정을 섞거나 모든 HDR·색 관리 상황에 같은 수치를 적용하지 않는다.
사진으로 보는 결과.


1~5편은 코드를 찾아 연결하고 고친 기록
무료 포토샵 개발의 첫 다섯 편을 관통하는 방식은 같다. React·초기 PixiJS처럼 실제로 가져다 쓴 기반이 있고, Konva·glfx.js처럼 소스를 읽고 설계에 참고한 구현이 있다. 그 사이를 AI와 작성한 문서·레이어·계산·UI 코드로 연결하고 비교 결과에 따라 다시 고쳤다.
1~5편이 보여주는 변화는 개별 편집 기술의 갑작스러운 탄생이 아니다. 기존 라이브러리와 공개 구현, 알려진 계산법을 연결해 기반을 만들고, AI와 그 기반을 확장한 것이다. 기능이 늘어날수록 공통 코드를 재사용할 수 있다는 점이 대체 편집기를 만드는 현실적인 경로가 된다.
노출 편은 그 조합이 한 기능에서 끝나지 않고 다음 기능의 기반이 되는 모습을 보여준다. 본문 코드는 공개 v0.16.0 기준이며, 출처와 검증 범위를 남겨 어느 부분을 재사용하고 어느 부분을 작성했는지 다시 따라갈 수 있게 했다.