[TIL]이미지 프로세스 이해

우기·2023년 4월 7일
0
post-thumbnail

📒 오늘 공부한 내용

🔍수업목차

[19-1] 이미지 프로세스 이해
[19-2] 이미지 업로드
[19-3] HTML 기본 FILE 태그 숨기기
[19-4] 이미지 검증

✅ 이미지 프로세스 이해 (이미지 서버, 스토리지 포함)


  • 이미지 프로세스를 이해하기 위해서는 storage 사용을 알아야 한다.
  • storage 또한 컴퓨터이며 여러 컴퓨터들을 연결시켜 놓은 큰 용량을 담을 수 있는 데이터베이스다.

📂 이미지 업로드

  • uploadFile 이라는 api가 있을때, 파일을 선택하고 uploadFile을 요청하게 될 경우, backend에서 storage로 파일을 전송하게 된다.

📂 이미지 조회

  • 이미지를 보기 위해서는 주소를 사용해 접근하게 된다.
  • storage에서는 backend로 이미지를 조회할 수 있는 이미지 주소를 넘겨주게 되고, database에 이미지 주소를 저장한다.
  • frontend에서도 이미지 주소를 통해 이미지를 조회한다.

💡 storage는 어디에 있나?

AWS,GCP,AZURE와 같은 클라우드 안에 있다.

✅ 이미지 업로드


  • api는 uploadFile을 사용해 이미지를 업로드
  • 이미지 업로드는 uploadFile로 받아온 이미지 url을 createBoard에 넣어주면 된다.

📂 아폴로 업로드 라이브러리 설치와 세팅

  • url을 가지고 오기위한 라이브러리로 createUploadLink를 설치

1️⃣ 라이브러리 설치를 위해 터미널에 yarn add apollo-upload-client 입력해 설치해 설치

2️⃣ 아폴로 업로드는 타입스크립트 또한 지원해주는 라이브러리다. 따라서 타입을 설치 yarn add @types/apollo-upload-client --dev 를 입력

3️⃣ app.tsx에서 세팅

// app.tsx파일
// import 추가하기
import {createUploadLink} from "apollo-upload-client"

// 세팅 함수 부분
const uplodLink = createUploadLink({
		uri : "백엔드 주소"
	})

const client = new ApolloClient({
		link : ApolloLink.from([uplodLink]),
		cache : new inMemoryCache(),
	})

