본문 바로가기
개발관련 이것저것

thumbnailator를 이용한 썸네일 이미지 생성

by 이상한나라의개발자 2024. 3. 12.

Thumbnailator는 Java에서 간단하고 편리하게 이미지 썸네일을 생성할 수 있는 라이브러리입니다. 사용하기 쉬운 API를 제공하여 이미지 크기 조정, 회전, 워터마크 추가 등 다양한 이미지 처리 기능을 쉽게 구현할 수 있습니다. 특히, 고품질 이미지 리사이징 알고리즘을 내장하고 있어, 썸네일 이미지의 품질을 유지하면서 빠르게 처리할 수 있습니다.

 

Thumbnailator의 주요 기능

  • 이미지 리사이징 : 원하는 크기로 이미지의 크기를 조절할 수 있습니다.
  • 이미지 회전 및 뒤집기 : 이미지를 원하는 각도로 회전시키거나 수평/수직으로 뒤집을 수 있습니다.
  • 워터마크 추가 : 이미지 워트마크 (텍스트 또는 이미지)를 추가하여 저작권을 표시할 수 있습니다.
  • 이미지 형식 변환 : JPEG, PNG 등 다양한 이미지 형식으로 변환할 수 있습니다.

 

Thumbnailator 사용하기

- gradle

implementation group: 'net.coobird', name: 'thumbnailator', version: '0.4.20'

 

- maven

<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.20</version>
</dependency>

 

다음은 저장된 이미지 파일의 경로를 가져와서 100*100 크기의 썸네일 이미지를 생성하고 반환하는 SpringBoot 기반의 예제 입니다.

thumbnailator은 텍스트를 워터마크로 사용하는 API는 제공하지 않습니다. 따라서, 워터마크를 사용 하기 위해 워터마크 이미지의 실제 경로를 입력해야 합니다. 

import net.coobird.thumbnailator.Thumbnails;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.file.Paths;

@RestController
public class ThumbnailController {

    @GetMapping("/thumbnail")
    public ResponseEntity<InputStreamResource> getThumbnail() throws Exception {
        String imagePath = "/Users/anthony/wonyoung.jpg"; // 이미지 파일 경로
        ByteArrayOutputStream os = new ByteArrayOutputStream();

        // 이미지를 100x100 크기로 리사이징하고 스트림에 저장
        Thumbnails.of(Paths.get(imagePath).toFile())
                .size(100, 100)
                .rotate(180) // 이미지를 180도 회전
                .watermark(Positions.BOTTOM_RIGHT, // 워터마크 위치를 오른쪽 하단으로 지정
                        Thumbnails.of(new File("/Users/anthony/watermark/mark.jpg")).size(50, 50).asBufferedImage(), // 워터마크 이미지 로드 및 크기 지정
                        0.5f) // 워터마크 투명도 설정 (0.0f ~ 1.0f)
                .toOutputStream(os);
        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());

        return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_JPEG)
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"thumbnail.jpg\"")
                .body(new InputStreamResource(is));
    }
}

 

ResponseEntity<InputStreamResource> 로 응답을 내려주게 되는데, 실제 dto 객체에 아래와 같이 속성을 추가하고 이미지 바이트를 직접 저장하여 응답을 할 수도 있습니다.

@Data
public class FileVO {
    private String name;
    private String size;
    private String fullPath;
    private byte[] byteArray;
}

 

 

ResponseEntity<ByteArrayResource> 대신에 FileVo에 직접 리턴한다면 아래와 같이 코드를 구성하시면 됩니다. 하지만 이미지 데이터를 JSON의 일부로 인코딩해서 전송하는 것은 일반적으로 권장되지 않습니다. 그 이유는 이미지 데이터가 크기 때문에 JSON 문자열이 매우 길어질 수 있고, 이로 인해 성능에 부정적인 영향을 줄 수 있게 때문입니다. ( 권장 X )

또한, Base64 인코딩은 바이트 데이터를 문자열로 변호나하는 과정에서 원래 데이터 크기보다 약 33% 증가합니다. 따라서 특히 큰 이미지 파일을 처리할 때는 이점을 고려해야 합니다.

@RestController
public class ThumbnailController {

    @GetMapping("/thumbnail")
    public ResponseEntity<FileVo> getThumbnail() throws Exception {
        String imagePath = "/Users/anthony/wonyoung.jpg"; // 이미지 파일 경로
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        FileVo fileVo = new FileVo();

        // 이미지를 100x100 크기로 리사이징하고 스트림에 저장
        Thumbnails.of(Paths.get(imagePath).toFile())
                .size(100, 100)
                .rotate(180) // 이미지를 180도 회전
                .watermark(Positions.BOTTOM_RIGHT, // 워터마크 위치를 오른쪽 하단으로 지정
                        Thumbnails.of(new File("/Users/anthony/watermark/mark.jpg")).size(50, 50).asBufferedImage(), // 워터마크 이미지 로드 및 크기 지정
                        0.5f) // 워터마크 투명도 설정 (0.0f ~ 1.0f)
                .toOutputStream(os);
        
        // 썸네일 이미지 데이터를 Base64 인코딩하여 저장
        String encodedImage = Base64.getEncoder().encodeToString(os.toByteArray());
        fileVo.setByteArray(encodedImage.getBytes());

        return fileEntity;
    }
}

 

화면에 출력하기 위해서는 서버로 부터 바이트 배열 형태의 이미지 데이터를 자바스크립트를 사용하여 Blob 객체로 변환하고URL.createObjectURL() 을 사용하여 Blob을 가르키는 URL을 생성할 수 있습니다. 이 URL을 img 태그의 src 속성에 설정하면 이미지가 화면에 표시 됩니다.

 

다음은 fetch API를 사용하여 서버로 부터 이미지 데이터를 받고, Blob 객체로 변환한 후 화면에 표시하는 코드 입니다.

<!DOCTYPE html>
<html>
<body>

<img id="image" width="100" height="100" />

<script>
// 이미지를 로드하는 함수
function loadImage(url) {
  fetch(url)
    .then(response => response.blob()) // 이미지 데이터를 Blob으로 변환
    .then(blob => {
      const imageUrl = URL.createObjectURL(blob); // Blob URL 생성
      document.getElementById('image').src = imageUrl; // 이미지 태그의 src 설정
    })
    .catch(error => console.error('Error loading the image:', error));
}

// 이미지 로드 함수 호출, 서버의 이미지 URL을 인자로 제공
loadImage('http://localhost:8080/thumbnail');
</script>

</body>
</html>

 

아래 코드는 view 페이지를 호출하기 위한 코드 입니다.

@GetMapping("/thumbnail/view")
public String view(Model model) {
    return "thumbnailview";
}