조금 평범한 개발 이야기

JAVA로 구현한 TEXT를 IMAGE로 변환하는 방법 본문

개발/JAVA 기초와 활용

JAVA로 구현한 TEXT를 IMAGE로 변환하는 방법

jogeum 2019. 10. 15. 02:08
  1. 준비
  2. CustomText
  3. CustomTextType
  4. CustomImage
  5. 이미지 변환
  6. 소스코드

 

준비

문득 블로그를 하다가 보니 글 자주 작성하진 않아 리스트가 휑해 보이는 것도 있겠지만 필연적으로 기술 블로그이다 보니 이미지가 없어 왠지 글이 허전해 보인다는 생각이 들었습니다. 그래서 머라도 채워 넣을까 하는 생각에 TEXT를 간단하게 IMAGE로 변환해 주는 사이트를 찾다가 그냥 귀찮아서 로그를 만들기 위한 용도로 코드를 작성해 봤습니다. 순전히 개인적으로 사용할 목적으로 만들었기 때문에 실제 사용할 때 부족한 부분이 발생할 수 있다는 점 염두해 주시길 바랍니다.

먼저 프로젝트에서 lombok 라이브러리를 사용할 예정이니 다운로드 후 프로젝트 환경설정에 추가해 줘야 합니다.

TEXT 변환시 사용할 폰트는 시스템에 설치되어 있는 폰트를 아무거나 사용해도 되지만 저작권 문제가 발생할 수 있으므로 꼭 무료 폰트를 사용하시길 바랍니다.

당연하겠지만 java 가 설치되어 있어야 하며 샘플을 개발 시 JDK 11을 사용해 개발되었습니다.


CustomText

가장 먼저 사용할 TEXT를 추상화한 CustomText를 구현해 보겠습니다.

TEXT를 사용할 때 그대로 String을 사용하는 것이 아니라 한번 추상화 과정을 거쳐 글씨를 작성할 때 필요한 정보를 모아 두는 것이 좋겠다고 생각해서 CustomText 를 만들었습니다. 즉 글씨를 작성할때 사용할 내용과 그것을 꾸미기 위한 정보를 함께 담아 추상화를 진행했습니다.

CustomText는 Builder 패턴을 적용했고 이를 이용해 인스턴스를 생성할 수 있습니다.

@Getter
public class CustomText {
    private String text;
    private String fontFamily;
    private int fontSize;
    private String fontColor;
    private FontStyle fontStyle;

    public enum FontStyle {
        PLAIN, BOLD, ITALIC
    }

    @Builder
    public CustomText(String text, String fontFamily, Integer fontSize, String fontColor, FontStyle fontStyle) {
        this.text = Objects.requireNonNull(text);
        this.fontFamily = Objects.requireNonNull(fontFamily);
        this.fontSize = Objects.requireNonNull(fontSize);
        this.fontColor = Objects.requireNonNull(fontColor);
        this.fontStyle = fontStyle == null ? FontStyle.PLAIN : fontStyle;
    }

    public Font getFont() {
        return new Font(this.fontFamily, this.getFontStyle(), this.fontSize);
    }

    private int getFontStyle() {
        switch (this.fontStyle) {
            case BOLD: return Font.BOLD;
            case ITALIC: return Font.ITALIC;
            default: return Font.PLAIN;
        }
    }

    public Color getColor() {
        return Utils.getColor(this.fontColor);
    }
}

CustomTextType

아무래도 CustomText를 만든 것 까진 좋은데 공통적으로 사용 되는 타입이 필요할 것 이라고 생각했습니다. 제목을 표시하는데 같은 폰트와 사이즈를 매번 기입하는 것은 불편하기 때문입니다. 이렇게 미리 정의 해둔 타입을 Enum Factory Method 패턴을 적용해 CustomText 를 생성하도록 구성했습니다.

public enum CustomTextType {
    title {
        @Override
        public CustomText getText(String text) {
            return CustomText.builder()
                    .text(text)
                    .fontFamily("나눔고딕")
                    .fontColor("#EDF5E1")
                    .fontSize(48)
                    .fontStyle(CustomText.FontStyle.BOLD)
                    .build();
        }
    },
    subtitle {
        ...
    };

