[Node.js] multer로 이미지 업로드 & sharp로 이미지 리사이징

JNETiii·2021년 6월 17일
4

Backend

목록 보기
1/3

❓Multer란

Multer란 파일을 업로드 하기 위한 node.js 미들웨어이다.

❓Sharp란

Sharp란 node.js에서 이미지를 처리하기 좋은 패키지이다.

1. 준비

multer와 sharp install하기

npm install multer --save
npm install sharp --save

모듈 가져오기

const multer = require("multer");
const sharp = require("sharp");

2. 이미지가 저장될 파일 만들기

나는 server의 uploads 파일에 이미지를 업로드 할 것이기 때문에 uploads 파일이 없으면 만들어주는 코드를 먼저 구현하였다.

// uploads 폴더 없으면 생성
fs.readdir("uploads", (err) => {
  if (err) {
    fs.mkdirSync("uploads");
  }
});

3. Multer를 통해 이미지 업로드 구현

이때, 사용자가 같은 이름의 이미지를 두 번 업로드 할 경우, 이미 uploads 파일에 있는 이미지가 또 업로드 되기 때문에 오류가 발생한다!

그러므로 파일명을 확실하게 구분해 줄 나만의 규칙이 필요하다. 여기서 나는 기존파일명 + 시간 + 확장자 로 저장하였다.

const upload = multer({
  storage: multer.diskStorage({	// 파일이 저장될 경로
    destination(req, file, cb) {
      cb(null, "uploads/");
    },
    filename(req, file, cb) {
      const ext = path.extname(file.originalname);	// 파일 확장자
      const timestamp = new Date().getTime().valueOf();	// 현재 시간
      // 새 파일명(기존파일명 + 시간 + 확장자)
      const filename = path.basename(file.originalname, ext) + timestamp + ext;
      cb(null, filename);
    },
  }),
});

4. 이미지를 업로드하는 라우트 구현

이미지를 업로드하는 라우트의 미들웨어로 위에 작성한 uploads를 사용한다.

// 이미지를 업로드하는 라우트
router.post("/upload", upload.single("selectImg"), (req, res) => {
  res.json({ filename: `${req.file.filename}` });
});

(여기서 "selectImg"는 프론트에서 FormData를 생성 할 때 명시한 것이다 .)

// form data 생성 => 프론트
const formData = new FormData();
formData.append("selectImg", image);

5. Sharp로 이미지 리사이즈(파일크기 압축효과..!)

마이페이지에서 프로필 이미지 로딩 시간이 길어져서 이미지를 압축했다.
이미지를 업로드하는 라우트를 수정하였다.

// 이미지를 업로드하는 라우트
router.post("/upload", upload.single("selectImg"), (req, res) => {
  try {
    sharp(req.file.path)  // 압축할 이미지 경로
      .resize({ width: 600 }) // 비율을 유지하며 가로 크기 줄이기
      .withMetadata()	// 이미지의 exif데이터 유지
      .toBuffer((err, buffer) => {
        if (err) throw err;
        // 압축된 파일 새로 저장(덮어씌우기)
        fs.writeFile(req.file.path, buffer, (err) => {
          if (err) throw err;
        });
      });
  } catch (err) {
    console.log(err);
  }
  res.json({ filename: `${req.file.filename}` });
});

이미지의 크기를 변경할 경우 이미지의 exif데이터가 손실되는데, exif데이터에는 이미지의 방향 정보가 들어있다. 이미지가 멋대로 회전되지 않게 하기 위해서 exif데이터를 유지시켜주는 .withMedata()를 5번째 줄에 추가한다.

fs.writeFile()을 통해 이미지를 저장해주면 기존 파일을 덮어씌우기 때문에 기존 파일을 삭제할 필요도 없고 충돌로 인한 오류도 나지 않는다.

결론

sharp로 이미지를 리사이즈 시켜주면 이미지의 크기가 3MB에서 25KB로 줄어드는 것을 확인할 수 있다. 더 빠른 페이지를 구현하기 위해 이미지 압축을 하는 습관을 들이자..!

profile
도전자 | 개발자

0개의 댓글