박주니 개발 정리

엑셀업로드시 ipfs url 이미지 전환 삽입 방법 본문

react

엑셀업로드시 ipfs url 이미지 전환 삽입 방법

박주니 2023. 9. 9. 14:06
728x90
반응형

설명 이유)

마켓을 운영하다보면 리스트를 확인할 때 해당 상품에 이미지도 엑셀에 필요할 때가 있습니다. 저는 이미지를 ipfs형식으로 전환해서 불러오기 때문에 <img>에 src로 url 넣으면 이미지가 나오지만 엑셀 적용은 다른 방식이기 때문에 공유하게 되었습니다. 

 

먼저 이 설명을 듣기 전에 엑셀 업로드시 데이터 적용 방법 참고하시기 바랍니다.

엑셀 업로드해서 데이터 적용하는 방법은 동일합니다. 그부분에서 rowData에 image_url을 추가해서 삽입하는 과정이라고 생각하시면 됩니다. 

 

1. ipfs url 을 따로 데이터를 rowData에서 제외해서 진행합니다. 

        const assetKeys = Object.keys(asset);
        assetKeys.forEach((id, i) => {
          console.log("id 확인: ", id);
          const rowData = [
            { value: "" }, // A열에 이미지 URL 값, 없으면 빈 문자열
			...
          ];
          // [rowData], 
          data.push(rowData);

          // 이미지는 별도 관리 -> { value: "" } A열에 들어갈 것이기 때문에 공란 처리
          const ipfsImageUrl = asset[id]?.image_url || "";
          if (ipfsImageUrl) {
			
          }
        });

설명)

  1. assetKeys는 예를 들어서 asset 데이터가 배열 형식으로 들어가져 있을 때 예를 들어서 값이 두개 들어가져 있을 때 console.log(assetKeys)를 하게 되면 [0, 1]이 나오게 됩니다. 
  2. rowData에 header을 제외한 첫번째 row에 해당되는데 값을 "" 빈 값으로 넣은 이유는 그 부분에 ipfs 이미지를 삽입하기 위함입니다. 만약에 첫번재줄에 값을 넣게 되면 중복해서 들어가게 됩니다. 
  3. ipfsImageUrl을 rowData에 한번에 넣지 않은 이유는 이미지 삽입하는 방식은 일반적으로 텍스트를 넣는 방식과는 다르고 또 별도로 jpg로 전환하는 과정을 거쳐야하기 때문에 분리를 했습니다. 

2. ipfs url을 이미지로 가져올 수 있는 함수를 구현합니다. 

        // IPFS 이미지를 가져오는 비동기 함수
        const fetchIpfsImage = async (ipfsImageUrl) => {
          try {
            console.log(ipfsImageUrl);
            const ipfsHash = ipfsImageUrl.match(/\/ipfs\/([a-zA-Z0-9]+)/)[1];
            const response = await axios.get(
              `https://ipfs.io/ipfs/${ipfsHash}`,
              {
                responseType: "arraybuffer",
              }
            );
            return response.data;
          } catch (error) {
            console.error("IPFS 이미지를 가져오는 중 오류 발생:", error);
            return null;
          }
        };

설명)

ipfsImageUrl은 1번에서 asset image_url에 해당되는 값입니다. 

먼저 ipfs url 형식은 https://crepas.mypinata.cloud/ipfs/QmWzxPgun9iDPz319sitnDfNSUi1GxMusAkqrS7QiriR25 이렇게 되어있습니다. 

  1. ipfsHash : ipfs/기준으로 뒤에 있는 값들을 가지고 오는 것입니다. QmWzxPgun9iDPz319sitnDfNSUi1GxMusAkqrS7QiriR25 
  2. response.data를 확인해보면 해당 ipfs에 arraybuffer 형식으로 저장된 것을 확인하실 수 있습니다. 

