fbpx

이미지 리사이징, 이미지 용량 줄이기 (1) (feat. HTML5 canvas, JavaScript)

플로우 개발 스토리 12월 27, 2019
dellose

author:

이미지 리사이징, 이미지 용량 줄이기 (1) (feat. HTML5 canvas, JavaScript)

입 이유 : 서버 리소스 관리를 위하여

용량이 큰 이미지는 서비스 운영에 있어 리소스가 많이 들기 때문에 썸네일 작업이 필요했습니다. 원래는 서버에서 작업을 하여 모바일, 웹 클라이언트 환경 상관없이 적용하려 했습니다. 하지만 전에 경험해보았을 때 서버에서 썸네일 작업을 진행할 경우 부하가 있는 것을 확인했습니다. 그래서 이번엔 클라이언트에서 이미지 리사이징하여 서버에 보내는 방식으로 적용해보았습니다. 그중에서도 웹 클라이언트(javascript)에서 이미지 리사이징했던 방법을 공유해보려고 합니다.


적용 기술 : HTML5 Canvas

javascript를 활용하여 이미지를 리사이징하는 방법에는 여러 가지 방법이 있지만 대부분은 HTML5 canvas라는 키워드로 수렴하게 됩니다. canvas는 html 태그 <canvas>와 같이 활용할 수 있는데 웹페이지에서 그래픽을 그릴 때 사용하는 컨테이너입니다. 대부분의 브라우저가 지원하는 기능이기 때문에 어디서든 활용이 가능합니다!


image.png
출처 : https://caniuse.com/#search=canvas

canvas 자체도 다양한 기능을 가지고 있지만 이미지 리사이징하는 기능이 있고 또 간단하기 때문에 많이 활용하는 것 같습니다!

canvas 를 활용하여 이미지 리사이징하기 위해서는 이미지 객체가 필요한데, 이미지 객체를 만드는 방법은

  • 파일을 이미지 객체로 만드는 방법
  • 이미지 주소를 활용하여 이미지 객체로 만드는 방법

두 가지가 있습니다.


이미지 객체 만들기(1) : File -> Image

보통 파일 첨부를 통해 이미지든 파일이든 받게 되면 File 객체로 받아지게 됩니다. 이 파일 객체를 이미지로 바꾸기 위해서는 파일을 읽어 들이고 파일의 dataUrl을 이미지로 바꾸는 과정이 필요합니다.

var reader = new FileReader();
reader.onload = function (e) {
  var img = new Image;
  img.onload = function() {
    var thumbFile = getThumbFile(img); //여기서 이미지 객체 img를 활용하여 썸네일 처리를 할 수 있음
  };
  img.onerror = function() {
    //에러가 나는 경우 처리를 할 수 있음
  };
  img.src = reader.result;
};
reader.readAsDataURL(tmpFile); //파일객체를 넣어줌

아래에서 getThumbFile(img)를 통하여 리사이징된 파일을 받아보겠습니다.


이미지 객체 만들기(2) : Path -> Image

var img = new Image;
img.onload = function() {
  var thumbFile = getThumbFile(img); //여기서 이미지 객체 img를 활용하여 썸네일 처리를 할 수 있음
};
img.onerror = function() {
  //에러가 나는 경우 처리를 할 수 있음
};
img.src = '/img/sss.png'; //이미지 파일의 주소를 넣어주면 됨

기존에 저장된 이미지 파일을 리사이징 할 수도 때문에 해당 과정으로 작업이 가능합니다. 썸네일 처리는 보통 이미지를 최초 첨부하는 때에 활용하기 때문에 해당 과정은 쓰지 않았지만 파일 주소가 있다면 위와 같이 간단하게 이미지 객체를 가져올 수 있습니다.


이미지 리사이징

복잡해 보이지만 두 단계로 보면 이미지 객체를 리사이징하고 싶은 크기의 canvas에 그리고 파일화하는 과정이라고 보면 됩니다. 이 파일 객체를 서버에 저장하여 활용하면 thumb로 활용할 수 있습니다!

function getThumbFile(_IMG){
  //canvas에 이미지 객체를 리사이징해서 담는 과정
  var canvas = document.createElement("canvas");
  canvas.width = '100px'; //리사이징하여 그릴 가로 길이
  canvas.height ='100px'; //리사이징하여 그릴 세로 길이
  canvas.getContext("2d").drawImage(_IMG, 0, 0, width, height);

  //canvas의 dataurl를 blob(file)화 하는 과정
  var dataURL = canvas.toDataURL("image/png"); //png => jpg 등으로 변환 가능
  var byteString = atob(dataURI.split(',')[1]);
  var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
  var ab = new ArrayBuffer(byteString.length);
  var ia = new Uint8Array(ab);
  for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }

  //리사이징된 file 객체
  var tmpThumbFile = new Blob([ab], {type: mimeString});
 
  return tmpThumbFile;
}

어떤 기준으로 리사이징해야 하는가?

이미지 리사이징하는 법은 위같이 하면 쉽게 처리됩니다. 하지만 이미지 리사이징한다는 것은 보통 이미지 용량을 줄이기 위해 시도되는 작업입니다. 위에서는 임의로 가로, 세로를 100px로 고정하여 리사이징했지만 실제 운영 시에는 실제 이미지의 비율도 고려해야 하며 지나치게 리사이징했을 경우 이미지가 깨지는 부분에 대하여 고민이 필요합니다! 해당 고민은 추가로 포스팅하여 정리하도록 하겠습니다!