목차
1. 개요
GOLFANI 에서는 이미지를 여러 곳에서 사용하고 있습니다.
최근 스마트폰 카메라의 발달로 카메라 사진들의 용량이 갈수록 증가하고 있습니다.
이미지 1장을 10MB의 용량이라고 한다면 5장을 업로드하려면 50MB의 데이터 통신이 필요합니다.
50MB를 다수의 사용자가 동시에 업로드한다고 하면 서버측에 부하가 발생할 것이고,
사용자 입장에서는 업로드하는데 시간이 오래 걸릴 수 있어 불편함을 초래합니다.
또한, 사용자가 해당 이미지를 불러오기 위해서도 50MB라는 데이터를 받아와야 합니다. 사용자는 웹사이트를 이용하는 데 있어서 상당히 불편함을 느낄 것입니다.
2. 이미지 리사이징
그렇다면 어떻게 해야 할까요??
바로, 업로드(저장) 되는 이미지의 용량을 줄이는 것입니다. 사용자가 이미지를 업로드할 때 클라이언트 단에서 이미지 용량을 줄여서 서버에 업로드하는 것입니다.
어떻게 하면 이미지의 용량을 줄일 수 있을까요? 이미지의 크기를 줄이거나 이미지의 퀄리티를 낮추면 용량을 줄일 수 있습니다.
GOLFANI에서는 이미지 크기를 줄이고, 퀄리티를 낮추는 방식 두가지를 사용하였습니다.
이미지 크기를 줄이는 방식은 원본이미지를 canvas를 통해 원하는 크기만큼 비율을 유지한채 다시 그렸습니다.
이미지 퀄리티는 캔버스로 그린 그림을 이미지로 저장할때 퀄리티를 지정하는 방식으로 낮췄습니다.
아래는, 해당 프로세스를 코드로 나타낸 것 입니다.
// 캔버스 만들기
const canvas = window.document.createElement('canvas');
// 캔버스 컨텍스트
const ctx = canvas.getContext('2d');
// 캔버스에 그릴 이미지
const canvasImage = new Image();
// 원본이미지 세팅하기
canvasImage.src = fileUrl;
// 리사이징하고싶은 최대 크기
const maxWidth = 1080;
const maxHeight = 1080;
canvasImage.onload = () => {
// 원본이미지의 크기를 가져옵니다.
let width = canvasImage.width;
let height = canvasImage.height;
// 원본이미지의 비율을 유지한채 최대크기로 리사이징 합니다.
if (width > height) {
if (width > maxWidth) {
height = height * maxWidth / width;
width = maxWidth;
}
} else {
if (height > maxHeight) {
width = width * maxHeight / height;
height = maxHeight;
}
}
// 리사이징된 이미지 크기 설정
canvas.width = width;
canvas.height = height;
// 캔버스에 이미지 그리기
ctx?.drawImage(canvasImage, 0, 0, width, height);
// 캔버스에 그려진 그림 이미지로 변환, 타입, 퀄리티 지정
const resizeImageUrl = canvas.toDataURL('image/jpeg', 0.75);
// 이미지 파일로 변경
const resizeImageFile = dataURLtoFile(resizeImageUrl, file.name);
}
이러한 과정을 통해 이미지 리사이징을 진행하였습니다. 퀄리티를 0.75정도로 진행하면 사용자가 느끼기에 이미지의 퀄리티가 나쁘지 않습니다. 이미지의 용량도 상당히 줄게 됩니다.
리사이징을 통해서 사용자가 업로드, 다운로드 시 걸리는 시간이 상당히 감소하게 되었습니다.
3. 여러 사이즈의 이미지
동일한 이미지가 여러 크기의 사이즈로 사용된다면 두 가지 이슈가 나타날 수 있습니다.
1) 업로드된 사이즈 보다 큰 사이즈로 이미지를 볼 때 -> 이미지 퀄리티가 나쁘게 나타납니다.
이를 방지하기 위해 해당 이미지가 웹사이트에서 사용하는 가장 큰 사이즈로 업로드합니다.
2) 업로드된 사이즈 보다 작은 사이즈로 이미지를 볼 때 -> 불필요한 자원 낭비 GOLFANI에서 예시를 들어 보겠습니다.
1. 프로필 페이지에서 보여지는 유저 프로필 사진

