browser-image-compression, heic2any

수즈·2023년 8월 28일

프로젝트 중 이미지 파일이 너무 큰 경우 렌더링이 늦게 된다는 걸 발견하였고 이미지 용량에 제한을 두거나 직접 변환하는 방법을 찾아보았다.

이미지 크기 변환은 다행히 라이브러리가 많았다. 근데 저번에 마지막 업데이트가 3년 전인 라이브러리를 사용했다가 아예 엎은적이 있어서... 최대한 반년 안에 업데이트가 되고 이슈가 활발한 라이브러리를 찾아내야 함.

browser-image-compression

import imageCompression from 'browser-image-compression';

 const handleImageInputChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (file) {
      await uploadImgFile(file);
      try {
        const options = {
          maxSizeMB: 1,
          useWebWorker: true,
        };

        const compressedFile = await imageCompression(file, options);
        console.log(`Original size: ${originalSize} bytes`);
        console.log(`Compressed size: ${compressedSize} bytes`);
        await uploadImgFile(compressedFile);
      } catch (error) {
        console.error('Image compression error:', error);
      }
    }
  };

옵션에서 파일 최대 용량을 지정해주면 됨. 저렇게 말고도 maxWidthorheight로도 할 수 있지만 우리 프로젝트는 어쨌든 1:1 크기로 들어가는 거라 용량으로 줄여주는 게 나을거라 판단.

이렇게 콘솔을 보면 사이즈가 잘 줄어든걸 확인할 수 있다.

다만 용량이 줄어드는지 확인하는 과정에서 다른 문제를 발견했는데,
폰에서 맥북으로 에어드랍을 보낸 이미지의 확장자명이 전부 heic (대충 아이폰용 파일이라고 생각하면 됨)였다 ... 나도 생전 처음 보는 확장자명이었고 당연히 우리 사이트에선 이 파일들을 받을 수가 없음 ... 그래서 Heic 파일은 webP나 jpg로 바꿔주는 작업이 필요했음.

heic2any

import heic2any from 'heic2any';

const handleImageInputChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];

    if (file) {
      console.log('Uploaded File:', file);

      const options = {
        maxSizeMB: 3,
        useWebWorker: true,
      };

      const resizeFile = async (fileToResize: File) => {
        try {
          console.log('Original File Size:', fileToResize.size);

          const compressedFile = await imageCompression(fileToResize, options);
          console.log('Compressed File Size:', compressedFile.size);

          await uploadImgFile(compressedFile);
          console.log('Uploaded Compressed File:', compressedFile);
        } catch (error) {
          console.error('Image compression error:', error);
        }
      };

      if (file.type === 'image/heic' || file.type === 'image/HEIC') {
        heic2any({ blob: file, toType: 'image/jpeg' }).then(function (resultBlob: any) {
          const jpgFile = new File([resultBlob], file.name.split('.')[0] + '.jpg', {
            type: 'image/jpeg',
            lastModified: new Date().getTime(),
          });
          console.log('Converted JPG File:', jpgFile);
          resizeFile(jpgFile);
        });
      } else {
        console.log('No conversion needed. Using original file.');
        resizeFile(file);
      }
    }
  };

(콘솔 남발해서 ㅈㅅ ... 근데 저는 콘솔로 확인을 해야 마음이 편해요 ...)
이렇게 사용해주었다.
webP가 나을지 jpg가 나을지는 사용해보면서 파악해야겠음.

 <input id="inputImg" type="file" accept="image/png, image/jpeg, image/jpg, image/HEIC, image/heic " onChange={handleImageInputChange} ref={imgRef} />

이렇게 accept에도 heic를 넣어주어야 한다.

콘솔에 heic가 jpg 로 바뀌고 용량을 또 한번 줄여서 변환된 걸 볼 수 있다.
그러나 여기서 또 문제를 발견함 ... (하나 해결하면 하나 생기고 미칠거 같음)

우리는 사진의 메타데이터를 받아서 위치 정보를 줄 생각이었다.
근데 jpg 로 바뀔 때까지는 (아마도 시간이 계속 남아있는 걸 보면) 메타데이터가 유지되는 거 같은데 용량을 줄이니 메타 데이터가 사라진 듯...
그리고 우리는 2번의 변환과정을 거치니까 이미지를 업로드 하는 과정이 꽤 김
나는 물론 콘솔을 통해 보니까 지금 변환이 되고 있는 걸 알지만
사용자 입장에서는 안 올라갔나 싶을 거 같음
그래서 로딩중 같은 ui 를 추가해야 할 듯....

그래서 남은 할 일
1. 메타 데이터가 유지되는지 확인하고 (exif.js 라이브러리 이용?)
2. 만약에 유지가 안된다면 유지가 되게 하는 방법을 찾아내야하고
3. 로딩중 넣기...

저 세개는 내일 이어서 ....

profile
👻

0개의 댓글