JAVA

[Java/자바] 이미지 리사이즈(ver. java)

밍글링글링 2018. 5. 9.
728x90

이미지 리사이즈.

우선, sanselan 사용할 것이다.

왜냐하면, 그냥 ImageIO만 사용하게되면 간혹 포토샵을 거친 이미지들을 읽지 못하는 경우가 있기 때문에,

자바오픈소스인 sanselan을 이용하여 이미지정보(크기, 색 공간, ICC프로파일 등) 및 메타 데이터의 빠른 구문 분석을 비롯하여

다양한 이미지 형식을 읽고 쓸 수 있어 자유로워서 사용하는 것을 권장한다.

 

Maven을 사용한다면 아래와 같이.

pom.xml

<dependency>
    <groupId>org.apache.sanselan</groupId>
    <artifactId>sanselan</artifactId>
    <version>0.97-incubator</version>
</dependency>

Maven을 사용하지 않고, jar파일로 사용할 예정이면

sanselan-0.97-incubator.jar
다운로드

▲ 위의 파일을 다운로드 받아 사용하자.

JpegReader.java

package jungle.common.util;

import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.byteSources.ByteSourceFile;
import org.apache.sanselan.formats.jpeg.JpegImageParser;
import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;

public class JpegReader {
     
    public static final int COLOR_TYPE_RGB = 1;
    public static final int COLOR_TYPE_CMYK = 2;
    public static final int COLOR_TYPE_YCCK = 3;

    private int colorType = COLOR_TYPE_RGB;
    private boolean hasAdobeMarker = false;

    public BufferedImage readImage(File file) throws IOException, ImageReadException {
        colorType = COLOR_TYPE_RGB;
        hasAdobeMarker = false;

        ImageInputStream stream = ImageIO.createImageInputStream(file);
        Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
        while (iter.hasNext()) {
            ImageReader reader = iter.next();
            reader.setInput(stream);

            BufferedImage image;
            ICC_Profile profile = null;
            try {
                image = reader.read(0);
            } catch (IIOException e) {
                colorType = COLOR_TYPE_CMYK;
                checkAdobeMarker(file);
                profile = Sanselan.getICCProfile(file);
                WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
                if (colorType == COLOR_TYPE_YCCK){
                    convertYcckToCmyk(raster);
                }
                 
                if (hasAdobeMarker){
                    convertInvertedColors(raster);
                }
                image = convertCmykToRgb(raster, profile);
            } finally {
                stream.close(); //원본에는 close해주는 부분이 없어서 추가해 줬음, 위치상으로 애매한데 리턴 전이라 그냥 닫아줌
            }

            return image;
        }

        return null;
    }

    public void checkAdobeMarker(File file) throws IOException, ImageReadException {
        JpegImageParser parser = new JpegImageParser();
        ByteSource byteSource = new ByteSourceFile(file);
        @SuppressWarnings("rawtypes")
        ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
        if (segments != null && segments.size() >= 1) {
            UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
            byte[] data = app14Segment.bytes;
            if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
            {
                hasAdobeMarker = true;
                int transform = app14Segment.bytes[11] & 0xff;
                if (transform == 2)
                    colorType = COLOR_TYPE_YCCK;
            }
        }
    }

    public static void convertYcckToCmyk(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);

            for (int x = 0; x < stride; x += 4) {
                int y = pixelRow[x];
                int cb = pixelRow[x + 1];
                int cr = pixelRow[x + 2];

                int c = (int) (y + 1.402 * cr - 178.956);
                int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
                y = (int) (y + 1.772 * cb - 226.316);

                if (c < 0) c = 0; else if (c > 255) c = 255;
                if (m < 0) m = 0; else if (m > 255) m = 255;
                if (y < 0) y = 0; else if (y > 255) y = 255;

                pixelRow[x] = 255 - c;
                pixelRow[x + 1] = 255 - m;
                pixelRow[x + 2] = 255 - y;
            }

            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static void convertInvertedColors(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);
            for (int x = 0; x < stride; x++)
                pixelRow[x] = 255 - pixelRow[x];
            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {

        if (cmykProfile == null){
            cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("ISOcoated_v2_300_eci.icc"));
        }

        ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
        BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
        WritableRaster rgbRaster = rgbImage.getRaster();
        ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
        ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
        cmykToRgb.filter(cmykRaster, rgbRaster);
        return rgbImage;
    }

    static void intToBigEndian(int value, byte[] array, int index) {
        array[index]   = (byte) (value >> 24);
        array[index+1] = (byte) (value >> 16);
        array[index+2] = (byte) (value >>  8);
        array[index+3] = (byte) (value);
    }
     
}

JpegReader.java를 쓴 경로에 

ISOcoated_v2_300_eci.icc
다운로드

파일을 추가해준다.

JpegReader를 사용할 때 필요하다.

public class FileUtil {

//****로컬용    
//    public static final String filePath = "C:\\TEMP\\";
//****
    
//****서버용    /filesvr/logo/
    public static final String filePath = "/data/fileserver/";
    public static final String thumbnailPath = "/data/fileserver/thumbnail/";

public void createdThumbnail(String newFileName, String folder, String ext){
        String filename = filePath + folder + newFileName;  
        String savename = thumbnailPath + newFileName;    // 새 이미지 파일명
        int newWidth = 600;                                  // 변경 할 넓이
        int newHeight = 700;                                 // 변경 할 높이
        String mainPosition = "W"; 
        
        int imageWidth;
        int imageHeight;
        double ratio;
        int w;
        int h;
        
        JpegReader jpegReader = new JpegReader(); //위에서 만든 Class
        Image bufferedImage = null;
         
        try {
            bufferedImage = jpegReader.readImage(new File(filename));
            
            // 원본 이미지 사이즈 가져오기
            imageWidth = bufferedImage.getWidth(null);
            imageHeight = bufferedImage.getHeight(null);

            if(mainPosition.equals("W")){    // 넓이기준

                ratio = (double)newWidth/(double)imageWidth;
                w = (int)(imageWidth * ratio);
                h = (int)(imageHeight * ratio);

            }else if(mainPosition.equals("H")){ // 높이기준

                ratio = (double)newHeight/(double)imageHeight;
                w = (int)(imageWidth * ratio);
                h = (int)(imageHeight * ratio);

            }else{ //설정값 (비율무시)

                w = newWidth;
                h = newHeight;
            }
            
            Image resizeImage = bufferedImage.getScaledInstance(w, h, Image.SCALE_SMOOTH);
            
            // 새 이미지  저장하기
            BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Graphics g = newImage.getGraphics();
            g.drawImage(resizeImage, 0, 0, null);
            g.dispose();
            ImageIO.write(newImage, ext, new File(savename));//동일한 명으로 이미지를 변경한다. 복사본을 남기려면 outputfile의 파일명을 변경
             
        } catch (ImageReadException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 

사용할 JAVA파일에서 아래와 같이 사용하면 저용량 이미지로 복사된다.

fileUtil.createdThumbnail(newFileName, folder, ext);
728x90

댓글