본문 바로가기
개발/React

리액트 - 캡처한 이미지를 깃허브에 업로드하기 (Upload Captured Image to GitHub)

by 피로물든딸기 2024. 1. 17.
반응형

깃허브 데스크탑으로 프로젝트 관리하기 강의 오픈!! (인프런 바로가기)

 

리액트 전체 링크

Git / GitHub 전체 링크

 

참고

- 이미지 캡처해서 웹에 붙여넣기

 

깃허브 리포지토리 이미지 불러오기
깃허브 API로 이미지 업로드하기
깃허브에 업로드된 이미지 삭제하기
캡처한 이미지를 깃허브에 업로드하기
캡처한 이미지 여러 개 업로드하기
Toast UI 에디터로 이미지를 포함한 깃허브 마크다운 저장하기

 

이번에는 이미지 파일을 업로드하지 말고, 캡처한 이미지를 깃허브에 올려보자.

 

링크를 참고하여 캡처한 이미지를 먼저 웹 페이지에 붙여 넣는 코드에서 보완해 나가자

import React, { useState } from "react";

const Capture = () => {
  const [image, setImage] = useState(null);

  const handleImagePaste = (event) => {
    const items = (event.clipboardData || event.originalEvent.clipboardData).items;
    
    for (let i = 0; i < items.length; i++) {
      if (items[i].type.indexOf("image") !== -1) {
        const blob = items[i].getAsFile();
        const reader = new FileReader();

        reader.onload = () => {
          setImage(reader.result);
        };

        reader.readAsDataURL(blob);
        break;
      }
    }
  };

  return (
    <div
      onPaste={handleImagePaste}
      style={{ border: "1px solid #ddd", padding: "20px", textAlign: "center" }}
    >
      <h1>이미지 붙여넣기</h1>
      {image && <img src={image} />}
    </div>
  );
};

export default Capture;


캡처 로직 수정

 

handleImagePaste는 blob을 setImage로 저장만 하고 그대로 종료한다.

  const handleImagePaste = (event) => {
    const items = (event.clipboardData || event.originalEvent.clipboardData).items;

    for (let i = 0; i < items.length; i++) {
      if (items[i].type.indexOf("image") !== -1) {
        const blob = items[i].getAsFile();
        setImage(blob);
        break;
      }
    }
  };

 

그리고 이미지 태그를 아래와 같이 수정한다.

{image && <img src={URL.createObjectURL(image)} alt="Pasted" />}

 

업로드를 할 때 파일의 메타데이터인 blob을 같이 보내기 위해서 위의 수정이 필요하다.


handleUpload 구현

 

이제 깃허브 API로 이미지 업로드하기를 참고하여 handleUpload를 아래와 같이 구현하자.

  const handleUpload = () => {
    if (!image) {
      console.error("Please select an image first.");
      return;
    }

    const reader = new FileReader();
    reader.onloadend = () => {
      const base64encoded = reader.result.split(",")[1];

      const filePath = "images/capture_image.jpg";
      const apiURL = `https://api.github.com/repos/bloodstrawberry/auto-test/contents/${filePath}`;
      const accessToken = process.env.REACT_APP_MY_TOKEN;

      axios
        .put(
          apiURL,
          {
            message: "Add image",
            content: base64encoded,
            branch: "main", // Update with your branch name
          },
          {
            headers: {
              Authorization: `token ${accessToken}`,
              "Content-Type": "application/json",
            },
          }
        )
        .then((response) => {
          console.log(
            "Image uploaded successfully:",
            response.data.content.name
          );
        })
        .catch((error) => {
          console.error("Error uploading image:", error);
        });
    };

    reader.readAsDataURL(image);
  };

 

전체 코드는 다음과 같다.

import React, { useState } from "react";

import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";

import axios from "axios";

