웹페이지에서 사용자의 접근성을 좋게 하는 방법중 하나는
서버에서 처리를 빠르게 하는 방법도 있지만, 이미지 로딩을 최적화 하는 것도 한가지 방법이다.
압축률이 좋은 사진 포맷을 활용하여 사진을 불러오게되면, 용량에 대한 클라이언트측의 부하가 적어지기 때문에, 사진 확장자나 압축방식을 적절하게 활용하는 것이 좋다.
그 중에 요즘 많이 쓰이는 방식이 구글에서 만들어낸 WEBP 확장자를 이용하는 방식인데, 다른 방식으로도 변환이 가능하겠지만, 자바스크립트를 활용하면, 빠른시간안에 적용할 수 있다.
주의사항을 참고해서 적용 범위를 살펴보자면, 실제 유저들이 사용하는 부분에서 사용하게되면 예외처리를 해야 하는 부분이 많아보이니, 간단하게 이미지정도만 업로드 하는 부분에 사용하게되면 충분히 유용하게 사용 할 수 있을 것 같다.
// 해당 함수로 원본 파일 객체(ogFile)를 전달
function convertImgToWebp(ogFile){
return new Promise(resolve => {
let og_src = URL.createObjectURL(ogFile);
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let userImage = new Image();
userImage.src = og_src;
userImage.onload = function(){
//기존 파일과 사이즈 맞춤
canvas.width = userImage.width;
canvas.height = userImage.height;
ctx.drawImage(userImage, 0, 0);
//webp 로 변경
let webpImage = canvas.toDataURL('image/webp');
// console.log(webpImage);
// 변경된 이미지를 다시 파일로 변경 start
let blobBin = atob(webpImage.split(',')[1]);
let _arr = [];
for(var i = 0; i < blobBin.length; i++){
_arr.push(blobBin.charCodeAt(i));
}
let webpFile = new File(
[new Uint8Array(_arr)],
ogFile.name.split('.')[0]+'.webp',
{type: 'image/webp'}
);
resolve(webpFile);
}
})
}
html 엘리먼트인 canvas를 사용해서 복제 후에 확장자 변경과 압축을 진행하는 방식이다.
특징이 있다면 해당 함수를 promise를 리턴한다.
왜냐면.. promise를 사용해서 await을 활용하지 않게되면 해당 함수 내부 로직이 처리되기 전에 호출한 부분 다음을 실행해버리는 경우가 생겨서, await을 사용해서 무조건 리턴 받은 후에 다음 로직을 실행해야한다.
예를들어
// webp 파일을 리턴 받아야 하는 함수
async function exampleFunction(id) {
var files = document.getElementById(id).files;
for( var i=0 ; i< files.length ; i++){
var _file = files[i];//webp로 변경전 file
var file = null;
//gif파일은 webp변환 예외
if(_file.type.indexOf('gif') <= 0){
file = await convertImgToWebp(_file); //webp로 변경후 file
} else{
file = _file;
}
//webp 변환시 빈파일로 반환된 경우 원본파일로 업로드처리
if(Number(file.size) === 0){
file = _file;
}
// ..후처리 로직
}
}
이런식으로 async 함수로 선언 후에 await을 사용해서 무조건 webp 변환 함수가 promise를 리턴 후에 이후 로직이 실행되게 해야 한다.
그 외에 gif나 가끔 빈파일로 리턴하는 경우에만 원본 파일로 올리는 예외처리를 해주었다. (사진이 너무 큰 경우에는 DataUrl이 너무 커져서 크롬 자체에서 차단을 하는 것 같다.)
웬만하면 javascript로 하는 방식은 비추하나, 급하게 적용해야 할 부분이 있다면 가장 간단하게
적용 할 수 있는 유용한 방법이라 생각한다.
해당 방법은 클라이언트 측에서 실행해야 하기 때문에, 유저가 사용하는 부분에서는 지양하는 것이 좋을 것 같다. 예외도 워낙 많아서...