    abstract public CustomText getText(String text);
}

CustomImage

자 이제 만들어둔 CustomText를 사용해 CustomImage를 만들 차례입니다. CustomImage는 이미지 작성을 위한 기본정보와 함께 이미지로 변환하는 주체가 CustomImage 이기 때문에 실질적인 변환을 진행하는 코드를 포함하고 있습니다.

CustomImage 역시 Builder 패턴을 적용했고 이를 이용해 인스턴스를 생성할 수 있습니다.

@Getter
public class CustomImage {
    private final static int margin = 60;
    private final static int lingSpacing = 10;
    private int imageWidth;
    private int imageHeight;
    private String imageColor;

    private int startHeight;

    @Builder
    public CustomImage(Integer imageWidth, Integer imageHeight, String imageColor) {
        this.imageWidth = Objects.requireNonNull(imageWidth);
        this.imageHeight = Objects.requireNonNull(imageHeight);
        this.imageColor = Objects.requireNonNull(imageColor);

        this.startHeight = margin;
    }

    public void converting(String filePath, CustomText... customTexts) {
        if (customTexts == null || customTexts.length == 0) {
            throw new RuntimeException("text 를 입력해 주세요.");
        }

        BufferedImage image = getBufferedImage();
        for (CustomText customText : customTexts) {
            this.draw(image, customText);
        }
        try (OutputStream os = new FileOutputStream(new File(filePath))) {
            ImageIO.write(image, "png", os);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private BufferedImage getBufferedImage() {
        BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = image.createGraphics();
        graphics.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
        graphics.setPaint(this.getColor());
        graphics.fillRect(0, 0, image.getWidth(), image.getHeight());
        return image;
    }

    private void draw(BufferedImage image, CustomText customText) {
        Graphics2D graphics = image.createGraphics();

        graphics.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
        graphics.setFont(customText.getFont());
        graphics.setColor(customText.getColor());
        FontMetrics fontMetrics = graphics.getFontMetrics();
        int fontHalfSize = fontMetrics.getHeight() / 2;

        graphics.drawString(customText.getText(), margin, startHeight + fontHalfSize);
        graphics.dispose();

        this.addHeight(fontMetrics.getHeight());
    }

    private void addHeight(Integer height) {
        startHeight += height + lingSpacing;
    }

    public Color getColor() {
        return Utils.getColor(this.imageColor);
    }
}

위 코드 중 converting 함수가 실질적인 변환 작업을 담당하게 되는데 인자로 생성할 이미지의 파일 경로와 작성할 내용을 담고 있는 CustomText 배열을 가지고 옵니다.

가지고 온 CustomText 배열이 반복을 하면서 내부 함수인 draw 함수를 호출해 실제 이미지를 생성하는 과정을 거치게 됩니다.


이미지 변환

작성한 CustomText와 CustomImage를 이용해 실제 텍스트 이미지를 생성하는 코드는 아래와 같습니다.

public class Main {
    public static void main(String[] args) {
        String userDir = System.getProperty("user.dir");;
        String filePath = String.format("%s/test.png", userDir);
        System.out.println("생성될 파일 : " + filePath);

        CustomImage image = CustomImage.builder()
                .imageWidth(600)
                .imageHeight(600)
                .imageColor("#5CDB95")
                .build();

        image.converting(
                filePath,
                CustomTextType.title.getText("TEXT TO"),
                CustomTextType.title.getText("IMAGE ++"),
                CustomTextType.title.getText("CONVERTING"),
                CustomTextType.subtitle.getText("created by jogeum"),
                CustomTextType.content.getText("java로 text를 image로 변환하기"),
                CustomTextType.comment.getText("java 11 / lombok / awt / 나눔고딕")
        );

        System.out.println("파일 생성 완료 !!");
    }
}

소스코드

https://github.com/jogeum/text2image

Comments