블로그를 도트 스타일로 바꾸고 나니 사진도 같은 분위기로 만들고 싶었습니다. 복잡한 편집 도구 대신 이미지를 올리고 분위기 하나만 고르면 바로 저장할 수 있는 간단한 변환기로 정리했습니다.
사진은 기기 안에서만
사진은 서버로 보내지 않고 브라우저 안에서 바로 처리합니다. 개인 사진을 올릴 때 괜히 신경 쓰이는 부분이 없고, 결과를 기다릴 필요도 없습니다. 파일 선택뿐 아니라 끌어다 놓기와 붙여넣기도 됩니다.
컨셉 하나만 고르기
같은 사진도 어떤 컨셉을 고르느냐에 따라 분위기가 달라집니다.
- 인물은 표정과 피부의 명암을 비교적 부드럽게 남깁니다.
- 풍경은 색과 작은 윤곽을 더 선명하게 표현합니다.
- 레트로는 제한된 색과 거친 무늬로 8비트 게임 같은 느낌을 냅니다.
- 클린은 거친 무늬를 줄여 매끈한 도트 그림으로 만듭니다.
컨셉 안에는 픽셀 크기와 색 수, 색감과 무늬 설정이 미리 들어 있습니다. 세부 값을 따로 만질 필요 없이 컨셉을 바꾸면서 결과만 비교하면 됩니다.
변환은 어떤 순서로 이루어질까
이 도구는 이미지를 새로 그리는 생성형 AI가 아니라, 선택한 사진의 픽셀을 정해진 순서로 바꾸는 이미지 처리 도구입니다.
- 사진의 방향 정보를 반영해 브라우저에서 이미지를 엽니다.
- 고른 컨셉이 픽셀 폭, 축소 방식, 색 수, 색감과 디더링 방식을 한꺼번에 정합니다. 현재 도구는 원본의 전체 화면 비율을 유지하며 별도 자르기는 하지 않습니다.
- 컨셉에 정해진 픽셀 폭까지 이미지를 줄여 큰 색 덩어리와 계단 모양 경계를 만듭니다.
- 컨셉에 들어 있는 밝기·대비·채도·감마와 선명도 값을 적용합니다.
- 자동으로 뽑은 색 또는 준비된 팔레트에서 각 픽셀과 가까운 색을 고릅니다.
- 인물·풍경·레트로 컨셉은 정해진 디더링을 적용하고, 클린 컨셉은 디더링을 끈 채 제한된 색으로 마무리합니다.
색을 고를 때는 RGB 숫자의 단순한 차이 대신 사람의 색 지각에 더 가깝게 거리를 비교하기 위해 OKLab 색공간으로 바꿔 최근접 색을 찾습니다. 인물 컨셉은 색 변화가 거칠어지지 않도록 디더링 강도를 낮추고, 레트로 컨셉은 제한된 팔레트와 규칙적인 무늬를 더 강하게 적용합니다.
결과가 마음에 들지 않을 때 바꿀 순서
현재 화면은 여러 수치를 따로 조절하는 편집기가 아니라 네 가지 컨셉을 빠르게 비교하는 도구입니다. 다음 순서로 고르면 편합니다.
- 사진 전체가 그대로 들어가므로, 남길 영역이 따로 있다면 기기의 사진 앱에서 먼저 잘라 둡니다.
- 얼굴이나 글자 윤곽이 사라지면 비교적 촘촘한 인물 또는 풍경을 고릅니다.
- 제한된 게임 색감과 규칙적인 점무늬가 필요하면 레트로를 고릅니다.
- 점무늬가 산만하면 디더링을 쓰지 않는 클린과 비교합니다.
- 네 결과 중 원본의 중요한 윤곽과 원하는 분위기가 함께 남는 것을 저장합니다.
예를 들어 얼굴 사진에서 눈과 입이 사라졌다면 64칸을 쓰는 레트로보다 128칸을 쓰는 인물 컨셉이 유리합니다. 원본 정보를 너무 일찍 줄였다면 뒤 단계의 선명도 처리로 그 윤곽을 복원할 수 없기 때문입니다. 반대로 작은 아이콘은 디더링을 끄는 클린 컨셉에서 경계가 더 또렷할 수 있습니다.
얼마나 많은 픽셀을 다루는 걸까
"브라우저에서 처리한다"는 말이 가벼워 보이지만, 숫자로 보면 만만치 않습니다. 사진 한 장이 몇 개의 점으로 이루어져 있는지부터 보겠습니다.
| 사진 | 픽셀 수 | 메모리에 펼쳤을 때 |
|---|---|---|
| FHD 화면 크기 (1920×1080) | 207만 | 약 7.9 MB |
| 스마트폰 12MP (4032×3024) | 1,219만 | 약 46.5 MB |
| DSLR 24MP (6000×4000) | 2,400만 | 약 91.6 MB |
가운데 줄을 보세요. 요즘 폰으로 찍은 사진 한 장을 브라우저가 다루려면 픽셀 1,200만 개를 만지게 됩니다. 색을 RGBA 4바이트로 펼치면 46MB짜리 배열입니다. JPG 파일이 3MB였더라도, 압축을 풀면 이만큼이 됩니다.
픽셀화는 이 숫자를 확 줄이는 일입니다
변환 결과는 반대로 아주 작습니다. 가로를 몇 칸으로 줄이느냐에 따라 이렇게 갈립니다.
| 가로 칸 수 | 만들어지는 블록 | 블록 하나가 평균적으로 삼키는 원본 픽셀 |
|---|---|---|
| 64칸 | 4,096개 | 약 2,976개 |
| 128칸 | 16,384개 | 약 744개 |
| 256칸 | 65,536개 | 약 186개 |
블록 하나가 원본 픽셀 수천 개를 대표합니다. 그래서 픽셀 아트로 바꾸면 원본의 세밀한 무늬가 사라지는 것이고, 반대로 칸을 늘릴수록 "픽셀 느낌"이 옅어집니다.
이 표는 앞에서 말한 "칸 수를 먼저 조절하라"는 조언의 근거이기도 합니다. 칸 수를 두 배로 늘리면 블록은 네 배가 되고, 블록당 삼키는 원본 픽셀은 4분의 1로 줄어듭니다.
화면이 멈추지 않도록
팔레트 추출과 디더링은 사진의 모든 픽셀을 여러 번 살펴볼 수 있는 작업입니다. 설정을 움직일 때마다 메인 화면에서 바로 계산하면 버튼과 비교 슬라이더가 버벅일 수 있습니다. 그래서 실제 색 변환은 Web Worker로 분리해 실행하고, Worker를 쓸 수 없는 브라우저에서만 같은 계산을 화면 스레드에서 처리합니다.
미리보기는 작업량을 제한한 크기로 계산합니다. 저장할 때는 완성된 작은 픽셀 이미지를 보간 없이 정수 배로 확대하므로, PNG를 크게 열어도 픽셀 경계가 흐려지지 않습니다. 같은 사진과 같은 설정을 넣으면 같은 처리 순서를 거쳐 같은 결과가 나옵니다.
비교하고 바로 저장하기
원본과 결과는 가운데 선을 움직여 바로 비교할 수 있습니다. 마음에 드는 컨셉을 고른 뒤 PNG 저장을 누르면 확대해도 픽셀 경계가 흐려지지 않는 이미지로 저장됩니다. 사진과 변환 결과는 서버로 전송되지 않습니다.
위의 데모 열어보기에서 직접 사진을 바꿔볼 수 있습니다.
직접 변환해 보기
컨셉 선택
세부 설정 없이 사진에 맞는 분위기만 선택하면 됩니다.
데모만 따로 보려면 전체 화면으로 열기.
색을 몇 개까지 줄일 수 있을까
팔레트를 몇 색으로 잡을지는 취향처럼 보이지만 결과를 가장 크게 바꾸는 값입니다. 줄일수록 도트 그림다워지고, 어느 지점을 넘으면 알아볼 수 없게 됩니다.
경계가 되는 지점은 사진마다 다릅니다. 색이 단순한 그림은 8 색으로도 형태가 남지만, 얼굴처럼 밝기가 조금씩 이어지는 대상은 같은 색 수에서 계조가 뭉쳐 평평한 덩어리가 됩니다. 인물 컨셉이 다른 컨셉보다 색을 넉넉히 쓰는 이유가 이것입니다.
색을 줄였을 때 생기는 문제를 덜어 주는 것이 디더링입니다. 팔레트에 없는 중간색을 두 색의 점을 섞어 흉내 내는 방식이라, 멀리서 보면 없는 색이 있는 것처럼 보입니다. 대신 가까이서 보면 규칙적인 무늬가 남습니다. 레트로한 느낌은 대부분 이 무늬에서 나옵니다.
그래서 조절 순서를 이렇게 잡으면 실패가 줄어듭니다. 먼저 색 수를 형태가 남는 최소까지 줄이고, 그다음에 디더링으로 부족한 계조를 메우고, 마지막에 격자 크기를 정합니다. 세 값을 동시에 만지면 어느 것 때문에 나빠졌는지 알 수 없게 됩니다.
개인정보와 한계
선택한 파일, 미리보기와 변환 결과는 모두 현재 브라우저 메모리와 Canvas에서 처리합니다. 업로드 API를 호출하지 않으며 새로고침하거나 탭을 닫으면 작업 중인 이미지는 사라집니다. 저장 버튼을 누른 결과만 사용자의 기기에 PNG로 내려갑니다.
아주 큰 사진은 기기 메모리와 브라우저 성능에 따라 여는 데 시간이 걸리거나 실패할 수 있습니다. 도구는 사진의 의미를 이해하지 않으므로 얼굴, 글자, 가는 선을 자동으로 복원하지도 않습니다. 중요한 윤곽이 사라지면 인물·풍경 컨셉을 먼저 비교하고, 네 컨셉 모두 맞지 않으면 원본을 미리 자르거나 더 단순한 사진을 쓰는 편이 낫습니다.