본문 바로가기

3.구현/Java or Kotlin

[java] java에서 ImageMagick 사용하기

들어가기

자바에 있는 ImageIO를 사용해서 이미지를 간단하게 처리는 코드를 작성하였는데 문제가 발생하였다. PNG 파일을 읽어오데 에러가 발생하였고 확인해보니 ImageIO에서 깨진 PNG 파일을 읽어오는 경우 발생하였다. 인터넷을 검색을 해보았지만, 대부분은 단순 파일 업로드나 이미지를 처리하다가 에러가 발생하면 처리하지 않고 파일로 저장한다. 그래서 다른 라이브러리를 찾아보았지만, 비슷했다. 결국 찾은게 ImageMagick이었다. 자바용으로 jMagic이 있었고 JNI를 사용하여 ImageMagick 라이브러리를 호출하는데 호환성 문제가 있었다. 다음으로 찾은게 im4java이다. 이는 ImageMagick의 명령어를 대신해서 호출해주는 라이브러리이다. 이제 ImageMagick를 하나씩 살펴보자.

작성자: http://ospace.tistory.com/ (ospace114@empal.com)

환경구성

일단 메이븐 기반으로 간단한 환경을 구성해보자.

ImageMagick 설치

먼저 ImageMagick를 다운받아서 설치해보자.

https://www.imagemagick.org/script/download.php

OS에 맞게 설치하면 된다. 아래 링크는 윈도우 바이너리 ImageMagick-7.0.8-33-portable-Q16 버전 파일이다.

Portable가 아닌 다른 버전을 설치하면 원하는 툴이 아닌 버전으로 설치되기 때문에 im4java에서 사용할 수 없게 된다. 반드시 portable 버전을 설치해야 한다.
윈도우즈가 아닌 centos인 경우는 설치가 더 간단하다. 굳이 다운받아서 설치할 필요없이 yum를 사용해서 설치하면 된다.

$ yum install imagemagick

im4java 설치

다음으로 im4java를 설치해보자. 물론 직접 받아서 설치할 수도 있지만 maven dependency를 추가해보자.

<dependency>
    <groupId>org.im4java</groupId>
    <artifactId>im4java</artifactId>
    <version>1.4.0</version>
</dependency>

버전은 적당한 버전을 지정하면 된다. 버전 정보는 메이븐 리포지토리에서 확인할수 있다.

https://mvnrepository.com/artifact/org.im4java/im4java

여기까지 끝났으면 기본적인 환경설정은 마친상태이다. 이제 부터 본격적인 예제를 살펴보자.

imageMagic 경로 설정

im4java에서 ImageMagick 명령을 호출하기 위해서 추가적인 설정이 필요하다. im4java가 imageMagic를 호출하기 위해서 설치된 위치를 알아야한다. 그렇기 때문에 imageMagic 명령어 있는 경로를 설정해줘야 제대로된 명령을 호출할 수 있다.
설정하는 방식이 3가지가 있다. 하나는 전역적으로 설정하는 방식과 명령어 별로 설정하는 방식이고 마지막으로 환경변수가 있다.

전역 설정

전역 설정은 setGrobalSearchPath()로 설정할수 있다. 이후 모든 명령어에 적용된다.

String impath = "path/ImageMagick-7.0.8/";
ProcessStarter.setGlobalSearchPath(impath);

지역설정

지역설정은 ConverCmd 개체를 생성하고 setSecurityPath() 메소드로 설정할수 있다. 이후 해당개체를 통한 명령어에 적
용된다.

String impath = "path/ImageMagick-7.0.8/";
ConvertCmd cmd = new ConvertCmd();
cmd.setSearchPath(impath);

환경변수

전역설정을 했다면 별다르게 추가 설정은 필요없지만, 지역설정을 할경우는 매번 명령 호출할 때마다 설정해야한다. 다른 방법으로는 IM4JAVA_TOOLPATH 환경변수를 설정해줘도 된다. 환경변수는 이시스템에서 실행되는 모든 im4java에 적용된다.

set IM4JAVA_TOOLPATH="path/ImageMagick-7.0.8/"

물론 운영체제에 맞게 환경변수를 설정해주면 된다. path는 ImageMagic가 설치된 경로이다.

이미지 리사이즈

먼저 간단하게 이미지 크기를 라사이즈 해보자. 이제 부터는 ImageMagick 툴을 제대로 활용하는 방법을 알고 있어야 한다. im4java는 ImageMagick 툴을 호출하는데 쉽게 호출해줄 뿐이지 궁극적으로 ImageMagick를 호출하는 명령어를 만들어서 대신 호출해줄 뿐이다.

im4java에서는 기본적으로 ConvertCmd로 convert 명령을 호출한다. 그때 사용하는 명령을 IMOperation으로 설정한다. 중요한 부분은 IMOperation에서 addImage()로 처리할 이미지를 추가하는데 순서가 중요하다. 별도로 입력 이미지나 저장할 이미지로 분리해서 지정하지 않는다. 순전히 ImageMagick의 명령에 입력되는 순서에 따라서 입력된다. 간단한 예제를 살펴보자.

ConvertCmd cmd = new ConvertCmd();

IMOperation op = new IMOperation();
op.addImage("img.png");
op.resize(200,200);
op.addImage("img_s.jpg");

cmd.run(op);

