Base 64 간단 정리하기
Canvas 를 공부하던중 Base 64 개념을 만나게 되어 이를 간단히 정리해보고자 한다.
Base 64 란 8비트 2진 데이터를 (플랫폼의) 문자 코드에 영향을 받지 않는 공통 ASCII 영역의 문자들로만 이루어진 일련의 문자열로 바꾸는 인코딩 방식을 가리키는 개념이다.
Base 64 는 데이터를 64진법 으로 나타낸다.
이를 0부터 63까지 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 으로 나타낸다.
베이스64의 정확한 규격은 RFC 1421, RFC 2045에 정의된다.
데이터를 Base64로 바꾸는 과정은
- 24비트 버퍼에 위쪽(MSB)부터 1바이트 (8비트)씩 3바이트를 채운다.
- 3바이트 보다 미만이라면, 버퍼의 남은 부분은 0으로 채워넣는다.
- 버퍼의 위쪽부터 6비트씩 잘라 그 값을 읽어, Base 64 의 값으려 변경한다.
- 버퍼의 남은 부분을 0으로 채운 값을 1바이트당 = 코드로 변경한다.
예를 들어, 데이터 가 Man 이라고 가정했을때,
이를 8비트로 변환하면,
01001101(M: 77) , 01100001(a: 97) , 01101110(n: 110)
이된다.
이를 6비트 씩 잘라 나열하면,
010011(T: 19) , 010110(W: 22) , 000101(F: 5) , 101110(U: 46)
이 된다.
이를 문자로 표현하면 TWFu 이 된다. 만약 3바이트를 채우기에 부족하다면, 나머지 Bit 영역을 0으로 채우고, 6 Bit 로 변환후, 부족했던 1 바이트(8bit) 당 1개의 = 를 추가한다.
Ma -> TWE=
Javascript 에서의 Base 64 변환
WindowOrWorkerGlobalScope 에 base64 utility method 로 btoa 과 atob 가 구현되어 있다.
- btoa(DOMString data): DOMString;
- atob(DOMString data): ByteString;
btoa() 은 입력 문자열을 Base 64 으로 표현되는 문자열을 반환한다.
만약 입력 문자열에 유니 코드 같은 btoa 에서 이해할 수 없는 문자열이 들어오면 InvalidCharacterError 가 발생한다.
atob() 은 인코딩된 Base 64 문자열을 디코드한다.
만약 입력 문자열에 Base 64 에 포함되지 않는 문자 (A-Z,a-z,0–9+/ 이외) 가 입력되면 DOMException 이 발생한다.
window.btoa('Man');
// TWFu
window.btoa('TWFu');
// Manwindow.btoa('\u');
// Uncaught SyntaxError: Invalid Unicode escape sequence
window.atob('🙂');
// Uncaught DOMException: Failed to execute 'atob' on 'Window'
유니코드를 Base 64 로 변환해야할 경우, 일반적으로 InvalidCharacterError 예외 가 발생 한다.
하지만 유니코드를Uniform Resource Identifier (URI) 컴포넌트로 변경하고 다시 Base 64 변경한다면, 가능하다.
encodeURIComponent() 와 decodeURIComponent 를 이용하여, 유니코드 를 URI 으로 변경하여 사용할 수 있다.
var uni = '🙂';var data = encodeURIComponent(uni);
// %F0%9F%99%82
var encode = window.btoa(data);
// JUYwJTlGJTk5JTgyvar decode = window.atob(encode);
// %F0%9F%99%82
decodeURIComponent(decode);
// 🙂
Base 64 는 전자 메일을 통한 이진 데이터 전송 등에 많이 쓰인다.
A-Z,a-z,0–9,/+ 만을 사용하기 때문에, 문자 포맷이 달라 데이터를 손상시킬 수있는 시스템 간에 안정적으로 전송 될 수 있다.
Data URI scheme
Data URI scheme 은 웹페이지에 Data 를 인라인으로 포함하는 방법이다.
DataURL 은 작은 이미지 같은 파일을 문서 (Html, JS, CSS) 에 인라인으로 작성할 수 있는데, 작성된 이미지와 같은 정보는 이미 문서에 포함되어 있기때문에, 서버에 요청하지 않고도 이미지를, 사용할 수 있다.
이 구조는 RFC 2397 에 정의 되어 있다.
data:[<mediatype>][;base64],<data>
data: 으로 시작하며, ,
으로 실제 데이터와 구분한다.
- Hello, World! 를 변환하면, 아래와 같다.
- data:,Hello%2C%20World!
- data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
DataURL 은 데이터 길이 제한이 있을 수 있으며, 쿼리 문자열은 지원하지 않는다.
이미지를 사용할 때 주로 많이 사용 되는데, 아래와 같이 쓸 수 있다.
<!-- html -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQoU2NkYGD4z0AEYBxViC+UqB88AKk6CgERnGWPAAAAAElFTkSuQmCC" /><style>
/* css */
body {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQoU2NkYGD4z0AEYBxViC+UqB88AKk6CgERnGWPAAAAAElFTkSuQmCC')
}
</style><script>
// js
var img = new Image();
img.addEventListener('load', () => {
// 캔버스에 그리기
var ctx = document.querySelector('canvas').getContext('2d');
ctx.drawImage(img, 0, 0);
});
img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQoU2NkYGD4z0AEYBxViC+UqB88AKk6CgERnGWPAAAAAElFTkSuQmCC"
</script>
하지만 문서에 이미지가 포함되기 때문에 image file 을 cache 할수 없으므로, 어떻게 쓰냐에 따라 성능에 좋을수도, 약영향이 있을수도 있다.
FileReader
FileReader 는 File 혹은 Blob 객체를 이용하여, 파일의 내용을 읽을 수 있게 해주는 Web API 이다.
Input 태그로 FileList 를 얻어 FileReader.readAsDataURL()
으로 Base64 데이터로 변환하고 이를 atob 로 데이터 변환 가능하다.
<!-- html -->
<input type="file" accept=".txt">/><script>
// js
document.querySelector('input[type=file]')
.addEventListener('change', (e) => {
var file = e.target.files[0];
var reader = new FileReader(); reader.addEventListener('load', () => {
// , 위치부터 Base 64 정보이다.
var dataIndex = reader.result.indexOf(',') + 1;
var base64 = reader.result.substring(
dataIndex,
reader.result.length
); // Base 64 를 문자로 변환
var text = window.atob(base64);
console.log(text);
}, false);
reader.readAsDataURL(file);
});
</script>
해당 DataURL 은 이미지나 비디오 등의 DataURL 을 읽을 수 있는 이벤트에 전달이 가능하다.
ArrayBuffer
ArrayBuffer 는 일반 고정 길이의 이진 데이터 버퍼를 나타내는 데 사용되는 데이터 형 이다.
이를 상속받아 구현한 typed array 중 Uint8Array 를 이용하여, 버퍼 데이터를 받아, 8 Bit 데이터 형으로 만들고, 이를 6 Bit 로 쪼개서 Base 64 로 변환하는 형태의 btoa 를 구현할 수 있다.
위 코드는 버퍼정보를 받아서 8bit 형태로 만든뒤, (>> 18 등) 으로 6비트 씩 자르고, 이를 encodings 의 문자로 치환하는 것을 볼 수 있다.
base64ArrayBuffer([77, 97, 110])
// TWFu