const Capture = () => {
  const [image, setImage] = useState(null);

  const handleImagePaste = (event) => {
    const items = (event.clipboardData || event.originalEvent.clipboardData).items;

    for (let i = 0; i < items.length; i++) {
      if (items[i].type.indexOf("image") !== -1) {
        const blob = items[i].getAsFile();
        setImage(blob);
        break;
      }
    }
  };

  const handleUpload = () => {
    if (!image) {
      console.error("Please select an image first.");
      return;
    }

    const reader = new FileReader();
    reader.onloadend = () => {
      const base64encoded = reader.result.split(",")[1];

      const filePath = "images/capture_image.jpg";
      const apiURL = `https://api.github.com/repos/bloodstrawberry/auto-test/contents/${filePath}`;
      const accessToken = process.env.REACT_APP_MY_TOKEN;

      axios
        .put(
          apiURL,
          {
            message: "Add image",
            content: base64encoded,
            branch: "main", // Update with your branch name
          },
          {
            headers: {
              Authorization: `token ${accessToken}`,
              "Content-Type": "application/json",
            },
          }
        )
        .then((response) => {
          console.log(
            "Image uploaded successfully:",
            response.data.content.name
          );
        })
        .catch((error) => {
          console.error("Error uploading image:", error);
        });
    };

    reader.readAsDataURL(image);
  };

  return (
    <Box sx={{ m: 3 }}>
      <Button
        sx={{ m: 2 }}
        component="label"
        variant="contained"
        startIcon={<CloudUploadIcon />}
        onClick={handleUpload}
      >
        GitHub Upload
      </Button>
      <div
        onPaste={handleImagePaste}
        style={{
          border: "1px solid #ddd",
          padding: "20px",
          textAlign: "center",
        }}
      >
        <h1>이미지 붙여넣기</h1>
        {image && <img src={URL.createObjectURL(image)} alt="Pasted" />}
      </div>
    </Box>
  );
};

export default Capture;

파일 덮어쓰기

 

현재 파일 이름을 고정했기 때문에 다시 파일을 업로드하면 아래와 같이 에러가 발생한다.

 

이 경우는 sha를 얻은 다음에 put을 하면 파일을 덮어쓸 수 있다.

handleUpload를 아래와 같이 변경하자.

  const handleUpload = () => {
    if (!image) {
      console.error("Please select an image first.");
      return;
    }

    const filePath = "images/capture_image.jpg";
    const apiURL = `https://api.github.com/repos/bloodstrawberry/auto-test/contents/${filePath}`;
    const accessToken = process.env.REACT_APP_MY_TOKEN;

    const reader = new FileReader();
    reader.onloadend = () => {
      const base64encoded = reader.result.split(",")[1];

      axios
        .get(apiURL, {
          headers: {
            Authorization: `token ${accessToken}`,
          },
        })
        .then((response) => {
          const sha = response.data.sha;

          axios
            .put(
              apiURL,
              {
                message: "Update image",
                content: base64encoded,
                branch: "main", // Update with your branch name
                sha: sha,
                committer: {
                  name: "bloodstrawberry",
                  email: "bloodstrawberry@gmail.com",
                },
                author: {
                  name: "bloodstrawberry",
                  email: "bloodstrawberry@gmail.com",
                },
              },
              {
                headers: {
                  Authorization: `token ${accessToken}`,
                  "Content-Type": "application/json",
                },
              }
            )
            .then((response) => {
              console.log(
                "Image updated successfully:",
                response.data.content.name
              );
            })
            .catch((error) => {
              console.error("Error updating image:", error);
            });
        })
        .catch((error) => {
          console.error("Error fetching existing image details:", error);
        });
    };

    reader.readAsDataURL(image);
  };

 

참고로 위의 코드는 파일이 이미 있는 경우에만 동작한다.

실제 코드에서는 파일이 존재한다면 기존 방식대로, 그렇지 않다면 위의 방식대로 하는 절차가 필요할 수 있다.

반응형

댓글