[개발] 이미지 리사이징한 썸네일 생성

이진규·2023년 3월 30일
1

시작

기존에는 프론트 측에서 주는 이미지 파일을 S3에 바로 업로드 하고, 원본 이미지를 프론트에서 바로 사용하도록 하였습니다. 이렇게 진행하다 보니 게시글의 리스트를 조회하는 부분에서 썸네일 크기보다 너무 큰 이미지를 호출하게 되었습니다. 그래서 프론트 측으로 부터 받는 이미지를 받을때 크기를 리사이징(OOOpx * OOOpx로 크기 조절, OOO은 선택)하여 추가적으로 썸네일용 이미지를 S3에 올리려고 합니다.

SpringBoot를 이용한 이미지 리사이징

JAVA를 이용한 이미지 리사이징은 다음 라이브러리를 이용하여 가능합니다.

  1. java.awt.Graphics2D
  2. Image.getScaledInstance()
  3. Imgscalr
  4. Thumbnailator
  5. Marvin

위 라이브러리들 중, 가장 간단한 방법은 1번 java.awt.Graphics2D였지만 생각보다 이미지가 많이 깨져 사용하지 않았습니다. 그 외에 다양한 라이브러리가 있지만 그 다음으로 간단하면서도 이미지가 잘 깨지지 않는다고 생각한 5번의 Marvin 라이브러리를 이용하였습니다.

썸네일 구현

1. Marvin Library 의존성 추가

우선 필요한 의존성을 build.gradlew에 추가 해줍니다.

implementation 'com.github.downgoon:marvin:1.5.5'
implementation 'com.github.downgoon:MarvinPlugins:1.5.5'
implementation 'org.springframework:spring-test'

Marvin 라이브러리를 사용하기 때문에 Marvin, MarvinPlugins 의존성을 추가 해줍니다.
그리고 MultipartFile로 이미지를 받고 있어, 이미지 파일을 BufferedImage로 변환하고 다시 MultipartFile로 변환할 때 MockMultipartFile를 사용하기 위해 spring-test를 의존성에 추가해줍니다.

2. 썸네일 용 이름 생성

private String getThumbnailFileName(String serverFileName) {
	return "s_" + serverFileName;
}

기존에 serverFileName은 UUID를 이용하여 서버 저장용 이름을 따로 생성하였습니다. 이 이름 앞에 "s_"를 붙여 줌으로써 썸네일용 이름이라는 것을 명시해줍니다.

3. 이미지 리사이징

private MultipartFile resizeAttachment(String fileName, String fileFormatName, MultipartFile multipartFile,
		int targetWidth, int targetHeight) {

		try {
        	// MultipartFile -> BufferedImage Convert
			BufferedImage image = ImageIO.read(multipartFile.getInputStream());

			// 원하는 px로 Width와 Height 수정
			int originWidth = image.getWidth();
			int originHeight = image.getHeight();
			
            // origin 이미지가 resizing될 사이즈보다 작을 경우 resizing 작업 안 함
			if (originWidth < targetWidth && originHeight < targetHeight)
				return multipartFile;

			MarvinImage imageMarvin = new MarvinImage(image);

			Scale scale = new Scale();
			scale.load();
			scale.setAttribute("newWidth", targetWidth);
			scale.setAttribute("newHeight", targetHeight);
			scale.process(imageMarvin.clone(), imageMarvin, null, null, false);

			BufferedImage imageNoAlpha = imageMarvin.getBufferedImageNoAlpha();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ImageIO.write(imageNoAlpha, fileFormatName, baos);
			baos.flush();

			return new MockMultipartFile(fileName, baos.toByteArray());

		} catch (IOException e) {
        	// 파일 리사이징 실패시 예외 처리
			throw new FailResizeAttachment();
		}
	}

3-1 인자 넘기기

  1. fileName에는 위에서 생성한 썸네일용 이름을 넘겨주도록 합니다.
  2. fileFormatName에는 원본 파일에 대한 포맷을 따로 추출하여 넘겨주도록 합니다.
private String getFileFormatName(MultipartFile file) {
	return file.getContentType().substring(file.getContentType().lastIndexOf("/") + 1);
}

위의 함수를 실행하면 다음과 같이 jpeg파일의 경우 jpeg, png파일의 경우 png로 포맷이 추출됩니다.

3. multipartFile에는 원본 파일을 넘겨 주도록 합니다.
4. targetWidth에는 원하는 Width에 대한 픽셀 값을 넘겨주도록 합니다.
5. targetHeight에는 원하는 Height에 대한 픽셀 값을 넘겨주도록 합니다.

3-2 작업

  1. MarvinImage 객체의 경우, BufferedImage 를 통해 생성이 되기 때문에 먼저 MultipartFile을 BufferedImage로 변경합니다.
  2. origin 이미지가 resizing될 사이즈보다 작을 경우 resizing 작업 안 하도록 설정합니다.
  3. Scale 객체에 의해 기존 이미지 파일의 width, height를 변경하여 BufferedImage로 변환하였습니다.
  4. MockMultipartFile을 이용해 다시 BufferedImage를 MultipartFile로 변경 후 return 해주도록 합니다.

4. 결과

이미지 업로드시 다음과 같이 원본과 썸네일용 이미지 총 2개가 생성되게 됩니다.

AWS S3에도 업로드 되어있는 것을 확인하였습니다.

참고자료

이미지 리사이징 관련한 stackoverflow
How Can I Resize an Image Using Java?에 대한 글
이미지 리사이징 처리한 블로그

profile
항상 궁금해하고 공부하고 기록하자.

0개의 댓글