처음 addImage()로 입력되는 "img.png" 파일이 입력 이미지이고, 추가 연산으로 리사이즈가 폭 200px, 높이 200px으로 변경한다. 마지막으로 addImage()에서 입력되는 "img_s.png"는 최종 출력되어 저장되는 이미지이다. 이는 ImageMagick의 convert의 명령어를 입력해보면 대충 어떤 의미인지 알게된다. 필자도 처음에 이를 알지 못해서 혼동을 했지만, 입력되는 순서와 실제 생성되는 명령어 순서와 일치하기 때문에 입력되는 순서만 주의하면 된다.
위의 예제는 단순히 보면 이미지 크기를 줄이는 명령이기에 썸네일 이미지 생성과 동일한 과정이다. im4java에서는 썸네일 이미지 만드는 명령이 따로 있다. 물론 정확히 말하면 ImageMagick에서 별도 명령이 존재한다.

ConvertCmd cmd = new ConvertCmd();

IMOperation op = new IMOperation();
op.addImage("img.png");
op.thumbnail(200,200);
op.addImage("img_s.jpg");

cmd.run(op);

항상 IMOperation에서 명령 옵션을 설정하지만 실제 명령을 실행하는 곳은 ConvertCmd에서 실행해야 한다.

두개 이미지 조합

두개의 이미지를 합성하는 예제이다. 여기서는 단순히 이미지를 겹치는 효과만 살펴보려고 한다. 먼저 예제를 보자.

ConvertCmd cmd = new ConvertCmd();

IMOperation op = new IMOperation();
op.addImage("img.png");
op.addImage("logo.png");
op.gravity("SouthEast");
op.composite();
op.addImage("img_logo.png");

cmd.run(op);

이번에는 이미지가 3개가 입력되었다. 그리고 gravity()가 있는데 이미지 합성하는데 2번째 이미지의 기준 위치를 기정한다. 그리고 composite()를 사용해서 이미지를 합성한다고 지정하고, 마지막 이미지가 저장할 파일을 가리킨다.
앞의 예제는 ConvertCmd를 사용해서 합성했지만 composite명령을 사용하는 CompositeCmd도 사용가능하다. 이미지가 겹쳐지는 순서가 있기 때문에 composite에서는 먼저 노출될 이미지를 처음에 놓아야 한다. ConvertCmd와는 순서가 반대이기 때문에 주의가 필요하다.

CompositeCmd composite = new CompositeCmd();

IMOperation op = new IMOperation();
op.blend(50);
op.addImage("logo.png");
op.addImage("img.png");
op.gravity("SouthEast");
op.addImage("img\_logo.png");

composite.run(op);

명령어 재사용?

마지막으로 명령어 재사용을 해보자. 앞의 예제는 이미지를 처리할 때마다 매번 생성하고 설정해고 실행을 해야하는 과정을 거친다. 대부분의 작업이 동일한 작업을 반복하기 때문에 재사용이 필요하게 된다. 특히 이미지 처리에서 보면 처리할 파일이 달라지고 처리되는 연산은 동일한 경우가 대부분이다. 이런 작업을 im4java에서 지원하고 있다. 간단하게 앞의 이미지 리사이즈를 가지고 살펴보자.

ConvertCmd cmd = new ConvertCmd();

IMOperation op = new IMOperation();
op.addImage();
op.resize(200,200);
op.addImage();

cmd.run(op, "img.png", "img_s.jpg");

addImage()를 실행할 때에 파일명이 없이 추가하고 있다. 빈 템플릿을 추가한다고 보면된다. 이미지 리사이즈는 입력 이미지와 출력 이미지인 2개가 필요하기 때문에 addImage()을 두번 호출하고 있다. 그리고 run()를 호출할 때에 addImage()의 순서에 맞게 파일명을 입력한다. 즉, 입력되는 파일 명이 앞의 addImage()에 위치에 치환된다.

앞으로는 IMOperation 객체를 만들어 두고 ConvertCmd에서 run() 호출시 필요한 이미지 명을 변경하면서 호출하면 된다.

결론

이외에도 다양한 기능이 im4java에서 제공하고 있다. 또한 비동기 명령 수행 기능과 병렬 처리도 지원되고 있으니 관심있으신 분은 im4java의 개발자 가이드를 참조하면 된다. 내용도 많지도 않고 단순해서 살펴보는데 어렵지 않을 것이다. 직접 imageMagic를 호출한다면 굳이 im4java를 사용할 이유는 없다.

ImageMagick를 사용하는게 깔끔한 방법은 아니지면 현 시점에서 최선의 선택이다. 그러나 지원되는 운영체제가 유닉스, iOS, Mac OS, Windows만 지원하고 있어서 그외 운영체제에서는 사용하는데 제한(?)이 있다. 그러나 잘 사용하면 굳이 프로그래밍 언어에 제한을 두지 않고 다양한 이미지 처리를 손쉬게 사용할 수 있다는 장점이 있다. 추후 배포하거나 처음 설치할 때에 ImageMagick도 같이 고려해야는 까다로운 부분이 생긴다.

그외 장단점이 있지만 자신의 상황에 맞게 적절한 선택을 하는게 중요하다. 배보다 배꼽이 커질 수도 있기 때문에 반드시 ImageMagick를 사용하는게 좋다고는 볼 수 없다.

부족한 글이지만 도움이 되었으면 한다. 모두 즐거운 코딩생활하세요. ospace.

참조

[1] ImageMagick, 2019.03.11, https://www.imagemagick.org/index.php

[2] im4java, 2019.03.11, http://im4java.sourceforge.net/

[3] im4java Developer's guide, 2019.03.11, http://im4java.sourceforge.net/docs/dev-guide.html

반응형