Shinnara's Blog
Talking with Shinnara :: NaraTalk.com


사용자 삽입 이미지
 취미로 하고 있는 사진 생활.. 이제 17개월인 딸아이 사진만해도 수십 기가 바이트에 이르곤 한다. 엄청난 양의 사진들.. 만약 필름으로 찍었다면..   1기가면 보통 300 장 정도의 JPG 사진을 찍을 수 있다. 물론 사용하는 기중에 따라 다르겠지만.... 사진에 나와 있는 저 카메라.. 며칠 전 새롭게 발표된, 그 이름도 멋진.. EOS 1Ds Mark III 이다. 저런 카메라야 그림의 떡이지만.. 그래도 참 멋지게 생겼다. 탐나는 놈이네 그려...


각설하고, 이제 다시 경어체로 시작해봅니다.

이미지를 다루다 보면 가장 흔히 하는 것 중에 하나가 회전일것입니다. 조금 괜찮은 디지털 카메라라면 내부에 센서를 내장해서 카메라의 상태를 체크해서 가로 사진인지 세로 사진인지를 구별해내기도 하지만, 그렇지 않은 경우가 더 많은 것 같습니다.  또한 구별을 하더라도 메타 데이터에만 저장하는 경우도 많아서 윈도우즈의 기본 이미지 뷰어등으로는 가로/세로가 구별되지 않기도 합니다. Picasa 등의 소프트웨어를 이용하면 알아서 변환해주더군요.

오늘은 이러한 이미지 변환을 Java 에서 구현하는 방법입니다.
좀더 목적을 확실하게 해보자면 a.jpg 화일을 읽어서 +90도 또는 -90도 회전하여 a.jpg 로 다시 저장하는 것입니다.

Java API 를 찾아보면 Graphics2D 에 rotate() 메소드가 있는 것을 확인할 수 있습니다.  파라메터로 radian 값을 넘겨주면 이미지를 회전시키는 메소드 입니다. 아래는 이를 이용한 코드입니다.

 
           File file = new File("a.jpg");
            BufferedImage bi = ImageIO.read(file);
            Graphics2D g2d = (Graphics2D) bi.getGraphics();
            g2d.rotate(Math.toRadians(degree));          
            ImageIO.write(bi, "jpg", file);

이렇게 하면 쉽게 되리라 생각했는데, a.jpg 는 바뀌지가 않습니다. 생각해보건데 g2d 에서 변환한 내용이 bi 에 적용되지 않는 것 같다는 추측을 조심스레 해봅니다. 실제로 drawString() 을 해서 저장을 해봐도 마찬가지입니다.  g2d의 내용을 bi 로 적용시키는 방법이 필요합니다. 그건 나중에 찾아보기로 하고..

일단 문제가 발생하면 검색을 시작합니다. 구글 검색의 생활화.. 예전에는  API 도 찾아보고, 책도 찾아보고 혼자 고민도 많이 했는데, 많은 경우 검색을 통해 답을 얻는 것이 더 빠르곤 했습니다.  이러한 문제들이 비단 저의 문제만은 아니기에 많은 분들이 같은 문제로 고민하고 해결책을 찾으려 노력하셨을테니까요.  하여간 검색을 하다가 Graphics2D 를 쓰지 않고 회전시키는 방법에 대한 글을 발견합니다. 코드를 보시면 아시겠지만 픽셀 단위로 이동시키는 아주 원시적(?)인 방법입니다. 하지만 가장 확실한 방법일 수도 있겠지요.

