본문 바로가기
React

React 파일 이미지 최적화 하기 react-image-file-resizer

by 왜안돼요 2024. 7. 10.
728x90

메인프로젝트를 통해서 이것저것 참 많이 써본것 같다.

이번엔 이미지 파일 리사이저를 통해 이미지 최적화를 해보겠따.

 

이미지 리사이징이 왜 필요한가? 🤔

이미지 용량이 큰 경우엔 서버와 DB에 부담을 줄 수 있고 프론트에서 이미지를 느리게 불러오기 때문에 

이미지 용량이 크다면 서버와 DB에 부담을 줄이며 프론트에서 이미지를 빠르게 보여줄 수 있게 리사이징이 필수라고 나는 생각한다!

 

메인 프로젝트에서는 사진업로드가 많은 서비스이다 보니

채팅에서는 굳이 용량이 크고 사이즈가 클 필요가없다는 생각이 들어 리사이징을 진행하기로 했다

 

react-image-file-resizer는 이미지 리사이징, 인코딩을 위해 사용한다. base64 혹은 blob으로 변환이 가능함

base64 인코딩이 뭐유..?

진짜 말 그대로 풀면 64비트를 기본으로하는 인코딩이라는것이다!

인코딩이 뭔디???? 

인코딩은 컴퓨터에 정보를 저장하고 전송하기 위해 사용되는 방법!

 

정보를 저장하거나 전송할 때는 이진수(binary)형태로 변환 되어야 하며, 이진수로 변환하는 과정을 인코딩이라 한다.

 

그래서 base64 인코딩이란!

이진수(binary) 데이터를 text로 바꾸는 인코딩의 하나로써 이진수 데이터를 아스키코드 영역의 문자로만 이루어진 문자열로 바꾸는 인코딩 방식이다.

base64 인코딩 동작 방식

문자열 -> ASCII(아스키코드) -> binary전환 -> 6비트씩 묶어서 8비트 문자로 변환 -> base64 색인표에서 찾아서 치환

 

base 64로 이미지를 인코딩하면 data:image/파일형식;base64 으로 시작하는 형태로 콘솔에 찍힌다!

 

blob은 뭐유..?

blob(Binary Large Object)은 하나의 개체로 구성된 바이너리 데이터의 집합을 의미한다. 

blob은 용량이 큰 데이터를 의미하는데 주로 이미지, 오디오 같은 미디어 객체를 저장하는 데 사용된다.

 

base64의 형태와는 다르게 객체에 저장한다

 

react-image-file-resizer 사용법

yarn add react-image-file-resizer

 

리사이징 할 컴포넌트에서 임포트 해주기

import Resizer from 'react-image-file-resizer';

 

 

리사이징 함수

 

const convertFileToBase64 = (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    try {
      Resizer.imageFileResizer(
        file, // 원본 파일
        800, // 최대 가로 너비
        800, // 최대 세로 높이
        'JPEG', // 변환할 이미지 포맷
        100, // 품질
        0, // 회전
        (uri) => {
          resolve(uri as string);
        },
        'base64' // 출력 타입
      );
    } catch (error) {
      reject(error);
    }
  });
}

라이브러리 문서 

문서에 예시가 나와있어서 보고 잘 따라하면 된다.

 

 

프로젝트에서 사용해보기

 

input요소 이용하기

<input type="file" ref={fileInputRef} style={{ display: 'none' }} onChange={handleFileChange} />

type="file"

인풋 요소를 파일 타입으로 정의해서 로컬에 있는 데이터를 업로드 

accept="image/*"

이미지 파일만 업로드 

나는 쓰지않았다.

 

메세지 전송함수

const handleSend = async () => {
  let imageBase64 = "";
  if (fileInputRef.current?.files?.[0]) {
    const file = fileInputRef.current.files[0];
    imageBase64 = await convertFileToBase64(file);
  }

  if (inputMessage.trim() !== "" || imageBase64) {
    sendMessage(inputMessage.trim(), imageBase64, userData?.nickname);
  }
  setInputMessage(""); // 메시지 전송 후 입력 필드 초기화
  setPreviewImage(null); // 메시지 전송 후 미리보기 초기화
  if (fileInputRef.current) fileInputRef.current.value = ''; // 파일 입력 초기화
}

이미지가 있으면 base64로 변환한다. 텍스트나 이미지가 있을 경우 메세지를 전송하고 입력 필드와 미리보기 초기화

 

카메라 아이콘 클릭 핸들러

const handleCameraIconClick = () => {
  fileInputRef.current?.click();
}

카메라 아이콘을 클릭했을때 파일입력 클릭

 

파일 변경 핸들러

const handleFileChange = () => {
  if (fileInputRef.current?.files?.[0]) {
    const file = fileInputRef.current.files[0];
    const previewUrl = URL.createObjectURL(file);
    setPreviewImage(previewUrl);
  }
}

선택된 이미지의 미리보기 url 생성하고 상태에 설정

 

이미지 제거 핸들러

const handleRemoveImage = () => {
  setPreviewImage(null);
  if (fileInputRef.current) {
    fileInputRef.current.value = '';
  }
}

선택된 이미지를 제거하고 파일 입력을 초기화

 

JSX

return (
  <div className='flex flex-col sm:mb-10 md:mb-10'>
    {previewImage && (
      <div className="mb-2 flex flex-col p-2 relative z-50">
        <div className='flex justify-end'>
          <XMarkIcon className='w-6 cursor-pointer' onClick={handleRemoveImage} />
        </div>
        <img src={previewImage} alt="미리보기" className="w-80 object-cover" />
      </div>
    )}
    <div className="flex items-center justify-between pb-1">
      <div className="w-10 h-10 rounded-full flex justify-center items-center">
        <CameraIcon className="w-7 h-7 cursor-pointer" onClick={handleCameraIconClick} />
        <input type="file" ref={fileInputRef} style={{ display: 'none' }} onChange={handleFileChange} />
      </div>
      <div className="flex flex-row justify-between rounded-full w-full">
        <input
          placeholder="메시지를 입력하세요."
          className="block w-full rounded-lg border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-customGray placeholder:text-gray focus:ring-2 focus:ring-inset focus:ring-mainBlack sm:text-sm sm:leading-6"
          onChange={(e) => setInputMessage(e.target.value)}
          value={inputMessage}
          onKeyDown={handleKeyPress}
        />
        <CommonButton
          className="w-10 h-10 bg-chatBg rounded-full flex justify-center items-center"
          onClick={handleSend}
        >
          <PaperAirplaneIcon className="w-7 h-7 cursor-pointer" />
        </CommonButton>
      </div>
    </div>
  </div>
);

*리사이징 함수는 순수함수로 컴포넌트 밖에 빼놓도록 한다!

 

결과

사진 리사이징 전 파일크기랑 이미지 크기를 잘 보십쇼

 

 

이렇게 보낸 사진을 다시 저장해서 속성을 확인해보겠습니달라

 

이미지 크기도 줄고 용량도 많이 줄은걸 볼 수 있다!

 

하지만 부작용이 있다..  이미 저화질이고 인터넷에 돌아다니는 디지털 풍화 제대로온 이미지들은 용량이 늘어난다

아마 이미지 크기가 커지면서 늘어나는것 같다.

 

채팅같은 경우에는 사용자가 카메라로 직접 찍어 첨부하는 경우가 더 많지 않나? 싶어 그렇게 작은 이미지들은 신경쓰지 않기로 했다 ..ㅎ!

 

 

참고

React 이미지 리사이징 하기

Base64 인코딩이란

데이터 타입 blob

 

최근댓글

최근글

skin by © 2024 ttuttak