# 이미지를 데이터 URI로 — CSS나 HTML에 넣을 base64 인코딩

사진 전체를 텍스트 한 줄로. CSS나 HTML에 그대로 붙여 넣으세요.

> PNG, JPEG, SVG, WebP를 CSS나 HTML에 붙여 넣을 데이터 URI로 바꿉니다. SVG는 base64 대신 퍼센트 인코딩해서 읽을 수 있고 더 짧습니다. 브라우저에서 돌아가고 아무것도 업로드하지 않습니다.

이 페이지는 브라우저 안에서만 동작하는 대화형 도구입니다(https://abox.tools/ko/이미지-base64-변환/). 도구에 넘긴 어떤 것도 업로드되지 않습니다. 아래는 이 페이지가 도구에 대해 글로 설명하는 내용 전부입니다. 도구를 쓰려면 이 주소를 여세요.

## 이미지 파일은 **절대 업로드되지 않습니다**. 서버가 아예 없으니까요.

인코딩은 내 브라우저가 내 기기의 성능으로 합니다. 페이지가 이미 손에 쥔 바이트를 두고 하는 산술일 뿐이에요. 인코더도, 서버도, 빼놓을 네트워크 단계도 없습니다. 이 도구에는 네트워크 기능이 하나도 없어서 가져올 것도 보낼 것도 없고, 설령 보내려 해도 이 페이지 반대편에는 사진을 받아 줄 서버 자체가 없습니다.

- ✗ 업로드 없음
- ✗ 가입 없음
- ✗ 다시 인코딩하지 않음
- ✓ 오프라인 동작
- ✓ 오픈 소스

## 이미지를 데이터 URI로 바꾸는 방법

1. **이미지를 고릅니다.** 선택 영역에 끌어다 놓거나 직접 골라 주세요. 브라우저가 디스크에서 곧바로 읽습니다. 그동안 어디로도 아무것도 나가지 않습니다.
2. **결과가 어디로 갈지 말합니다.** URI만, CSS 규칙, 사용자 지정 속성, `<img>` 태그, 아니면 마크다운. 어느 쪽이든 URI에 따옴표를 제대로 씌워 줍니다. 인라인 SVG가 동작하느냐 조용히 실패하느냐를 가르는 것이 바로 그 세부니까요.
3. **대가를 읽습니다.** 결과마다 몇 글자가 되었는지, 파일보다 얼마나 커졌는지, 이만한 크기를 인라인으로 넣는 것이 좋은 생각인지가 적힙니다. base64는 3분의 1을 더합니다. 그 3분의 1이 요청 하나를 아낄 값어치가 있는지는 전적으로 크기에 달렸고, 그래서 지금 어느 쪽에 서 있는지를 페이지가 말해 줍니다.
4. **경고를 확인합니다.** 사진에 EXIF나 색 프로파일, XMP가 들어 있으면 그것이 결과의 몇 바이트를 차지하는지와 함께 이름이 적힙니다. 확장자가 실제 형식과 다르면 페이지는 형식을 따르고 그 사실을 알려 줍니다. 브라우저가 결과를 그리지 못해도 그렇다고 말합니다.
5. **복사하거나 내려받습니다.** 결과마다 버튼이 하나씩 있고, 전부 한 번에 처리하는 버튼도 있습니다. 사용자 지정 속성은 `:root` 블록에 싸여 나오니 스타일시트 맨 위에 바로 붙여 넣으시면 됩니다.

## 자세한 설명

[스타일시트 안에 그림을 넣어야 할 때와 넣지 말아야 할 때](https://abox.tools/ko/가이드/css-이미지-넣기/): 데이터 URI의 대가, base64가 3분의 1을 더하는데 gzip이 그것을 돌려주지 않는 이유, SVG를 절대 base64로 만들면 안 되는 이유, 그리고 인라인 SVG를 조용히 망가뜨리는 따옴표 실수.

## 상자 속 다른 도구

- [SVG를 이미지로](https://abox.tools/ko/svg-png-변환/): 크기를 말하세요. 벡터에는 잃어버릴 자기 크기가 없습니다.
- [이미지를 SVG로](https://abox.tools/ko/이미지-svg-변환/): 형태 하나, 윤곽선 하나. 있으면 안 되는 것은 가리키기만 하세요.
- [키 비교 차트](https://abox.tools/ko/키-비교/): 키를 적으면 그림을 가져갑니다. 그리려고 어디로도 보내지 않습니다.
- [이미지 압축](https://abox.tools/ko/이미지-압축/): 용량만 말씀하세요. 나머지는 알아서 맞춥니다.

## 자주 묻는 질문

### 제 이미지가 어딘가로 업로드되나요?

아닙니다. 파일을 읽고 인코딩하는 일은 내 기기에서 도는 내 브라우저가 하고, 브라우저가 이미 갖고 있는 두 함수를 씁니다. 이 도구에는 네트워크 기능이 하나도 없어서 무언가를 가져오지도, 보내지도 않습니다. 이 페이지의 `Content-Security-Policy`에 연결해도 되는 주소가 전부 적혀 있는데, 그중 이 사이트 것은 하나도 없습니다.

### 데이터 URI가 무엇인가요?

보통 웹 주소가 들어갈 자리에 파일 전체를 적어 넣는 방법입니다. 브라우저더러 가서 가져오라고 시키는 `url("logo.png")` 대신, 사진 자체가 들어 있는 `url("data:image/png;base64,iVBORw0...")`를 씁니다. 브라우저가 그 자리에서 디코딩합니다. 실질적인 효과는 요청 하나가 줄어드는 것입니다. 사진이 스타일시트나 페이지 뒤가 아니라 그것과 함께 도착하니까요.

### 제 SVG는 왜 base64가 아닌가요?

base64가 SVG에는 맞지 않는 인코딩이기 때문입니다. SVG는 텍스트이고 URL은 이미 텍스트를 실어 나를 수 있습니다. 이스케이프해야 하는 문자도 몇 개뿐이고요. 그것만 퍼센트 인코딩하고 나머지를 그대로 두면 같은 파일을 base64로 만든 것보다 대개 5분의 1쯤 짧은 URI가 나오고, 스타일시트 안에서 여전히 읽을 수 있습니다. 요소 이름도, 색도, `viewBox`도 그대로 남아 고칠 수 있고요. base64를 고집하는 드문 도구 체인을 위해 강제로 base64를 쓰는 체크박스도 있습니다.

### base64를 쓰면 이미지가 얼마나 커지나요?

3분의 1쯤입니다. 파일 3바이트가 base64 4글자가 되니, 앞에 붙는 `data:image/png;base64,`를 빼고 33%입니다. 그게 바닥이고 피할 수 없습니다. URL이 허용하는 문자만으로 임의의 바이트를 적어 내는 비용이라 그렇습니다. 페이지가 파일 크기 옆에 글자 수를 나란히 보여 주는 것도 같은 이유입니다. 스타일시트를 배포하고 나서 알게 되는 일이 없도록요.

### 이미지를 인라인으로 넣는 게 실제로 좋은 경우는 언제인가요?

작고, 당장 필요할 때입니다. 모든 페이지가 불러오는 스타일시트에 들어간 2KB짜리 아이콘은 분명한 이득입니다. 왕복이 하나 줄고, CSS가 도착하는 순간 사진도 거기 있으니까요. 10KB쯤을 넘으면 손익이 뒤집힙니다. 인라인된 사진은 더 이상 별개의 파일이 아니라서 따로 캐시될 수 없고, 다른 것과 병렬로 받아 올 수도 없으며, 그것을 감싼 파일이 바뀔 때마다 통째로 다시 내려받습니다. 스타일시트 안의 200KB짜리 사진은 사이트 모든 페이지의 임계 경로에 200KB를 얹는 셈이에요. 각 결과가 그 선의 어느 쪽에 떨어지는지는 페이지가 말해 줍니다.

### gzip을 쓰면 base64가 더한 만큼이 상쇄되나요?

사람들이 기대하는 것보다는 훨씬 덜합니다. 이미 압축된 파일, 그러니까 PNG도 JPEG도 WebP도 다 그런데, 그런 파일의 base64는 잘 압축되지 않습니다. 압축기가 찾아낼 중복이 거의 남아 있지 않으니까요. 대개 base64가 더한 3분의 1 가운데 10분의 1쯤을 돌려받지, 전부를 돌려받지는 못합니다. 퍼센트 인코딩한 SVG는 반대입니다. 여전히 텍스트라서 예전만큼 잘 압축되고, 그것 또한 SVG를 base64로 만들지 않는 이유입니다.

### 이 과정에서 제 이미지가 조금이라도 바뀌나요?

아닙니다. 여기 있는 다른 도구들과 일부러 다르게 만든 점입니다. 픽셀로 디코딩했다가 다시 인코딩하는 일이 없습니다. 디스크에서 나온 바이트가 그대로 URI로 들어갑니다. JPEG는 화질도 크기도 그대로인 바로 그 JPEG로 남습니다. 결과를 사본이 아니라 같은 파일이라고 말할 수 있는 이유입니다.

### 그러면 EXIF와 GPS 정보도 스타일시트로 들어가나요?

들어갑니다. 붙여 넣기 전에 한 번 생각해 볼 대목이에요. 다시 인코딩하지 않으므로 카메라가 쓴 모든 것이 사진과 함께 갑니다. 위치, 촬영 시각, 카메라 일련번호까지요. 휴대폰 사진이라면 그것만 30KB가 되기도 하는데, base64로는 40KB가 되어 페이지의 임계 경로에 얹히고, 게다가 저장소에 커밋될 무언가에 집 주소가 들어갑니다. 이 페이지는 JPEG, PNG, WebP에 메타데이터가 얼마나 들었는지 읽어 알려 줍니다. 먼저 빼내려면 [EXIF 확인 및 제거](https://abox.tools/ko/exif-정보-삭제/)를 쓰세요.

### 왜 제 파일 확장자와 다른 타입을 썼나요?

확장자는 틀릴 수 있지만 바이트는 틀릴 수 없기 때문입니다. `logo.png`라는 이름으로 실제로는 JPEG로 내보낸 파일은 어느 이미지 도구든 감당해야 할 만큼 흔합니다. 그런데 타입을 잘못 적은 데이터 URI는 그냥 그려지지 않습니다. 대체 수단도 없고 읽어 볼 만한 오류 메시지도 없어요. 그래서 타입은 파일의 첫 몇 바이트에서 읽습니다. 여기서 다루는 모든 형식에서 그 바이트가 무엇인지를 분명히 말해 주고, 둘이 어긋나면 페이지가 알려 줍니다.

### 미리보기가 비어 있습니다. 무엇이 잘못됐나요?

URI 쪽은 아마 멀쩡합니다. HEIC와 TIFF는 완벽히 올바른 데이터 URI를 만들지만 Safari 말고는 어떤 브라우저도 그리지 않습니다. 그러니 붙여 넣는 곳에서도 사진은 보이지 않을 거예요. [이미지 압축](https://abox.tools/ko/이미지-압축/)이나 [이미지 크기 조절](https://abox.tools/ko/이미지-크기-조절/)로 먼저 PNG나 JPEG, WebP로 바꾸세요. 형식이 평범한 것이라면 파일 자체가 손상됐을 가능성이 큽니다. 미리보기는 이 페이지가 만든 URI에서 그려지므로, 비어 있다는 것은 사진이 디코딩되지 않았다는 뜻이니까요.

### 데이터 URI에 크기 제한이 있나요?

CSS나 `<img>` 태그에서 마주칠 만한 제한은 없습니다. 요즘 브라우저는 거기에 현실적인 상한을 두지 않습니다. 브라우저가 제한하는 것은 주소창에 데이터 URI를 입력하는 쪽인데, 대부분 웬만한 길이는 거부합니다. 이 용도와는 무관한 보안상의 이유고요. 진짜 제한은 위에서 말한 그것입니다. 기술적으로 무엇이 깨지기 훨씬 전에, 그 페이지는 평범한 이미지 파일을 썼을 때보다 이미 느려져 있습니다.

### 무료인가요? 가입해야 하나요?

무료이고 계정도, 로그인도, 체험판도, 워터마크도 없습니다. 파일 개수나 용량 제한도 없습니다. 그 값을 치를 서버가 없으니까요. 작업은 내 기기에서 일어납니다. 이 사이트는 광고로 유지되는데, 그 광고에도 내 이미지에 관한 것은 넘어가지 않습니다.

### 오프라인에서도 되나요?

됩니다. 페이지를 한 번 불러온 다음 인터넷을 끊어도 계속 동작합니다. 아무것도 업로드되지 않는다는 가장 간단한 증명이기도 하고요. 이미지를 어딘가로 보내서 인코딩하는 도구라면 선을 뽑는 순간 멈춰 버릴 테니까요.

## 이 약속을 직접 확인하는 방법

- **이미지는 나갈 곳이 없습니다.** 이 페이지가 연결해도 되는 주소는 Content-Security-Policy에 모두 적혀 있는데, 그중 이 사이트 것은 하나도 없습니다. 파일이 모일 만한 수신 지점이 없고, 설령 있더라도 거기로 파일을 보낼 코드가 없습니다.
- **여기서는 아무것도 가져오지 않습니다.** `src/` 어디에도 `fetch`도, `XMLHttpRequest`도, `sendBeacon`도 없습니다. 인코딩은 `btoa`와 `encodeURIComponent`가 합니다. 브라우저가 처음부터 갖고 있던 두 함수이고, 둘 다 바이트를 받아 텍스트를 돌려줄 뿐 어디로도 가지 않습니다.
- **미리보기가 곧 증거입니다.** 결과 옆의 그림은 원본 파일이 아니라 이 페이지가 방금 만든 데이터 URI에서 그려집니다. 그게 보인다는 건 URI가 맞다는 뜻이에요. 서버 없이, 내 기기에서 확인되는 셈입니다. 그려지지 않으면 망가진 것을 건네는 대신 그렇다고 말해 줍니다.
- **메타데이터 경고는 붙여 넣는 사람 편입니다.** 데이터 URI는 파일을 그대로 복사하기 때문에, 사진의 GPS 좌표도 함께 스타일시트로 들어갑니다. 이 페이지는 그런 것이 얼마나 들어 있는지 읽어 알려 줍니다. 그러지 않으면 커밋한 뒤에야 알게 되니까요.
- **구글이 불러오는 것과, 구글에게 주지 않는 것.** 광고와 측정 스크립트는 구글에서, 후원 버튼은 Buy Me a Coffee에서 옵니다. 어느 쪽에도 내 사진에 관한 것은 넘어가지 않습니다. 파일을 읽거나 인코딩하는 코드는 한 줄도 빠짐없이 이 출처에서 제공되고 저장소에 공개되어 있습니다.
- **오프라인에서도 동작합니다.** 네트워크를 끊어도 도구는 그대로입니다. 애초에 네트워크를 쓰는 단계가 없었으니까요. 가장 간단한 증거입니다.

**직접 확인해 보세요.** 위에 적은 어느 것도 그냥 믿으실 필요는 없습니다. 이 페이지는 저장소 안의 템플릿과 설정을 빌드 스크립트가 찍어 낸 결과이고, 그 스크립트는 누구나 읽고 직접 돌려 볼 수 있습니다. 결과물은 `dist` 브랜치에 그대로 올라가 있고요. 그래서 실제로 제공되는 파일과 소스를 빌드한 결과를 나란히 놓고 비교해 보실 수 있습니다: https://github.com/A-Box-of-Tools/website

먼저 읽어 볼 파일을 꼽자면, Content-Security-Policy는 `config/site.toml`, 두 가지 인코딩과 각각을 고른 이유는 `src/encode.js`, 미디어 타입을 이름이 아니라 파일에서 읽어 내는 방법은 `src/sniff.js`, 지금 붙여 넣으려는 것 중 얼마만큼이 사진이 아닌지를 알려 주는 검사는 `src/metadata.js`에 있습니다.