하여간 위의 코드를 가져다가 테스트를 해보았습니다. 회전이 되기는 하는데 어째 이상했습니다. 코드를 유심히 살펴보니 약간의 버그가 있더군요. 그래서 수정을 했습니다. 딱 두군데.. 아래 코드에서 빨간색으로 표시한 부분입니다.

    public  BufferedImage rotate90CW(BufferedImage bi)
    {
        int width = bi.getWidth();
        int height = bi.getHeight();
       
        BufferedImage biFlip = new BufferedImage(height, width, bi.getType());
       
        for(int i=0; i<width; i++)
            for(int j=0; j<height; j++)
                biFlip.setRGB(height-1-j, i, bi.getRGB(i, j));
       
        return biFlip;
    }

    public  BufferedImage rotate90CCW(BufferedImage bi)
    {
        int width = bi.getWidth();
        int height = bi.getHeight();
       
        BufferedImage biFlip = new BufferedImage(height, width, bi.getType());
       
        for(int i=0; i<width; i++)
            for(int j=0; j<height; j++)
                biFlip.setRGB(j, width-1-i, bi.getRGB(i, j));
       
        return biFlip;
    }


원리가 워낙 간단하여 추가로 설명하지 않아도 될것 같습니다. 하여간 이렇게 해서 완성한 코드는 아래와 같습니다.

            File file = new File("a.jpg");
            BufferedImage bi = ImageIO.read(file);
            BufferedImage rotated = null;
           
            if( direction.equals("ccw")) rotated = rotate90CCW(bi);
            else rotated = rotate90CW(bi);           
            
            ImageIO.write(rotated,"jpg",file);
        
 드디어 원하는 결과를 얻었습니다.

그런데 한가지 문제가 있습니다.  위의 코드대로 하면 결과물의 품질이 원본과 많이 다르게 나옵니다. 화일의 사이즈가 줄어들면서 화질이 떨어지는 문제가 있더군요. 현재는 그 부분에 대해 좀더 알아보고 있습니다.

또한, 위의 예를 보면서 생각한것인데, 앞서 Graphics2D 는 새로운 Graphics 객체나 Image 객체를 만들어 내는 형태로 수정하면 정상적으로 작동하지 않을까 생각해봅니다. 시간이 나면 테스트해서 결과를 올리겠습니다.

끝으로, 화질이 떨어지는 문제를 풀어보고자 제가 썼었던 방법에 대해 간략히 소개하고 마치도록하겠습니다.
ImageIO 를 직접적으로 쓰지 않고 ImageWriter 를 통해서 화일을 쓰도록 테스트해보았습니다.

           
            Iterator writers = ImageIO.getImageWritersByFormatName("jpg");
            ImageWriter writer = (ImageWriter) writers.next();
            ImageWriteParam writeParam = writer.getDefaultWriteParam();
            writeParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);
            ImageOutputStream ios = ImageIO.createImageOutputStream(file);
            writer.setOutput(ios);          
            writer.write(rotated);
           
위에서 ImageIO.write() 를 통해 저장할때와는 다르게 화일 사이즈는 줄지 않으나, 화질은 유지되지 않음을 확인하였습니다. CompressionMode 를 바꾸어 보았으나 별반 차이는 없더군요. 읽어 들일때의 문제일까 싶어서 그쪽 부분도 확인해보았으나, ImageReader 를 써도 해결되지는 않았습니다.  문제가 해결되는 대로 내용을 올리도록 하겠습니다.


        





0 Trackback, 2 Comment

TRACKBACK :: http://naratalk.com/trackback/98 관련글 쓰기

댓글을 달아 주세요

  1. 손님  댓글주소  수정/삭제  댓글쓰기

    ImageIO.write(bi, "jpg", file); 이거 화질 안좋아요
    아래 소스를 추천합니다
    public static void saveJPEG(BufferedImage thumbImage, OutputStream out, double compression) throws IOException {
    JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
    JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);
    compression = Math.max(0, Math.min(compression, 100));
    param.setQuality((float)compression / 100.0f, false);
    encoder.setJPEGEncodeParam(param);
    encoder.encode(thumbImage);
    }

    2008/07/20 07:33

1  ... 213 214 215 216 217 218 219 220 221  ... 264 
다...... (264)
Computer/Programming (106)
Links (14)
책 읽는 즐거움 (7)
끄적임 (66)
즐거운 과학 나라 (7)
일본 (5)
Study (4)