위와 같이 이미지와 그 내부에 글자를 쓰고자 할 때 매번 포토샵 같은 프로그램에 들어가서 작업하려면 귀차니즘이 발동하기 때문에 힘든데 이럴때를 위해 만든 유틸성 자바 프로그램의 소스를 공유하고자 합니다. 좀 더 응용하면 더 좋은 프로그램이 나올수도 있겠네요
자바최신 버전 설치(1.7이상 권장) 후 실행하시면 됩니다. (자바 프로그램에 대한 설명은 생략하겠습니다. main에 예제까지 넣었으니 ㅜㅜ )
package com.wonsama.wswriter.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;
/**
* 입력 텍스트를 이미지로 만들어 준다
* @author parkwon
* @since 2017.03.24
*/
public class WsImageTextUtil {
/**
* 테스트용 진입점
* @param args 파라미터
* @since 2017.03.24
*/
public static void main(String[] args)
{
try{
new WsImageTextUtil();
}catch (Exception e) {
e.printStackTrace();
}
}
/**
* 생성자
* @since 2017.03.24
*/
WsImageTextUtil() throws Exception
{
// drawText("어머니가 짜장면이 싫다고 하셨어", "/Users/parkwon/Desktop/sample.png");
String[] texts = {"아이폰 7 붉은색 사주세요"};
drawTextWithImage(texts
, "/Users/parkwon/Desktop/writes/title.png"
, "http://imgnews.naver.com/image/5463/2017/03/21/0000000101_003_20170322105216516.png");
}
/**
* 텍스트를 이미지로 만들어준다
* @param text 텍스트
* @param fileLoc 파일위치
* @throws Exception 오류
* @since 2017.03.27
*/
public void drawText(String text, String fileLoc) throws Exception
{
Font font = new Font("나눔고딕", Font.PLAIN, 28);
Rectangle r = getFontrect(text, font);
int width = (int) r.getWidth();
int height = (int) r.getHeight();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = getG2D(img);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
g2d.drawString(text, 0, fm.getAscent());
g2d.dispose();
// 이미지 파일을 생성한다
ImageIO.write(img, "png", new File(fileLoc));
}
/**
* 웹 이미지 내부에 텍스트를 포함하여 이미지로 만들어준다
* @param texts 텍스트 문자열
* @param fileLoc 파일위치
* @param backgrondImageURL 웹이미지 주소
* @throws Exception 오류
* @since 2017.03.27
*/
public void drawTextWithImage(String[] texts, String fileLoc, String backgrondImageURL) throws Exception
{
final int FONT_SIZE = 18;
final int POS_X = 30;
final int POS_Y = 20;
BufferedImage img = ImageIO.read(new URL(backgrondImageURL));
Graphics g = img.getGraphics();
Font font = new Font("나눔고딕", Font.PLAIN, FONT_SIZE);
// 우선은 첫 라인 정보만 가져온다. 일반적으로 가장 길게 설정하는 것이 맞다고 생각함.
Rectangle rect = getFontrect(texts[0], font);
int oriWidth = img.getWidth();
int oriHeight = img.getHeight();
double ratio = (rect.getWidth() + POS_X*2) / oriWidth;
int newWidth = (int) (rect.getWidth() + POS_X*2);
int newHeight = (int) (oriHeight * ratio);
// 배경 이미지 RESIZE 처리
img = resizeImage(img, newWidth, newHeight*texts.length);
// 텍스트 처리
for(int i=0;i<texts.length;i++){
Graphics2D g2d = getG2D(img);
g2d.setFont(font);
int x = POS_X;
int y = (FONT_SIZE + POS_Y)*(i + 1);
// 그림자 처리
drawStringDropshadow(g2d, texts[i], x, y);
}
g.dispose();
// 배경 이미지 CROP 처리
img = cropImage(img, new Rectangle(0, 0, newWidth, (FONT_SIZE+POS_Y)*texts.length+POS_Y) );
// 이미지 파일을 생성한다
ImageIO.write(img, "png", new File(fileLoc));
}
/**
* 입력받은 문자열의 사각영역을 반환한다
* @param text 문자열
* @param font 폰트
* @return 사각크기
* @since 2017.03.24
*/
private Rectangle getFontrect(String text, Font font){
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = fm.stringWidth(text);
int height = fm.getHeight();
g2d.dispose();
return new Rectangle(0, 0, width, height);
}
/**
* 아웃라인 처리
* @param g2d 2D 그래픽스
* @param text 문자열
* @param x X좌표
* @param y Y좌표
* @param cin 내부 색상
* @param cout 외부 색상
* @since 2017.03.27
*/
private void drawStringOutline(Graphics2D g2d, String text, int x, int y, Color cin, Color cout){
g2d.setColor(cout);
g2d.drawString(text, ShiftWest(x, 1), ShiftNorth(y, 1));
g2d.drawString(text, ShiftWest(x, 1), ShiftSouth(y, 1));
g2d.drawString(text, ShiftEast(x, 1), ShiftNorth(y, 1));
g2d.drawString(text, ShiftEast(x, 1), ShiftSouth(y, 1));
g2d.setColor(cin);
g2d.drawString(text, x, y);
}
/**
* 그림자 텍스트를 그려준다
* @param g2d 2D 그래픽스
* @param text 문자열
* @param x X좌표
* @param y Y좌표
* @since 2017.03.27
*/
private void drawStringDropshadow(Graphics2D g2d, String text, int x, int y)
{
g2d.setColor(new Color(20, 20, 20));
g2d.drawString(text, ShiftEast(x, 2), ShiftSouth(y, 2));
g2d.setColor(new Color(220, 220, 220));
g2d.drawString(text, x, y);
}
/**
* 폰트를 회전 처리한다
* @param font 폰트
* @param angle 회전각 0~360 / -를 넣으면 반시계 방향으로 계산
* @return 회전처리 된 폰트
* @since 2017.03.24
*/
private Font rotatedFont(Font font, double angle){
// 폰트 회전처리
AffineTransform form = new AffineTransform();
form.rotate(Math.toRadians(angle), 0, 0);
return font.deriveFont(form);
}
/**
* 이미지 크롭처리
* @param img 이미지
* @param rect 사각정보
* @return 신규 이미지
* @since 2017.03.24
*/
private BufferedImage cropImage(BufferedImage img, Rectangle rect) {
BufferedImage dest = img.getSubimage(rect.x, rect.y, rect.width, rect.height);
return dest;
}
/**
* 이미지 리사이징
* @param img 이미지
* @param newW 새로운 넓이
* @param newH 새로운 높이
* @return 신규 이미지
* @since 2017.03.24
*/
private BufferedImage resizeImage(BufferedImage img, int newW, int newH) {
Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH);
BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = dimg.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
return dimg;
}
/**
* 이미지에서 2D 그래픽스 개체를 얻어온다
* @param img 이미지버퍼
* @return 2D 그래픽스
* @since 2017.03.24
*/
private Graphics2D getG2D(BufferedImage img)
{
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
return g2d;
}
/**
* 좌표 이동처리 - 위쪽 / 북
* @param p 현 좌표
* @param distance 이동거리
* @return 변경된 좌표
* @since 2017.03.27
*/
int ShiftNorth(int p, int distance) {
return (p - distance);
}
/**
* 좌표 이동처리 - 아래쪽 / 남
* @param p 현 좌표
* @param distance 이동거리
* @return 변경된 좌표
* @since 2017.03.27
*/
int ShiftSouth(int p, int distance) {
return (p + distance);
}
/**
* 좌표 이동처리 - 오른쪽 / 동
* @param p 현 좌표
* @param distance 이동거리
* @return 변경된 좌표
* @since 2017.03.27
*/
int ShiftEast(int p, int distance) {
return (p + distance);
}
/**
* 좌표 이동처리 - 왼쪽 / 서
* @param p 현 좌표
* @param distance 이동거리
* @return 변경된 좌표
* @since 2017.03.27
*/
int ShiftWest(int p, int distance) {
return (p - distance);
}
}