4️⃣ 파일 업로드할 수 있도록 화면 그려주기

  • onChange를 통해 이미지 파일을 가지고와 file에 넣어준다.
  • file을 variables에 넣어 uploadFile mutation을 날려준다.
  • 이미지가 정해둔 스토리지에 들어가고, 해당 스토리지에서 url을 반환 받아 가지고 온다.
  • 콘솔에 받아온 이미지 URL이 찍힌다.
    // 이미지 업로드 api 사용을 위한 쿼리 작성
    const UPLOAD_FILE = gql`
      mutation uploadFile($file: Upload!) {
        uploadFile(file: $file) {
          url
        }
      }
    `;
    export default function ImageUploadPage(): JSX.Element {
      const [imageUrl, setImageUrl] = useState("");
      const [uploadFile] = useMutation<
        Pick<IMutation, "uploadFile">,
        IMutationUploadFileArgs
    (UPLOAD_FILE);
    
      // 이미지 업로드 함수
      const onChangeFile = async (
        event: ChangeEvent<HTMLInputElement>
      ): Promise<void> => {
        const file = event.target.files?.[0]; // 배열로 들어오는 이유: <input type="file" multiple/>일때, 여러 개 업로드 가능하기 때문입니다.
        const result = await uploadFile({ variables: { file } });
    		console.log(result.data?.uploadFile.url);
        setImageUrl(result.data?.uploadFile.url ?? "");
      };
      return (
        <>
          <input onChange={onChangeFile} type="file" />
          <img src={`https://storage.googleapis.com/${imageUrl}`} />
        </>
      );

💡 해당 url의 이미지를 보고싶다면

저장해둔 스토리지 주소의 뒤에 이미지 url을 적어주면 된다.
http://storage.goolgeapis.com/이미지url

✅ HTML 기본 FILE 태그 숨기기


📂 useRef 이용하기

  • HTML 태그를 선택할 때는 getElementId를 사용했다.

  • react에서는 HTML 태그에 접근을 도와주는 역할을 useRef가 하고 있다.

import { useRef } from 'react';

export default function ImageRefPage(): JSX.Element {
	const fileRef = useRef<HTMLInputElement>(null);

}
<input
  style={{ display: "none" }}
  onChange={onChangeFile}
  type="file"
  ref={fileRef}
/> 

useRef를 이용한 전체 코드

import { gql, useMutation } from "@apollo/client";
import { ChangeEvent, useRef, useState } from "react";
import {
  IMutation,
  IMutationUploadFileArgs,
} from "../../../src/commons/types/generated/types";

const UPLOAD_FILE = gql`
  mutation uploadFile($file: Upload!) {
    uploadFile(file: $file) {
      url
    }
  }
`;
export default function ImageRefPage(): JSX.Element {
  const [imageUrl, setImageUrl] = useState("");
  const fileRef = useRef<HTMLInputElement>(null);

  const [uploadFile] = useMutation<
    Pick<IMutation, "uploadFile">,
    IMutationUploadFileArgs
(UPLOAD_FILE);
  const onChangeFile = async (
    event: ChangeEvent<HTMLInputElement>
  ): Promise<void> => {
    const file = event.target.files?.[0]; // 배열로 들어오는 이유: <input type="file" multiple/>일때, 여러 개 업로드 가능하기 때문입니다.
    const result = await uploadFile({ variables: { file } });
    setImageUrl(result.data?.uploadFile.url ?? "");
  };

  const onClickImage = (): void => {
    // 기존 방식 : document.getElementById("파일태그ID")?.click();
    fileRef.current?.click();
  };
  return (
    <>
      <div
        style={{ width: "50px", height: "50px", backgroundColor: "gray" }}
        onClick={onClickImage}

        이미지 선택
      </div>
      <input
        style={{ display: "none" }}
        onChange={onChangeFile}
        type="file"
        ref={fileRef}
      />
      <img src={`https://storage.googleapis.com/${imageUrl}`} />
    </>
  );
}

✅ 이미지 검증


📂 이미지 유무와 사이즈 검증하기

  • 이미지를 5MB이하의 사이즈만 넣을 수 있도록
const onChangeFile = async (
    event: ChangeEvent<HTMLInputElement>
  ): Promise<void> => {
    const file = event.target.files?.[0];

		// 검증 로직
    if (typeof file === "undefined") {
      alert("파일이 없습니다.");
      return;
    }
    if (file.size > 5 * 1024 * 1024) { // 5MB
      alert("파일 용량이 너무 큽니다.(제한: 5MB)");
      return;
    }

		// API 호출 로직
    const result = await uploadFile({ variables: { file } });
    setImageUrl(result.data?.uploadFile.url ?? "");
  };

📂 이미지 확장자 검증하기

  • 이미지 확장자가 png , jpeg가 아니면 업로드 할 수 없도록 막기

방법 1

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

		~~~	// 기타 검증 로직 생략

    if (!file.type.includes("jpeg") && !file.type.includes("png")) {
      alert("jpeg 또는 png 파일만 업로드 가능합니다.");
      return;
    }

		~~~ // API 호출 로직 생략

  };

방법 2

<input
  style={{ display: "none" }}
  onChange={onChangeFile}
  type="file"
  ref={fileRef}
  accept="image/jpeg,image/png" // 띄어쓰기 없이 콤마(,)를 기준으로 작성합니다.
  // accept를 추가하면 지정되지 않은 확장자는 선택 자체가 불가합니다.
/>

💡 MB(메가바이트) KB(키로바이트) B(바이트)

1024B = 1KB
1024KB = 1MB

profile
개발 블로그

0개의 댓글