java / / 2023. 11. 3. 07:13

썸네일(Thumbnail) 생성 라이브러리

이미지 썸네일을 만드는 방법에는 여러가지가 있다. 자바가 아닌 라이브러리도 많이 있지만 호환성이나 특정 설치프로그램이 필요한 경우가 있어서 여기서는 자바로 생성하는 방법만 알아본다.

1. 썸네일 라이브러리

  • Java 코어를 이용
    • java.awt.Graphics2D
    • Image#getScaledInstance
  • 라이브러리 이용
    • Imgscalr
    • Thumbnailator
    • Marvin
    • Skija
  • Metadata 추출 (Thumbnail)
    • Metadata Extractor - 이미지 파일에서 썸네일 정보 추출

1) java.awt.Graphics2D

Graphics2D는 2차원의 Shape, text, image를 렌더링하는 기본 클래스이다.

사용법

public static BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException {
    BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
    Graphics2D graphics2D = resizedImage.createGraphics();
    graphics2D.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null);
    graphics2D.dispose();
    return resizedImage;
}

BufferedImage.TYPE_INT_RGB 파라미터는 이미지의 컬러 모델을 나타낸다.
지원 가능한 목록은 여기를 보면 된다. (official Java BufferedImage documentation)

Graphics2D는 RenderingHints라는 추가적인 파라미터가 있다. RenderingHints를 사용하여 이미지 품질 및 처리 시간을 개선하는데 사용할 수 있다.

graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

RenderingHints는 전체 목록은 this Oracle tutorial에서 확인할 수 있다.

2) Image.getScaledInstance()

Image를 사용한 방법이고 고품질의 이미지를 생성한다.

사용법

public static void resizeImage(String filename, String outputFilename) throws IOException {
    BufferedImage image = ImageIO.read(new File(filename));

    Image resizedImage = image.getScaledInstance(512, 384, Image.SCALE_DEFAULT);
    BufferedImage outputImage = new BufferedImage(512, 384, BufferedImage.TYPE_INT_RGB);
    outputImage.getGraphics().drawImage(resizedImage, 0, 0, null);

    ImageIO.write(outputImage, "JPEG", new File(outputFilename));
}

getScaledInstance()에서 flag를 지정함으로써 이미지 리샘플링하는데 사용될 수 있다.

Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);

사용 가능한 flag는 official Java Image documentation에서 확인할 수 있다.

3) Imgscalr

Imgscalr는 백그라운드에서 Graphic2D를 사용한다. 이미지 리사이징을 위한 몇 가지 API를 가지고 있다.

Imgscalr는 선택하는 옵션에 따라 가장 좋은 결과, 가장 빠른 결과 혹은 균형잡힌 결과를 제공한다. 또한 이미지 crop, 회전과 같은 다른 기능도 있다.

설치 방법

<dependency>
    <groupId>org.imgscalr</groupId>
    <artifactId>imgscalr-lib</artifactId>
    <version>4.2</version>
</dependency>

사용법

public static void resizeImage(String filename, String outputFilename) throws IOException {
    BufferedImage image = ImageIO.read(new File(filename));
    BufferedImage resizeImage = Scalr.resize(image, 512);
    ImageIO.write(resizeImage, "JPEG", new File(outputFilename));
}

라이브러리는 다양한 옵션이 있고 배경에서 이미지를 투명하게 처리한다.

가장 중요한 파라미터는 아래와 같다.

  • mode - 알고리즘이 사용하는 리사이즈 모드. 예를 들면 이미지 비율을 유지할지 여부 (AUTOMATIC, FIT_EXACT, FIT_TO_HEIGHT, FIT_TO_WIDTH)
  • method - 리사이즈 할 때 어디에 중점을 두어야 하는지. speed, quality or both. (AUTOMATIC, BALANCED, QUALITY, SPEED, ULTRA_QUALITY)

method의 SPEED와 ULTRA_QUALITY의 옵션 차이에 따른 속도차이는 실제 10배 정도 차이가 난다.

Imgscalr는 Java Image IO가 지원하는 모든 이미지 파일에서 동작한다. - JPG, BMP, JPEG, WBMP, PNG, and GIF. TIFF

4) Thumbnailator

Thumbnailator는 오픈소스 이미지 라사이징 라이브러리이며 기하급수적으로 사용량이 증가하고 있다.
JPG, BMP, JPEG, WBMP, PNG, and GIF를 지원한다.

설치 방법

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

사용법

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws Exception {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    Thumbnails.of(originalImage)
        .size(targetWidth, targetHeight)
        .outputFormat("JPEG")
        .outputQuality(1)
        .toOutputStream(outputStream);
    byte[] data = outputStream.toByteArray();
    ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
    return ImageIO.read(inputStream);
}

5) Marvin

Marvin은 이미지의 간단한 조작을 위한 툴이며 많은 유용한 기능(crop, rotate, skew, flip, scale)과 고급 기능(blur, emboss, texturing)을 제공한다.

설치 방법

<dependency>
    <groupId>com.github.downgoon</groupId>
    <artifactId>marvin</artifactId>
    <version>1.5.5</version>
    <type>pom</type>
</dependency>
<dependency>
    <groupId>com.github.downgoon</groupId>
    <artifactId>MarvinPlugins</artifactId>
    <version>1.5.5</version>
</dependency>

사용법

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) {
    MarvinImage image = new MarvinImage(originalImage);
    Scale scale = new Scale();
    scale.load();
    scale.setAttribute("newWidth", targetWidth);
    scale.setAttribute("newHeight", targetHeight);
    scale.process(image.clone(), image, null, null, false);
    return image.getBufferedImageNoAlpha();
}

6) Skija

