Data URI 생성기
이미지, 폰트, 텍스트를 data: URI로 인코딩하거나 디코딩합니다. Base64와 퍼센트 인코딩을 실제로 측정해 비교합니다. 브라우저에서 실행됩니다.
data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%232563eb'%20stroke-width='2'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M8%2012.5l2.5%202.5%205-6'/%3E%3C/svg%3E
여기서는 퍼센트 인코딩이 더 짧습니다: 255자 대 272자로 17자를 아낍니다.
크기
- 원본 바이트
- 174
- URI, Base64
- 272
- URI, 퍼센트 인코딩
- 255
URL 안에 들어간 파일
data URI는 파일 전체를 URL로 적어 놓은 것입니다. 브라우저가 가지러 가야 할 리소스를 가리키는 대신 바이트 자체를 실어 나르므로, 아이콘은 그것을 쓰는 스타일시트 안에, 작은 이미지는 그것을 보여 주는 HTML 안에 살 수 있습니다. RFC 2397이 1998년에 이 스킴을 정의했고, 그 뒤 20년 동안 어디서나 지원됩니다.
문법은 짧습니다. 스킴 이름 다음에 선택적인 미디어 타입과 선택적인 매개변수가 오고, 이어서 선택적인 base64 플래그, 쉼표, 그리고 데이터가 옵니다. 쉼표 앞은 전부 헤더이고 뒤는 전부 페이로드입니다. 그래서 브라우저는 첫 쉼표에서 나누며, 그래서 페이로드 안의 쉼표는 해가 없습니다.
data:[<mediatype>][;base64],<data> data:,hello text/plain;charset=US-ASCII data:text/plain;charset=utf-8,hello the same bytes, spelled out data:image/png;base64,iVBORw0KGgo= binary, Base64 encoded data:image/svg+xml,%3Csvg%20... markup, percent-encoded
빈 헤더도 적법하며 그 뜻은 text/plain;charset=US-ASCII입니다. 명세가 건네주는 유일한 기본값입니다. 이 페이지는 쓴 적 없는 미디어 타입을 조용히 보여 주는 대신, 그 기본값을 적용했다고 알려 줍니다.
두 인코딩과 어느 쪽이 짧은가
RFC는 페이로드를 적는 두 가지 방법을 정의하며, 그 선택은 취향의 문제가 아닙니다. 특정 파일에 대해서는 한쪽이 뚜렷하게 짧고, 어느 쪽인지는 전적으로 파일의 내용에 달려 있습니다.
Base64는 3바이트마다 64자 알파벳에서 4문자를 만들어 냅니다. 비용은 고정되어 있고 예측 가능합니다. 정확히 3분의 1이 늘고 여기에 패딩이 붙습니다. 무엇에나 통하므로 사람들이 기본으로 집어 드는 형태입니다.
퍼센트 인코딩은 URL에서 적법한 문자는 있는 그대로 두고, 그렇지 않은 문자 하나마다 3문자를 씁니다. 대부분이 평범한 ASCII인 데이터, 즉 SVG나 작은 스타일시트, JSON 조각에서는 대다수 바이트가 손대지 않은 채 지나가므로 결과가 Base64보다 짧아지고, 이십에서 삼십 퍼센트까지 짧아지는 일도 흔합니다. 반대로 거의 모든 바이트를 이스케이프해야 하는 PNG나 폰트에서는 원본의 세 배에 가까워져 Base64보다 훨씬 불리합니다.
얼마나 이스케이프할지도 그 자체로 하나의 결정이며, 이 페이지는 두 답을 모두 제공합니다.
- 엄격한 집합은 RFC 3986의 비예약 문자, 즉 영문자와 숫자, 하이픈, 마침표, 밑줄, 물결표를 벗어나는 모든 바이트를 이스케이프합니다. 결과는 어떤 맥락에서도 안전하지만, 그럴 필요가 없던 문장 부호까지 이스케이프하는 대가를 치릅니다.
- 최소 집합은 data URI 문법이 실제로 허용하는 문자를 그대로 둡니다. 여기에는 슬래시, 콜론, 등호, 따옴표, 괄호처럼 마크업에 가득한 문자들이 포함됩니다. 퍼센트 인코딩이 이기는 지점이 바로 여기이며, 속성을 작은따옴표로 감싼 SVG가 큰따옴표로 감싼 SVG보다 훨씬 잘 인코딩되는 까닭도 이것입니다.
- 용도가 규칙 하나를 더 더합니다. HTML 속성 안에서는 맨 앰퍼샌드가 문자 참조를 시작하므로, img 용도를 고르면 그것도 이스케이프됩니다. 그 밖에는 달라지는 것이 없습니다. 큰따옴표와 꺾쇠괄호, 역슬래시는 애초에 허용 집합 밖이라 두 수준 모두에서 이스케이프됩니다.
- 퍼센트 기호는 어느 수준에서나 항상 이스케이프됩니다. 이스케이프 시퀀스를 여는 문자이므로, 글자 그대로의 퍼센트는 %25로 적어야 하며 그러지 않으면 다음 두 문자가 16진수로 읽힙니다.
추측하게 두는 대신, 페이지는 데이터를 두 방식 모두로 인코딩하고 두 길이와 그 차이를 알려 줍니다. 이긴 쪽을 고르거나, 이유가 있다면 인코딩을 직접 지정하세요.
33%는 압축 이전의 숫자
data URI에 관한 논의는 거의 언제나 Base64가 파일 크기를 3분의 1 늘린다고 되풀이합니다. 산술적으로는 맞지만 실무적으로는 오해를 부릅니다. 그 숫자는 바이트가 회선에 오르기 전을 말하는데, 어느 서버든 나가는 길에 텍스트를 압축하기 때문입니다.
Base64는 정보를 더하지 않습니다. 같은 정보를 더 많은 문자에 펼칠 뿐이며, 1바이트가 가질 수 있는 256개 값 가운데 64개만 사용합니다. 이는 gzip과 Brotli가 제거하려고 존재하는 바로 그 중복입니다. PNG나 JPEG, WOFF2 폰트처럼 이미 압축된 데이터에서는 압축기가 내용 자체는 건드리지 못해도 Base64 부분은 원래 크기에 매우 가깝게 다시 눌러 담을 수 있습니다. 그 유명한 3분의 1은 대부분 사라집니다.
그래서 이 페이지는 주장하는 대신 측정합니다. 브라우저 자체의 gzip 구현으로 세 가지를 압축합니다. 별도 파일로 제공했을 때의 데이터, 그것을 Base64로 담은 문서, 그리고 퍼센트 인코딩으로 담은 문서입니다. 이 세 숫자가 크기 논쟁의 정직한 판본이며, 인라인의 진짜 대가가 애초에 크기가 아니라는 사실을 자주 보여 줍니다.
진짜 대가는 다른 데 있습니다. 인라인된 파일은 그 자체로 캐시할 수 없어 그것을 담은 문서의 사본마다 다시 내려받게 되고, 두 페이지가 함께 쓰는 일도 결코 없습니다. 게다가 막습니다. 스타일시트는 그 한가운데 앉아 있는 URI를 다 읽기 전에는 파싱을 끝내지 못합니다. 애초에 인라인을 매력적으로 만들었던 요청당 비용은 HTTP/2가 대부분 없앴습니다. 모든 페이지에 나오는 아주 작은 아이콘이라면 여전히 합리적인 거래이지만, 수십 킬로바이트를 넘으면 대개 그렇지 않습니다. 이 페이지가 30킬로바이트부터 경고하는 이유입니다.
타입은 바이트에서 나온다
data URI는 미디어 타입이 맞을 때에만 쓸모가 있습니다. 틀리면 브라우저는 이미지 표시를 거부하거나, 엉뚱한 파서를 돌리거나, 알지 못하는 타입으로 제공된 것에 대해서는 대신 내려받기를 제안합니다.
파일을 끌어다 놓으면 브라우저가 자기 나름의 타입을 알려 주지만, 그 판단은 파일 확장자에서만 나온 것입니다. JPEG의 이름을 .png로 바꾸면 브라우저는 그것을 PNG라고 부릅니다. 이 페이지는 대신 첫 바이트를 읽습니다. 거의 모든 이진 형식은 서명으로 시작합니다. PNG는 ASCII에 나올 수 없는 바이트 뒤에 PNG라는 글자가 오고, JPEG는 고정된 3바이트로, PDF는 퍼센트 기호와 PDF라는 단어로, WOFF와 WOFF2는 각자의 네 글자 태그로 시작합니다. 서명과 확장자가 어긋나면 서명이 이기고, 그 어긋남을 보고합니다.
목록은 일부러 짧게 두었습니다. 브라우저가 판별할 수 있는 모든 것이 아니라, 사람들이 실제로 인라인하는 형식만 담았습니다. 아무것도 맞지 않고 바이트가 올바른 텍스트라면 타입은 텍스트이며, 마크업이 무엇으로 시작하는지를 보고 SVG와 XML을 나눕니다. 아예 아무것도 맞지 않으면 답은 application/octet-stream이고 필드는 편집 가능한 채로 남습니다. 틀린 추측은 모른다고 인정하는 것보다 나쁘기 때문입니다.
텍스트 데이터에서는 문자 집합도 중요합니다. 명세의 기본값은 US-ASCII인데 오늘날 그것을 뜻하는 사람은 없으므로, 텍스트 계열 미디어 타입에는 charset=utf-8을 붙여 제시합니다. 빼더라도 바이트가 망가지지는 않지만, 다시 읽는 방식은 달라집니다.
반대로 읽어내기
일의 나머지 절반이 오히려 더 자주 생깁니다. 스타일시트나 DOM 덤프, 저장한 페이지에서 data: URI를 발견했고 그것이 무엇인지 알고 싶은 경우입니다. 붙여 넣으면 페이지가 분해합니다. 미디어 타입, 그 매개변수, 어떤 인코딩이 쓰였는지, 몇 바이트로 디코딩되며 그 대가로 몇 문자를 쓰는지, 그리고 헤더의 주장과 무관하게 그 바이트가 실제로 무엇인지. 이미지는 그려 주고, 텍스트는 보여 주며, 그 밖의 것은 첫 바이트를 16진수로 보여 줍니다.
디코딩은 엄격합니다. 붙여 넣은 URI는 신뢰할 수 없는 입력이고, 그럴듯하지만 틀린 답은 오류보다 나쁘기 때문입니다. 빠진 쉼표, 망가진 미디어 타입, 16진수 두 자리가 따라오지 않는 퍼센트 기호, Base64 알파벳 밖의 문자. 어느 것이든 조용히 고쳐지지 않고 문제의 위치와 함께 실패합니다.
두 가지는 허용합니다. 모든 브라우저가 허용하며, 줄바꿈된 스타일시트에서 복사한 URI가 그러지 않으면 쓸 수 없게 되기 때문입니다. 페이로드 안의 공백은 제거하고, 모자란 Base64 패딩은 채웁니다. 둘 다 보고하므로, 손에 든 URI가 어디서나 통하는 URI와 꼭 같지는 않다는 사실을 알 수 있습니다.
비슷해 보이는 한 가지는 아예 거부합니다. 더하기와 슬래시를 하이픈과 밑줄로 바꾼 URL 안전 Base64 알파벳은 JSON Web Token이 쓰는 것이지 data URI가 받는 것이 아닙니다. 조용히 받아들이면 실제로 그것을 불러올 브라우저와 다른 바이트로 디코딩하게 되므로, 문제가 된 문자의 위치와 함께 이름을 밝혀 거부합니다.
어디서 실행되는가
모든 일이 여러분의 브라우저 안에서 일어납니다. 고른 파일은 로컬 파일 API로 읽으며 업로드하지 않습니다. 인코딩과 압축 측정, 디코딩 모두 여러분의 기기에서 실행되고, 아무것도 저장하거나 기록하지 않습니다. 이 점은 대부분의 페이지보다 여기서 더 중요합니다. 사람들이 data URI로 바꾸는 파일은 대개 내부 자산이고, 살펴보려고 붙여 넣는 URI는 운영 중인 페이지에서 나오기 때문입니다.
자주 묻는 질문
- 제 파일이 어딘가로 올라갑니까?
- 아닙니다. 파일은 브라우저 자체의 파일 API로 로컬에서 읽고, 여러분의 기기에서 인코딩하며, 어디로도 보내지 않습니다. 디코딩하려고 붙여 넣은 URI도 마찬가지입니다.
- Base64와 퍼센트 인코딩 중 무엇을 써야 합니까?
- 여러분의 데이터에서 더 짧은 쪽이며, 그것은 페이지가 측정해 줍니다. 어림잡아: SVG, CSS, JSON 등 텍스트에는 퍼센트 인코딩, 이미지와 폰트, 이미 압축된 것에는 Base64입니다. 차이는 어느 쪽으로든 이십에서 삼십 퍼센트에 이르는 일이 흔합니다.
- Base64가 정말 파일을 33% 키웁니까?
- 압축 전이라면 그렇습니다. 3바이트마다 4문자입니다. 회선에서는 대체로 그렇지 않습니다. Base64는 1바이트가 가질 수 있는 256개 값 중 64개만 쓰고, 그 중복이 바로 gzip이 제거하는 것이어서 압축 후 크기는 대개 원본 파일의 압축 후 크기에 가깝습니다. 페이지가 둘 다 측정하니 직접 확인할 수 있습니다.
- data URI는 얼마나 커질 수 있습니까?
- 요즘 브라우저는 문서 안의 URI에 엄격한 상한을 두지 않습니다. 다만 옛 Internet Explorer는 32KB로 제한했습니다. 크기는 적법성이 아니라 성능의 문제입니다. 인라인된 파일은 따로 캐시할 수 없고 문서 사본마다 다시 내려받습니다. 이 페이지는 1메가바이트까지 인코딩하고 30킬로바이트를 넘으면 경고합니다.
- 제 SVG data URI가 CSS에서 깨지는 이유는 무엇입니까?
- 거의 언제나 이스케이프되지 않은 문자 때문입니다. #2563eb 같은 색에 들어 있는 우물 정 기호는 프래그먼트 식별자를 시작해 그 지점에서 URI를 잘라 버립니다. 큰따옴표는 그것이 들어 있는 CSS 문자열을 끝냅니다. SVG의 속성은 작은따옴표로 감싸고 최소 이스케이프 집합을 쓰세요. 우물 정 기호와 큰따옴표는 이스케이프되고 나머지는 짧게 남습니다.
- 스크립트나 iframe에 data URI를 쓸 수 있습니까?
- 쓸 수는 있지만 편의가 아니라 보안 문제로 다루십시오. data URI는 출처를 물려받지 않으며, 바로 그 때문에 브라우저는 이미 최상위 탐색을 막고 있습니다. script-src나 frame-src에서 data:를 허용하는 콘텐츠 보안 정책은 그 정책이 지키려던 것의 대부분을 포기하는 셈입니다. img-src나 font-src에서 허용하는 것은 일상적인 일입니다.
- 제 URL 안전 Base64는 왜 거부되었습니까?
- data URI가 받는 것은 표준 Base64이기 때문입니다. URL 안전 알파벳은 더하기와 슬래시를 하이픈과 밑줄로 바꾸는데, 이들은 다른 문자이고 다른 바이트로 디코딩됩니다. 받아들였다면 이 페이지가 그 URI를 실제로 불러올 브라우저와 다르게 디코딩하는 셈이 됩니다.
- 브라우저는 파일이 한 타입이라 하고 이 페이지는 다른 타입이라 합니다. 어느 쪽이 맞습니까?
- 이 페이지입니다. 브라우저는 파일 확장자에서 추론한 타입을 알려 주므로 이름이 바뀐 파일은 잘못 보고합니다. 이 페이지는 파일 앞부분의 서명, 즉 형식 자체가 선언하는 값을 읽습니다. 덮어쓸 이유가 있다면 필드는 편집 가능한 채로 남습니다.