본문 바로가기

개발 이야기/Java Basics

Java Advanced Imaging (JAI)을 이용한 썸네일(Thumbnail, 리사이징) / 마스킹(Masking)

이번 프로젝트에서 Java 기반 서버 사이드 이미지 처리가 필요해서 조사하면서 찾게 된 Library...

Java Advanced Imaging (JAI)

다양한 이미지 포맷(BMP, JPEG, PNG, PNM, TIFF)에 대한 인코더/디코더 뿐만 아니라
이미지 작업에 필요한 대부분의 기능을 API로 제공하고 있다.

하지만 직접 간단한 샘플 프로그램을 작성해보니, 다음과 같은 문제가 있다.
1) 해당 프로젝트의 유용성에 비해 정보가 정리가 되어 있지 않아 필요한 자료 찾기가 쉽지 않다.
   실제로 해당 API를 사용하려면 JAI 및 JAI Image I/O가 필요한데 이에 대한 설명 조차 제대로 되어 있지 않고
   홈페이지에는 튜토리얼은 커녕 샘플도 하나 없다.
2) 라이브러리 자체 이용은 어렵지 않으나, 이미지 연산에 대한 지식이 필요하다.
   (add?, subtract?, convolve?, composite? ???)

우선 몇시간 투자해서 만든 프로그램과 몇가지 자료들을 정리해본다....


[구현 목표]
우선 원하는 기능은
1) 특정 이미지의 Resizing 기능 (Thumbnail 생성)
2) 액자 형태의 마스킹(masking) 기능
3) jpg 형태로 파일 저장



1. JAI 구동 방식
  JAI는 이미지 처리를 위한 간단한 프레임워크를 제공한다.
  1) 파일, 상수값 등으로부터 이미지 생성
  2) 작업공간(ParameterBlock) 생성
  3) 작업할 이미지를 작업공간에 입력 : ParameterBlock.addSource()
  4) 필요한 파라메터들 입력 ParameterBlock.add()
  5) 이미징 작업(Operation) 수행하여 결과로 새로운 이미지를 얻음 : JAI.create()

2. 리사이징 함수
    public static RenderedImage resize(String path, float scale){
         /*
          * Create an input stream from the specified file name
          * to be used with the file decoding operator.
        */
        FileSeekableStream stream = null;
        try{
            stream = new FileSeekableStream(path);
        } catch (IOException e){
            e.printStackTrace();
            System.exit(0);
        }
        /* Create an operator to decode the image file. */
        RenderedOp image1 = JAI.create("stream", stream);
       
        /*
         * Create a standard bilinear interpolation object to be
         * used with the “scale” operator.
        */
        Interpolation interp = Interpolation.getInstance(
        Interpolation.INTERP_BILINEAR);
        /**
        * Stores the required input source and parameters in a
        * ParameterBlock to be sent to the operation registry,
        * and eventually to the “scale” operator.
        */
        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image1);
        pb.add(scale); // x scale factor
        pb.add(scale); // y scale factor
        pb.add(0.0F); // x translate
        pb.add(0.0F); // y translate
        pb.add(interp);       // interpolation method
        /* Create an operator to scale image1. */
        RenderedOp image2 = JAI.create("scale", pb);
        /* Get the width and height of image2. */
        return image2;
    }
 
3. 마스킹 함수
    마스킹은 이미지 연산 관련 지식이 있어야 가능하다. 실제로 인터넷을 보니 JAI에서 막상 마스킹을 어떻게
    구현해야 하는지에 대한 문의들이 꽤 돌고 있는데, 막상 답글이 없다...ㅡ.ㅡ"
    사실 포토샵에서 조차도 디자인에서 쓰는 예쁜 마스킹은 여러 이미징 과정을 거쳐서 나오는데...
    우선 두개의 마스킹 이미지와 빼기(subtract), 더하기(add) 연산만으로 간단한 마스킹을 구현했다...
    첫번째 이미지는 빼기 연산으로 모서리를 깍는데 이용되고,
    두번째 이미지는 더하기 연산으로 액자와 같은 역할을 하게 된다.
   (개념적으로는 composite으로 masking을 하는 것이 맞을 것 같은데, 여러 방법으로 시도해봐도 잘 안된다..ㅡ.ㅡ")

    public static RenderedImage mask(String path1, String mask1, String mask2){
         /*
          * Create an input stream from the specified file name
          * to be used with the file decoding operator.
        */
        FileSeekableStream st1 = null;
        FileSeekableStream st2 = null;
        FileSeekableStream st3 = null;
        try{
            st1 = new FileSeekableStream(path1);
            st2 = new FileSeekableStream(mask1);
            st3 = new FileSeekableStream(mask2);
        } catch (IOException e){
            e.printStackTrace();
            System.exit(0);
        }
        /* Create an operator to decode the image file. */
        RenderedOp image1 = JAI.create("stream", st1);
        RenderedOp image2 = JAI.create("stream", st2);
        RenderedOp image3 = JAI.create("stream", st3);
       
       
        ParameterBlock pb = new ParameterBlock();
        pb.addSource(image1);
        pb.addSource(image2);
        RenderedOp dst = JAI.create("subtract", pb);

        pb = new ParameterBlock();
        pb.addSource(dst);
        pb.addSource(image3);
        dst = JAI.create("add", pb);
       
        writeFile(path1.replaceFirst(".jpg",".1.jpg"), dst);
        return (RenderedImage )dst;
    }
}

4. 이미지 저장 함수
   워낙 사용법이 쉬워서 설명이 필요가 없다. 물론 매뉴얼을 보면 여러가지 옵션이 존재한다.

    private static void writeFile(String path, RenderedOp op) {
        OutputStream os = null;
        try{
            os = new FileOutputStream(path);
            JPEGEncodeParam param = new JPEGEncodeParam();
            ImageEncoder enc = ImageCodec.createImageEncoder("jpeg", os, param);
            enc.encode(op);
            os.close();
        } catch (IOException e){
            e.printStackTrace();
        }       
       
    }



[JAI 관련 유용한 정보]
공식 홈페이지 : https://jai.dev.java.net (JAI), https://jai-imageio.dev.java.net (JAI image I/O)
도움되는 글들 :
  - http://blog.sdnkorea.com/blog/184  (SDN 공식 블로그의 JAI 소개글)
  - http://thdwns2.springnote.com/pages/1008950
  - 관 련 링크 정리 된 곳

[관련 자료]
   (JAI 영문 레퍼런스 서적, 예전 버전 기반이라 오류가 일부 있지만 매우 유용)
   (구현 모듈 코드)


Java Graphic Programming

SWT/JFace 인 액션
Matthew Scarpino 등저/제갈호준,이선아 공역

자바로 만드는 애니메이션 & 그래픽스
쳇 하스,로메인 가이 공저/양석호 역

Java FX
짐 클라크,짐 코너스,에릭 브루노 공저/이진행,이아정,정다정 공역

예스24 | 애드온2