Skia는 Jetbrains에서 개발한 다양한 하드웨어와 소프트웨어 플랫폼에서 지원하는 오픈 소스 2D 그래픽 라이브러리이다.
성능상 기존 Java 2D 툴킷보다 좋다.

Skija는 Skia를 위한 Java 바인딩이다. (Skia를 위한 Java 라이브러리)

설치 방법

<repositories>
    <repository>
        <id>space-maven</id>
        <url>https://packages.jetbrains.team/maven/p/skija/maven</url>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>org.jetbrains.skija</groupId>
        <artifactId>skija-macos-arm64</artifactId>
        <version>0.93.6</version>
    </dependency>
</dependencies>

의존성은 os 플랫폼별로 다르다.

org.jetbrains.skija:skija-windows:${version}
org.jetbrains.skija:skija-linux:${version}
org.jetbrains.skija:skija-macos-x64:${version}
org.jetbrains.skija:skija-macos-arm64:${version}

${version}에 버전을 명시하면 된다. 최신 버전 기준으로 0.96.3이다. (https://github.com/JetBrains/skija/blob/master/docs/Getting%20Started.md)

repository url은 https://packages.jetbrains.team/maven/p/skija/maven으로 지정하면 된다.

Skija는 java 9부터 지원한다.

사용법

Image image = Image.makeFromEncoded(new FileInputStream("./test.jpeg").readAllBytes());
Surface surface = Surface.makeRasterN32Premul(400, 300);
Canvas canvas = surface.getCanvas();
Paint paint = new Paint();
canvas.drawImageRect(image, new Rect(0, 0, 400, 300), paint);
Image newImage = surface.makeImageSnapshot();
Path path = Paths.get("./test-thumbnail.jpeg");
byte [] bytes = newImage.encodeToData().getBytes();
Files.write(path, bytes);

skija에서 지원하는 이미지 포맷은 아래와 같다.

  • jpeg
  • gif
  • bmp
  • png

그 외 tiff는 지원하지 않는 듯 하다.

https://github.com/JetBrains/skija

7) Metadata extractor

Metadata-extractor는 미디어 파일로 부터 메타데이타를 읽어들이는 라이브러리이다.

설치 방법

<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.8.1</version>
</dependency>

사용법

Metadata metadata = ImageMetadataReader.readMetadata(imagePath);

지원하는 파일 확장하는 아래를 확인하면 된다.

https://github.com/drewnoakes/metadata-extractor

2. 라이브러리 성능 검토

위에서 선정된 라이브러리를 대상으로 실제 이미지 파일의 썸네일을 생성하여 테스트를 한다.

테스트 장비
  • OS : macOS ventura 13.4
  • CPU: Apple M1 Max 10 core
  • RAM: 32GB
  • HDD: 512GB (SSD)
대상 이미지 파일
  • 해상도 : 4032 x 3024
  • 파일 크기: 2.9MB
  • 리사이즈 크기 : 200 x 150

위의 파일에 대한 썸네일 생성을 10회 반복하여 평균값을 측정해 본 결과이다.

실행 결과
실행 시간 썸네일 크기 지원 이미지 포맷 이미지 품질
Graphics2D 157.1 (ms) 10kb jpeg, bmp, tiff, gif, png
ScaledInstance 329.5 (ms) 10kb jpeg, bmp, tiff, gif, png
Imgscalr 149.7 (ms) 10kb jpeg, bmp, tiff, gif, png
Thumbnailator 319.9 (ms) 8kb jpeg, bmp, tiff, gif, png
Marvin 452.9 (ms) 10kb jpeg, bmp, tiff, gif, png
Skija 54.9 (ms) 75kb jpeg, bmp, gif, png
tiff 지원안함
Metadata Extractor 2.6 (ms) 49kb jpeg

Metadata Extractor가 압도적으로 빠르다. 하지만 Metadata Extractor를 사용하기 위해서는 이미지 파일 안에 썸네일 정보가 포함되어 있어야 한다. 이미지에 썸네일 정보가 없으면 metadata extractor로 썸네일을 추출할 수 없다.

카카오톡으로 이미지를 전송하는 경우는 보통 썸네일 정보가 포함되지 않은 경우가 많으므로 사용할 수가 없다. 그래서 카카오톡으로 이미지 전송을 많이 하는 경우는 metadata extractor를 기본으로 사용할 수가 없다.

그 다음으로 사용할 수 있는 라이브러리는 SkijaImgscalr이다.

Metadata Extractor 다음으로 생성 시간에서 가장 빠른 라이브러리는Skija이다. 단, Skija는 Java 9부터 사용이 가능하고 tiff 포맷을 지원하지 않는다. 기본적으로 Skija를 사용하는 게 좋을 것 같지만 Java 8을 사용한다면 Imgscalr를 사용하는 것이 좋을 듯 하다.

멀티 쓰레드 환경

멀티 쓰레드 환경에서 테스트를 해봐도 위의 성능과 유사하게 나타난다.

결론

썸네일 라이브러리 선택은 환경에 따라 다를 수 있지만 우선 선택할 수 있는 요소는 3가지 정도인 듯 하다. 아래의 장단점이 있으니 상황에 맞게 사용하면 된다.

  • Metadata Extractor
    • 속도 엄청 빠름
    • metadata가 포함되어 있는 이미지(jpeg)만 가능 (카카오톡 고화질로 전송된 이미지)
  • Skija
    • 속도 빠름
    • 대부분 이미지 포맷 지원 (jpeg, gif, png, bmp)
    • tiff 지원안함
    • Java 9부터 사용가능
    • OS/CPU별 다른 라이브러리 선택해야 함
  • Imgscalr
    • 속도 무난
    • 모든 이미지 포맷 지원

참고

https://www.baeldung.com/java-resize-image

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유