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

2018. 5. 9. 16:56·JAVA
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
반응형

'JAVA' 카테고리의 다른 글

Java(자바) 버전 변경하면서 사용하는 법  (0) 2024.06.14
[JAVA] [오류] Error: Table [?] contains physical column name [?] referred to by multiple physical column names  (0) 2023.01.18
'JAVA' 카테고리의 다른 글
  • Java(자바) 버전 변경하면서 사용하는 법
  • [JAVA] [오류] Error: Table [?] contains physical column name [?] referred to by multiple physical column names
밍글링글링
밍글링글링
mingling - 밍글링, 밍글밍글링. 코드와 어우러지다. IT/ 프로그래밍/소스
    반응형
    250x250
  • 밍글링글링
    mingling
    밍글링글링
  • 전체
    오늘
    어제
    • 밍글링글링 (407) N
      • Flutter (2)
      • 일상생활 (8)
        • 리뷰 (1)
        • 생활정보 (4)
        • 맛집 (0)
        • 여행 (0)
        • 모든정보 (3)
      • JAVA (126)
        • 개념 (6)
        • 예제 (115)
        • Exception (2)
      • C (1)
        • C (1)
        • C++ (0)
        • C# (0)
      • JS (29)
        • JavaScript (18)
        • JQuery (5)
        • AJax (0)
        • NODE.JS (6)
        • Angular.JS 2.0 (0)
      • WEB (87)
        • HTML (6)
        • CSS (61)
        • JSP (20)
        • JSTL (0)
      • FrameWork (8)
        • Spring (8)
        • BootStrap (0)
        • MyBATIS (0)
        • JUnit (0)
      • 외부 라이브러리 (5)
      • 공유 소스 관리 (5)
        • Git (5)
        • SVN (0)
      • 빅데이터 프로그래밍 (37)
        • Python (37)
        • R Programming (0)
      • DB (7)
        • ORACLE (0)
        • MySql (6)
      • Development Tools (7)
        • StarUML (0)
        • eXERD (0)
        • Eclipse (4)
      • SKILL (6)
        • Migration (0)
        • Security (6)
      • MicroSoft (0)
        • Excel (0)
        • Word (0)
      • Android (0)
      • Server (21)
        • Ubuntu (5)
        • Linux (15)
      • IOS (0)
      • XML (0)
      • 미디어 (0)
      • 공지사항 (3)
      • NETWORK (1)
      • 게임 (4)
        • 피파 (1)
        • 리니지M (0)
        • 배틀그라운드 (1)
        • 듀랑고 (2)
      • 세상 이슈 (6)
      • 일렉트론 (0)
      • 대회 소식 (4)
      • 업무 (2)
      • Express, Vue (6)
      • docker (11)
      • svelte (3)
      • 블록체인 (1)
      • IT (10) N
      • Rust (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자바 객체 지향
    Rust lang
    vscode
    vue 설치
    Extension Bisect
    자바 exception
    lang rust
    jsp include
    브라우저 자동화
    자바 생성자
    자바 클래스
    css float
    vue cli
    css table
    AI 코딩 에이전트
    proxy pass
    에디터 팁
    프런트엔드
    API 설계
    자바 for문
    nginx ssl 설정
    리눅스 설치
    Java Array
    css list
    클론코딩
    css block
    React Compiler
    러스트
    SSL 인증서
    오류
    mysql db
    css perspective
    jsp parameter
    docker
    자바 배열
    css tb
    gitlab 설치
    svelte
    ssl 인증서 발급
    Node
    VS Code 팁
    rust linux
    nginx
    spring java
    ubuntu
    티스토리 자동화
    servlet class
    java casting
    css transition
    nginx ssl 적용
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
밍글링글링
[Java/자바] 이미지 리사이즈(ver. java)
상단으로

티스토리툴바