기존에는 프론트 측에서 주는 이미지 파일을 S3에 바로 업로드 하고, 원본 이미지를 프론트에서 바로 사용하도록 하였습니다. 이렇게 진행하다 보니 게시글의 리스트를 조회하는 부분에서 썸네일 크기보다 너무 큰 이미지를 호출하게 되었습니다. 그래서 프론트 측으로 부터 받는 이미지를 받을때 크기를 리사이징(OOOpx * OOOpx로 크기 조절, OOO은 선택)하여 추가적으로 썸네일용 이미지를 S3에 올리려고 합니다.
JAVA를 이용한 이미지 리사이징은 다음 라이브러리를 이용하여 가능합니다.
위 라이브러리들 중, 가장 간단한 방법은 1번 java.awt.Graphics2D였지만 생각보다 이미지가 많이 깨져 사용하지 않았습니다. 그 외에 다양한 라이브러리가 있지만 그 다음으로 간단하면서도 이미지가 잘 깨지지 않는다고 생각한 5번의 Marvin 라이브러리를 이용하였습니다.
우선 필요한 의존성을 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를 의존성에 추가해줍니다.
private String getThumbnailFileName(String serverFileName) {
return "s_" + serverFileName;
}
기존에 serverFileName은 UUID를 이용하여 서버 저장용 이름을 따로 생성하였습니다. 이 이름 앞에 "s_"를 붙여 줌으로써 썸네일용 이름이라는 것을 명시해줍니다.
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();
}
}
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에 대한 픽셀 값을 넘겨주도록 합니다.
이미지 업로드시 다음과 같이 원본과 썸네일용 이미지 총 2개가 생성되게 됩니다.
AWS S3에도 업로드 되어있는 것을 확인하였습니다.
이미지 리사이징 관련한 stackoverflow
How Can I Resize an Image Using Java?에 대한 글
이미지 리사이징 처리한 블로그