← Photoshot · 사용법과 개발기↗편집기 열기
Photoshot / Development02

무료 포토샵 개발기 2편: GitHub의 Konva 코드를 읽고 밝기·대비 고치기

무료 포토샵의 밝기·대비는 GitHub 검색에서 출발했다. Konva의 실제 필터 코드를 읽고 AI와 포토샷용 계산을 작성했지만, 슬라이더가 움직이는 것만으로 결과까지 맞지는 않았다. 참고 코드, 직접 구현, 측정 후 수정이라는 세 단계를 코드로 남긴다.

출처 대조 · 원고 갱신 2026.10.16

원고 읽기 ↓
보정 전
보정 전 / PORTRAIT STUDY 02
실제 포토샷 편집 화면 · 2026.10.13
실제 포토샷 편집 화면 · 2026.10.13
BUILD LOG / 01

먼저 Konva의 Contrast.ts를 열었다

2026년 9월 18일 개발 기록에는 konvajs/konva의 src/filters/Contrast.ts를 실제로 조회한 흔적이 있다. 이 파일은 픽셀 배열을 순회하며 RGB를 정규화하고 중간값을 기준으로 대비를 바꾼다. 공개 구현은 계산이 어디서 시작되고 끝나는지 읽을 수 있는 출발점이었다.

Konva 필터를 포토샷에 그대로 설치한 것은 아니다. 개발 기록에서 확인되는 것은 소스 조회와 별도 구현이다. 그래서 원고에서도 “Konva 코드를 참고했다”와 “Konva 코드를 복사했다”를 같은 말로 쓰지 않는다.

BUILD LOG / 02

AI와 처음 작성한 포토샷 계산

아래는 v0.16.0에 호환성용으로 남아 있는 이전 계산이다. 밝기를 먼저 적용하고, 대비를 0.5 중심으로 조절한다. Konva에서 중간값 중심의 계산을 읽었지만, 밝기 처리와 대비 계수는 포토샷 쪽에서 작성한 식이다.

외부 구현을 읽는 것은 답안을 얻는 일이 아니라, 무엇을 입력받고 어떻게 픽셀을 바꾸는지 파악하는 일이었다. 실제 편집기에는 조정값 저장, 마스크, 불투명도, 재렌더링을 함께 연결해야 했다.

코드 발췌 · src/adjustments.ts · v0.16.0 · L506–510 ↗
if (t === 'brightness' && a.revision !== 2) {
  x = v.brightness < 0 ? x * (1 + v.brightness / 100) : x + ((1 - x) * v.brightness) / 100;
  const contrast = v.contrast < 0 ? 1 + v.contrast / 100 : 1 / (1 - v.contrast / 101);
  x = (x - 0.5) * contrast + 0.5;
}
BUILD LOG / 03

비교 결과를 보고 계산을 바꿨다

9월 25일에는 Photoshop 27.3.1의 테스트 차트 출력과 비교했다. 밝기 +30·대비 +20 조건에서 당시 개선 작업 중간 버전은 채널 값 차이 평균 약 11.505, 최대 25였다. 이 수치는 9월 18일 최초 구현을 직접 측정한 값이 아니라, 9월 25일 비교 기록의 개선 전 상태다.

이후 측정한 응답 데이터를 sampleResponse로 읽는 방식으로 수정했다. 현재 revision 2의 일반 모드는 아래 두 줄로 밝기 응답과 대비 응답을 순서대로 적용한다. 외부 저장소의 공식을 옮기는 단계에서, 우리 비교 결과에 맞춰 코드를 수정하는 단계로 넘어간 것이다.

코드 발췌 · src/adjustments.ts · v0.16.0 · L517–518 ↗
x = sampleResponse(toneResponse.brightness, v.brightness, -150, x);
x = sampleResponse(toneResponse.contrast, v.contrast, -50, x);
BUILD LOG / 04

한 번 계산해 256칸 표로 재사용하기

조정 슬라이더가 바뀔 때마다 모든 픽셀에 복잡한 계산을 반복할 필요는 없었다. RGB 각 채널의 0~255 입력에 대응하는 결과를 미리 만들어 두고 픽셀 처리에서 재사용한다. 이것이 LUT, 즉 조회표다. 아래는 포토샷의 compileAdjustment 내부 코드다.

AI가 작성한 밝기 계산을 이 공통 경로에 넣으면서, 뒤이어 구현할 레벨·곡선·노출도 같은 구조를 사용할 수 있게 됐다. GitHub 자료에서 찾은 계산 아이디어를 서비스 안에서 재사용 가능한 코드로 묶는 과정이었다.

코드 발췌 · src/adjustments.ts · v0.16.0 · L503–505 ↗
const tables = ['r', 'g', 'b'].map((channel) =>
  Float64Array.from({ length: 256 }, (_, i) => {
    let x = i / 255;
BUILD LOG / 05

사진 예시와 수치 검증은 별개다

사진 예시는 밝기 18·대비 12로 만든 실제 포토샷 결과다. 비교표의 +30·+20 테스트와 설정이 다르다. 인물 원본은 AI 생성 예시 이미지이며, 화면 캡처와 보정 결과는 실제 편집기에서 얻었다.

기록된 +30·+20 테스트는 수정 후 평균 차이 약 0.241, 최대 1로 줄었다. 순서를 대비→밝기로 뒤집으면 평균 약 1.150, 최대 4였다. 같은 숫자 두 개라도 적용 순서가 결과에 영향을 준다는 점까지 확인했다.

보정 전 · AI 생성 예시 인물 이미지
보정 전 · AI 생성 예시 인물 이미지
보정 후 · 실제 포토샷 출력
보정 후 · 실제 포토샷 출력
BUILD LOG / 06

GitHub 참고에서 우리 코드의 검증까지

이번 편의 출처는 명확하다. Konva Contrast.ts는 읽고 참고한 외부 코드, adjustments.ts와 응답 데이터 연결은 AI와 작성·수정한 포토샷 코드다. 무료 포토샵 개발은 좋은 공개 구현을 찾는 일과, 그것을 우리 구조에 맞게 연결하고 검증하는 일이 함께 진행됐다.

위 수치는 특정 차트와 설정의 과거 비교 결과다. 모든 사진이나 모든 Photoshop 모드가 동일하다는 뜻은 아니다. 다음 편은 이 공통 조정 경로에 레벨과 히스토그램을 연결한 기록이다.

구현과 참고 자료

모든 사용법·개발기 보기 ↗↗직접 편집해 보기