(Java) Animated GIF 썸네일 생성하기

유인근·2021년 3월 1일
0

Java

목록 보기
1/2
post-thumbnail

About

Java에서 GIF 파일의 썸네일을 만드는 작업을 진행하면서, 작업한 과정과 방법에 대해 기록해 보고자 한다 : )

To Do

GIF 파일은 여러 개의 정적 이미지 프레임을 이어붙인 동적 이미지 파일이다. 이때 GIF의 여러 프레임 중 원하는 프레임만 추출하여, 썸네일 크기만큼 크기를 줄여서 다시 새로운 GIF 파일로 이어붙이는 작업이 필요하다. 즉, GIF 썸네일 파일도 곧 새로운 GIF 파일로 생성하려고 한다. 이에 대한 대략적인 순서를 요약해보면 다음과 같다.

  1. 원하는 프레임을 추출
  2. 프레임을 원하는 썸네일 크기만큼 리사이징
  3. 다음 프레임으로 전환되는 시간(지연 시간)을 설정
  4. 프레임을 다시 이어붙여서 새로운 GIF 파일 생성

이 글에서는 1, 4(3번 포함)번의 방법과 과정에 대해 기록하고자 한다.
(만약, GIF 썸네일을 정적인 하나의 이미지로만 생성해내려면 1, 2번의 과정만 있으면 될 거 같다)

원하는 프레임 추출하기

처음에는 GIF도 곧 여러 개의 정적 이미지들을 이어붙인 이미지 파일이기 때문에, javax의 javax.imageio 사용을 시도해봤다. 하지만 GIF 파일에서 원하는 프레임을 추출할 때, javax의 ImageIO.read 함수를 사용하게 되면 ArrayIndexOutOfBoundsException: 4096가 발생하는 고질적인 문제가 있었다.

그래서 이 문제를 해결한 관련 오픈 소스를 찾아보다가 GIF 파일을 디코딩 할 수 있는 기능을 구현한 오픈 소스(https://github.com/rtyley/animated-gif-lib-for-java)를 알게 되었고, 시도해본 결과 사용법도 어렵지 않고 큰 이슈 없이 동작이 잘 되는 것을 확인해서 사용하게 됐다.

InputStream targetStream = new FileInputStream(new File(""));
GifDecoder gifDecoder = new GifDecoder();
gifDecoder.read(targetStream);
BufferedImage image = gifDecoder.getFrame(0); // 인덱스에 해당하는 프레임 추출

사실 처음에는 다른 오픈 소스(https://github.com/DhyanB/Open-Imaging) 사용을 시도했는데, 나중에 여러 GIF 파일로 테스트해보면서 일부 GIF 프레임을 뽑아낼 때 이미지가 깨져보이는 문제가 발생했었다. 오픈 소스 레포를 다시 보니, 관련한 문제가 이미 이슈로 생성되어 있었고 최근 커밋이 2년 전인 걸로보아 바로 개발이 진행되지 않을 거 같았다. 그래서 호기롭게 '내가 관련 코드를 분석해보고 해결해보자!' 라고 시도해봤지만, 정확히 어떤 속성을 가진 파일 때문에 발생하는 문제인지 부터가 파악이 안되서 포기했다...

프레임 이어붙여서, 새로운 GIF 파일 생성

위에서 추출한 여러 프레임을 이어 붙이는 작업은 Memorynotfound라는 사이트의 레퍼런스(https://memorynotfound.com/generate-gif-image-java-delay-infinite-loop-example/)를 참고해서 진행했다. 여러 레퍼런스나 오픈 소스 등을 살펴봤지만 내가 필요한 부분만 코드로 잘 정리되어 있어 채택하게 됐다.

final int DELAY_TIME = 500; // 다음 프레임으로 전환되는 지연 시간(ms)
ImageOutputStream imageOutputStream = new FileImageOutputStream(new File(""));
GifSequenceWriter gifSequenceWriter = new GifSequenceWriter(imageOutputStream, gifDecoder.getFrame(0).getType(), DELAY_TIME, true);

하지만 해당 코드를 사용하다가 배경이 투명인 GIF를 다루는 과정에서, 다음 프레임으로 이미지가 바뀔 때 이전 이미지가 없어지지 않고 남아있는 문제가 발생했다. 관련한 문제를 조사해보니, GIF 파일에는 새로운 프레임을 보여줄 때 이전 프레임에 대한 처리 방법을 지정하는 disposal method라는 속성이 있다는 것을 알았다.
(* GIF 속성 관련 레퍼런스: https://docstore.mik.ua/orelly/web2/wdesign/ch23_05.htm)

그래서 위 레퍼런스를 참고하여 disposal method 설정 값을 restoreToBackgroundColor로 수정해줌으로써 관련 문제를 해결할 수 있었다.

결과

  • 원본 크기: 424 x 424 (px)
  • 썸네일 크기: 300 x 300 (px)
  • 썸네일 프레임 개수: 4개
  • 지연 시간: 0.5s

(원본이 첫번째 GIF, 썸네일이 두번째 GIF)

느낀점

GIF와 같이 파일을 다루는 작업을 해본 적이 거의 없어서, 작업이 어렵다기 보다는 생소하고 문제가 발생했을 때 어떻게 해결해야할지 막막했던 경우가 많았다. 이때 오픈 소스를 활용해보고 이슈가 발생하면 관련 레퍼런스를 찾아보면서 어떻게든 해결할 수 있었다. 이때 오픈 소스를 사용하면서 얻은 교훈은 단순히 오픈 소스가 당장 잘 동작한다고 바로 채택하는 것이 아니라, 사용하기 전에 관련 이슈에는 어떤 것들이 있고 나중에 어떤 문제로 작용할지 꼼꼼하게 확인해보는 게 중요하다고 느꼈다. 이미 알려진 이슈임에도 나처럼 확인하지 않고, 나중에 알게 된 이슈 때문에 문제가 되기 전에 말이다.

다음 글에서는 Java에서 ffmpeg을 활용한 동영상 파일 다루기(압축, 썸네일 생성, 재생시간 추출 등)에 대한 내용을 작성해보고자 한다.

profile
끊임없이 성장하는 개발자 🔥

0개의 댓글