2. 커뮤니티 작성자 유저 프로필 사진

위는 같은 사진이 사이즈가 다르게 쓰이는 예시입니다.
만약, 같은 크기의 사진으로 사용한다고 하면 작은 크기의 이미지를 부를 때도 큰 크기의 이미지를 불러오기 때문에 자원이 낭비됩니다.
따라서, 해당 이미지를 필요한 크기의 이미지로 불러오는 것이 중요합니다.
어떻게 하면, 필요한 크기의 이미지들을 제공할 수 있을까요?
3.1) GOLFANI에서 제공하는 방식
GOLFANI에서는 필요한 크기의 이미지들을 제공하는 방법은 해당 이미지를 필요한 크기들의 이미지들로 모두 저장하여 제공하는 방식입니다.
무식한 방법일수는 있으나, 필요한 크기가 많지 않을 경우에는 나쁘지 않은 방법입니다.
실제로 저희가 사용하는 크기는 최대 3가지 경우입니다.
1) 1080 * 1080(px) 고급화질
2) 600 * 600(px) 중급화질
3) 300 * 300(px) 저급화질
A라는 이미지 파일을 사용자가 업로드하려고 한다면, 아래와 같은 과정이 이루어지게 됩니다.
1) 원본 A이미지 -> 1080 * 1080크기의 이미지로 리사이징 합니다.
2) 리사이징된 이미지를 서버에 업로드하게 됩니다.
3) 서버에서 해당 이미지로 600 * 600, 300 * 300 크기의 이미지를 생성해 저장합니다.
그리고 클라이언트에서 각 크기에 해당하는 이미지를 불러오게 됩니다.
이런 방식으로 유저들에게 최적의 이미지들을 제공할 수 있습니다.
하지만, 모든 크기에 대해 이미지를 저장하고 있다 보니 부담이 될 수 있습니다.
3.2) On-demand Image Resizing
만약, 필요한 크기가 조금 더 많아지게 되면 어떨까요??
5개의 크기가 필요하다면 총 10000장의 이미지를 저장하기 위해 50000장의 이미지를 저장하여야 합니다.
또한, 필요한 크기가 변경된다면 (300 * 300) -> (450 * 450)
이미 저장되어 있는 300 * 300 사진들을 450 * 450 사이즈의 이미지로 변경하여야 합니다.
On-demand Image Resizing을 사용하게 된다면 위와 같은 단점들을 보완할 수 있습니다. On-demand Image Resizing은 사용자의 요청에 따른 크기의 이미지들을 그때그때마다 원본 사진을 리사이징 하여 제공합니다.
매 요청마다 리사이징하게 되면 발생하는 자원이 많아지게 되는데, 캐싱으로 해결이 가능합니다.
이러한 작업들은 AWS에서 제공하는 Lambda@edge 와 CloudFront를 통해 가능합니다.
CloudFront
웹 사이트에서 사용하는 이미지, 동영상(미디어 파일) 또는 css, js 같은 정적인 파일들을 보통 AWS S3서비스를 이용해 저장하여 사용합니다.
비용을 효과적으로 관리하는 동시에 애플리케이션의 성능과 보안까지 최적화하려면 CloudFront를 설정해 S3 버킷과 함께 사용하는 것이 좋습니다.

CloudFront를 이용하면 클라이언트에서 S3에 직접 요청하는 것이 아니라 CloudFront를 통해 접근하게 됩니다.
이때, S3에 존재하는 데이터들을 캐싱 하여 더 빠르고, 효과적으로 데이터들을 제공해 줍니다.
On-demand Image Resizing 프로세싱
1) 클라이언트에서 이미지에 대해 원하는 크기로 요청을 하게 됩니다.
2) CloudFront에서 해당 이미지가 원하는 크기로 리사이징된 데이터가 있는지 확인합니다.
3-1) 데이터가 존재하지 않으면, lambda가 실행되어 해당 이미지를 리사이징하여 제공합니다.
3-2) 데이터가 존재하면 캐싱 되어있는 데이터를 제공합니다.
이러한 방식으로 원하는 크기의 이미지를 제공받을수 있습니다.
마침
추후, GOlFANI의 이미지 리사이징 관리도 On-demand Image Resizing 방식으로 변경해 나갈 것 입니다.