Canvas API를 이용하여 구현한 그림판으로 그림을 그린 후,
해당 그림을 서버로 post 요청했다.
이 후 mypage의 갤러리에서 저장한 그림들을 get 요청하고
서버에서 받은 데이터들을 buffer로 base64인코딩한 다음 렌더링 코드를 짰다.
but 해당 그림들이 제대로 표시되지 않았다.
console.log로 인코딩한 데이터들을 확인한 결과, 해당 문자열의 앞부분에 불필요한 문자열이 붙어서 렌더링되고 있었다.
해당 갤러리나 서버에서의 코드는 문제 없어 보였고,
그림판 그림을 post 할 때의 코드를 확인해야 할 것 같았다.
요청 로직을 구현할 때 구글링한 결과들을 참고하여 구현했지만, 이미지 데이터를 가공하여 서버에 보내는 과정을 100% 이해한 것은 아니었기에 이 기회에 다시 공부하며 정리해보았다.
깃헙 - 에러 핸들링 과정 정리
- Canvas 이미지를 데이터로 저장(base64 인코딩)
- 저장된 Canvas 이미지를 base64에서 디코딩
- 디코딩된 값을 바이트 배열로 변환 후 저장
- typed array인 8bit unsigned array로 변환
- new blob() 생성자를 사용해 blob 값으로 변환
- FormData() 생성자를 사용해 이미지 값을 서버의 데이터로 저장
- ajax의 post 메소드를 사용하여 서버에 전송
toDataURL 메소드를 이용하여 canvas의 이미지를 base64 문자열로 가져오고,
적합한 포맷을 설정해준다.
(base64 Encoding, 포맷은 image/png로 설정)
인코딩
base64
Base64를 글자 그대로 직역하면 64진법이라는 뜻.
2의 제곱수에 기반한 진법 중 화면에 표시되는 ASCII 문자들로 표시할 수 있는 가장 큰 진법
-> Base64 Encoding은 Binary Data를 문자열로 변경하는 Encoding이다.
HTML, CSS, JSON등의 다른 포맷 안에 이미지데이터를 첨부할때 주로 Base64 이미지가 사용된다. HTML 문서에 이미지 데이터를 포함함으로써 브라우저는 부가적인 파일 요청을 할 필요가 없다
ASCII는 시스템 간 데이터를 전달하기에 안전하지 않다.
Base64는 ASCII 중 제어 문자와 일부 특수문자를 제외한 64개의 안전한 출력 문자만 사용한다.
(* 안전한 출력 문자란 문자 코드에 영향을 받지 않는 공통 ASCII를 의미)즉, Base64는 HTML 또는 Email과 같이 문자를 위한 Media에 Binary Data를 포함해야 될 필요가 있을 때, 포함된 Binary Data가 시스템 독립적으로 동일하게 전송 또는 저장되는 걸 보장하기 위해 사용한다.
MIME(영어: Multipurpose Internet Mail Extensions)
전자 우편을 위한 인터넷 표준 포맷이다. 전자우편은 7비트 ASCII 문자를 사용하여 전송되기 때문에, 8비트 이상의 코드를 사용하는 문자나 이진 파일들은 MIME 포맷으로 변환되어 SMTP로 전송된다. 실질적으로 SMTP로 전송되는 대부분의 전자 우편은 MIME 형식이다. MIME 표준에 정의된 content types은 HTTP와 같은 통신 프로토콜에서 사용되며, 점차 그 중요성이 커지고 있다.
, (쉼표) 뒤에서 시작하는 것이 캔버스의 base64 표현이므로 쉼표로 문자열을 분할해 인덱스 1내의 데이터만 가져온다.
const canvas: HTMLCanvasElement = canvasRef.current;
const image = canvas.toDataURL('image/png').split(',')[1];
서버에 전송할 수 있는 blob 타입으로 변환하기 위해 base64를 (atob()로) 다시 디코딩
-> 현재 atob은 사용불가, Buffer 추천
const toBinaryIMG = Buffer.from(image, 'base64').toString('binary');
Buffer 사용 이유 : 바이너리 데이터들의 스트림을 직접 다룸
const array = [];
for (let i = 0; i < toBinaryIMG.length; i += 1) {
array.push(toBinaryIMG.charCodeAt(i));
}
ArrayBuffer
- 자바스크립트에서 구현된 버퍼
고정된 크기의 메모리 공간에 바이너리 데이터를 저장하는 객체ArrayBufferView
- ArrayBuffer에 저장된 바이너리 데이터에 접근하는 객체
- TypedArray, DataView 2개가 제공된다.
TypedArray
- ArrayBufferView의 한 종류
배열 요소의 타입/크기를 개발자가 지정하여 생성할 수 있다.
- Uint8Array, Uint16Array, Float32Array 등이 있다.
ArrayBuffer와 TypedArray의 관계
- TypedArray는 ArrayBuffer에 저장된 바이너리 데이터를 이용해 만드는 배열이다.
const u8arr = new Uint8Array(array); //8비트의 typed array을 생성.
인자로 들어온 배열과 동일한 요소의 TypedArray생성 (ArrayBuffer도 함께 생성된다.)
Uint8Array 배열의 각 요소는 1byte(8bit)
ArrayBuffer,TypedArray 잘 정리된 블로그
const file = new Blob([u8arr], { type: "image/png" });
Blob(Binary Large OBject)
주로 이미지, 오디오, 영상 등의 데이터를 다룰 때 사용한다. (물론 꼭 미디어 관련해서만 사용하는 것이 아니라 html, plain text 등 바이너리로 표현 가능한 많은 데이터에서 쓸 수 있다.)
대개 데이터의 크기(Byte) 및 MIME 타입을 알아내거나, 데이터를 송수신을 위한 작은 Blob 객체로 나누는 등의 작업에 사용
Blob 생성자는 입력받은 배열의 요소들을 모두 합쳐 바이너리 데이터 형태로 저장하는 Blob객체를 반환한다.
const formdata = new FormData(); // formData 생성
formdata.append("picture", file); // formdata에 file data 추가
formdata.append('title', title);
formdata.append('emotion', emotion);
(참고)
https://pks2974.medium.com/base-64-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-da50fdfc49d2
https://lienkooky.tistory.com/93
https://tk-one.github.io/2018/08/28/nodejs-buffer/ (Buffer에 관해)