3. arraybuffer 형식으로 된 것을 base64로 인코딩을 진행합니다. 지금 이순서는 1번 코드에 이어서 진행하시면 됩니다. 

          if (ipfsImageUrl) {
            const promise = fetchIpfsImage(ipfsImageUrl)
              .then((imageData) => {
                if (imageData) {
                  // ArrayBuffer -> ipfs 이미지를 가지고 오게 됨
                  // 이미지를 Base64로 인코딩
                  const base64Image = Buffer.from(imageData).toString("base64");
                  return `data:image/jpeg;base64,${base64Image}`;
                }
                return null;
              })
              .catch((error) => {
                console.error("IPFS 이미지를 가져오는 중 오류 발생:", error);
                return null;
              });

            imagePromises.push(promise); // 이미지 다운로드 프로미스를 배열에 추가
          }

설명)

imageData는 fetchIpfsImage 함수 즉 arraybuffer을 전환한 값에 해당될 것입니다. 

return 을 통해 ipfs가 base64 인코딩 되어 이미지를 넣을 수 있는 상태가 되었습니다. 

imagePromises 배열에 현재 인코딩된 값들을 따로 넣습니다. 

 

4. 엑셀 업로드시 해당 이미지를 column 0행 즉 A행에 넣을 수 있게 구현합니다. 

        // Promise.all()는 Promise 객체들의 배열을 받아와서 모든 Promise가 완료될 때까지 기다리는 역할을 함
        Promise.all(imagePromises)
          .then((imageDataArray) => {
            // null인것들을 있을 경우 제외하고 다른 데이터 가져와서 처리
            const filteredImageDataArray = imageDataArray.filter(Boolean);

            // 모든 행에 대한 높이를 조절합니다.
            data.slice(1).forEach((rowData, rowIndex) => {
              const targetRowHeight = 50; // 원하는 높이 (단위: 픽셀)
              row.height = targetRowHeight;

              // 이미지 데이터를 사용하여 엑셀 워크시트에 이미지 추가
              if (filteredImageDataArray[rowIndex]) {
                const imageId = workbook.addImage({
                  base64: filteredImageDataArray[rowIndex],
                  extension: "jpeg",
                });

                // 이미지를 A열에 추가
                worksheet.addImage(imageId, {
                  tl: { col: 0, row: rowIndex + 1 }, // 이미지를 넣을 셀의 열과 행 지정 (index + 2는 헤더 행과 0부터 시작하는 인덱스 보정)
                  ext: { width: 60, height: 60 }, // 이미지 크기 조절
                });
              }
            });

          })
          .catch((error) => {
            console.error("전체 프로세스 중 오류 발생:", error);
          });
      } else {
        setScreen(true);
        alert("리스트 다시 확인해주시길 바랍니다.");
      }

설명)

1. Promise.all(imagePromises).then().catch() 

지금 이부분이 가장 중요한 것이 ipfs가 몇개 안될 때는 빨리 진행이 되는데 예를 들어서 10개만 넘어가도 느려지고 제대로 이미지가 안들어가는 이슈가 발생됩니다. 그런데 Promise.all(imagePromises)를 사용하게 되면 한마디로 현재 ipfs가 base64가 인코딩 된것이 확인되면 그 다음 순서로 진행될 수 있게 한다는 의미이기 때문에 ipfs 이미지 삽입하는 부분에 있어서 Promise.all을 알 수 있어서 이슈를 해결할 수 있었습니다.

2. imageId에 jpeg를 셋팅해서 worksheet에 별도로 이미지를 넣고 위치는 tl에서 col은 행에 해당되고 0일경우에는 A행에 해당이 됩니다.  row: rowIndex+1 즉 순차적으로 이미지를 A행 1열부터 순차적으로 넣는것을 의미합니다. 

 

여기에 제가 초반에 엑셀 업로드 데이터 셋팅하는 방법 정리한 것과 병합해서 진행하시면 가능하게 될 것입니다. 

tip)

그래도 어떻게 해야할 지 모르신다면 제가 초반에 올린 엑셀 업로드 하는 방법과 지금 이미지 삽입방법을 chatgpt에 코드를 넣어서 현재 이코드가 정상적으로 돌아갈 수 있게 수정해서 코드 알려줘하면 전체적인 코드가 나올 것입니다. 

728x90
반응형
Comments