QR 코드를 생성하고 텍스트 또는 이미지를 추가하는 Java 예제를 소개합니다. 스트림으로 QR 코드를 출력하는 방법도 포함됩니다.
기본 QR 코드 생성 및 로고 삽입
다음 코드는 QR 코드 생성 라이브러리(Google ZXing)를 사용하여 QR 코드를 만들고, 지정된 경로에서 로고 이미지를 읽어 QR 코드 중앙에 삽입하는 방법을 보여줍니다.
package com.example.qrcode;
import java.awt.BasicStroke;
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.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
public class QrCodeGenerator {
// QR 코드 기본 크기
private static final int QR_CODE_SIZE = 400;
// 로고 이미지 최대 너비
private static final int LOGO_MAX_WIDTH = 60;
// 로고 이미지 최대 높이
private static final int LOGO_MAX_HEIGHT = 60;
// 로고 이미지 파일 경로 (예시)
private static final String LOGO_PATH = "D:/QrCode/logo.jpg";
public static void main(String[] args) {
String dataUrl = ""; // QR 코드로 인코딩할 데이터 (URL 또는 텍스트)
String outputDir = "D:/QrCode/"; // QR 코드 이미지 저장 디렉토리
String outputFileName = ""; // QR 코드 이미지 파일명
// 예제: 여러 개의 QR 코드를 순차적으로 생성
for (int i = 1; i <= 2; i++) {
dataUrl = "http://example.com/details?id=" + i + "&channel=" + i;
outputFileName = i + ".png"; // 파일 확장자를 PNG로 변경
File outputFile = new File(outputDir, outputFileName);
// QR 코드 생성 및 저장
createQrCodeWithLogo(dataUrl, outputDir, outputFileName, LOGO_PATH);
// 생성된 QR 코드에 텍스트 추가
try {
addTextToImage(outputFile, "Sample Text", 5, Color.BLACK, 16);
} catch (Exception e) {
System.err.println("텍스트 추가 중 오류 발생: " + e.getMessage());
}
}
}
/**
* 지정된 데이터로 QR 코드를 생성하고 로고 이미지를 삽입하여 파일로 저장합니다.
*
* @param data QR 코드에 포함될 데이터 (URL 또는 텍스트)
* @param dirPath 생성된 QR 코드 이미지 저장 디렉토리 경로
* @param fileName 생성될 QR 코드 이미지 파일명
* @param logoPath QR 코드 중앙에 삽입할 로고 이미지 파일 경로
* @return 성공 시 true, 실패 시 false
*/
public static boolean createQrCodeWithLogo(String data, String dirPath, String fileName, String logoPath) {
try {
// QR 코드 인코딩 힌트 설정 (문자셋, 여백 등)
java.util.Map hints = new java.util.HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 4); // QR 코드 주변 여백 설정 (픽셀 단위)
// BitMatrix 생성
BitMatrix bitMatrix = new MultiFormatWriter().encode(data, BarcodeFormat.QR_CODE, QR_CODE_SIZE, QR_CODE_SIZE, hints);
File outputFile = new File(dirPath, fileName);
// 디렉토리 존재 여부 확인 및 생성
if (outputFile.getParentFile().mkdirs() || outputFile.getParentFile().exists()) {
if (outputFile.createNewFile() || outputFile.exists()) {
writeToImageFile(bitMatrix, "PNG", outputFile, logoPath); // 이미지 포맷을 PNG로 변경
System.out.println("QR 코드 생성 완료: " + outputFile.getAbsolutePath());
return true;
}
}
} catch (WriterException | IOException e) {
System.err.println("QR 코드 생성 오류: " + e.getMessage());
e.printStackTrace();
}
return false;
}
/**
* BitMatrix를 BufferedImage로 변환하고 로고를 삽입하여 지정된 파일로 저장합니다.
*/
private static void writeToImageFile(BitMatrix matrix, String format, File file, String logoPath) throws IOException {
BufferedImage image = toBufferedImage(matrix, logoPath);
if (!ImageIO.write(image, format, file)) {
throw new IOException("이미지 형식(" + format + ")을 " + file.getAbsolutePath() + "(으)로 저장할 수 없습니다.");
}
}
/**
* BitMatrix를 BufferedImage로 변환하고 로고를 삽입합니다.
*/
private static BufferedImage toBufferedImage(BitMatrix matrix, String logoPath) {
int width = matrix.getWidth();
int height = matrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// BitMatrix를 이미지 픽셀로 변환
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, matrix.get(x, y) ? Color.BLACK.getRGB() : Color.WHITE.getRGB());
}
}
// 로고 이미지 삽입 시도
if (logoPath != null && !logoPath.isEmpty()) {
try {
insertLogoImage(image, logoPath, true);
} catch (Exception e) {
System.err.println("로고 이미지 삽입 오류: " + e.getMessage());
}
}
return image;
}
/**
* QR 코드 이미지에 로고 이미지를 삽입합니다.
*
* @param source 원본 QR 코드 BufferedImage
* @param logoPath 삽입할 로고 이미지 경로
* @param compressLogo 로고 이미지 압축 여부
*/
static void insertLogoImage(BufferedImage source, String logoPath, boolean compressLogo) throws Exception {
File logoFile = new File(logoPath);
if (!logoFile.exists()) {
System.err.println("로고 파일 없음: " + logoPath);
return;
}
Image logo = ImageIO.read(logoFile);
int logoWidth = logo.getWidth(null);
int logoHeight = logo.getHeight(null);
// 로고 압축
if (compressLogo) {
if (logoWidth > LOGO_MAX_WIDTH) {
logoWidth = LOGO_MAX_WIDTH;
}
if (logoHeight > LOGO_MAX_HEIGHT) {
logoHeight = LOGO_MAX_HEIGHT;
}
// 이미지 리사이징
Image scaledLogo = logo.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH);
BufferedImage bufferedLogo = new BufferedImage(logoWidth, logoHeight, BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedLogo.getGraphics();
g.drawImage(scaledLogo, 0, 0, null);
g.dispose();
logo = scaledLogo; // 압축된 로고로 교체
}
// QR 코드 중앙에 로고 삽입
Graphics2D graph = source.createGraphics();
int xPos = (QR_CODE_SIZE - logoWidth) / 2;
int yPos = (QR_CODE_SIZE - logoHeight) / 2;
graph.drawImage(logo, xPos, yPos, logoWidth, logoHeight, null);
// 로고 주변에 테두리 효과 추가 (선택 사항)
Shape border = new RoundRectangle2D.Float(xPos, yPos, logoWidth, logoHeight, 6, 6);
graph.setStroke(new BasicStroke(3f)); // 테두리 두께
graph.setColor(Color.WHITE); // 테두리 색상
graph.draw(border);
graph.dispose();
}
/**
* 이미지 파일에 텍스트를 추가합니다.
*
* @param imageFile 텍스트를 추가할 이미지 파일
* @param text 추가할 텍스트
* @param fontStyle 글꼴 스타일 (예: Font.BOLD)
* @param color 글꼴 색상
* @param fontSize 글꼴 크기
*/
public static void addTextToImage(File imageFile, String text, int fontStyle, Color color, int fontSize) throws Exception {
// UTF-8로 텍스트 디코딩
String textToDraw = new String(text.getBytes("UTF-8"), "UTF-8");
Image originalImage = ImageIO.read(imageFile);
int imageWidth = originalImage.getWidth(null);
int imageHeight = originalImage.getHeight(null);
BufferedImage bufferedImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.createGraphics();
g.drawImage(originalImage, 0, 0, imageWidth, imageHeight, null);
// 텍스트 스타일 설정
g.setColor(color);
Font font = new Font("SansSerif", fontStyle, fontSize); // 글꼴 변경 (예: "SansSerif")
FontMetrics metrics = g.getFontMetrics(font);
g.setFont(font);
// 텍스트 위치 계산 (이미지 하단 중앙 근처)
int textWidth = metrics.stringWidth(textToDraw);
int x = (imageWidth - textWidth) / 2; // 중앙 정렬
int y = imageHeight - 20; // 하단에서 20픽셀 위
g.drawString(textToDraw, x, y);
g.dispose();
// 수정된 이미지를 원본 파일에 덮어쓰기
try (FileOutputStream out = new FileOutputStream(imageFile)) {
ImageIO.write(bufferedImage, "PNG", out); // PNG 형식으로 저장
System.out.println("이미지에 텍스트 추가 완료: " + imageFile.getAbsolutePath());
}
}
}
Hutool 라이브러리를 이용한 QR 코드 생성 (선택 사항)
Hutool 라이브러리를 사용하면 QR 코드 생성 및 텍스트 추가 과정을 더 간결하게 처리할 수 있습니다. 아래는 QrCodeUtil을 사용한 예시입니다.
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.StringUtils;
import java.awt.image.BufferedImage;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.nio.charset.Charset;
// ... (다른 import문)
public class HutoolQrCode {
public static String generateQrCodeWithTextAsBase64(String content, String textOverlay) {
// QR 코드 설정 (크기, 여백, 문자셋)
QrConfig config = new QrConfig()
.setWidth(300) // 너비
.setHeight(300) // 높이
.setMargin(2) // 여백
.setCharset(Charset.forName("UTF-8")); // 문자셋
// 기본 QR 코드 이미지 생성
BufferedImage qrImage = QrCodeUtil.generate(content, config);
// 텍스트 오버레이가 필요한 경우
if (StringUtils.isNotBlank(textOverlay)) {
int imgWidth = qrImage.getWidth();
int imgHeight = qrImage.getHeight();
BufferedImage overlayImage = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
Graphics g = overlayImage.createGraphics();
// 원본 QR 이미지 그리기
g.drawImage(qrImage, 0, 0, imgWidth, imgHeight, null);
// 텍스트 스타일 설정
g.setColor(Color.DARK_GRAY); // 텍스트 색상
int fontSize = 16;
// Font font = new Font("Arial", Font.PLAIN, fontSize); // 글꼴 설정
// FontMetrics metrics = g.getFontMetrics(font);
g.setFont(new Font("Arial", Font.PLAIN, fontSize)); // 직접 폰트 객체 생성
// 텍스트 위치 계산 (예: 하단 중앙)
// int textWidth = metrics.stringWidth(textOverlay); // FontMetrics 사용 시
// int x = (imgWidth - textWidth) / 2;
int x = 50; // 임의 위치 설정
int y = imgHeight - 30; // 하단에서 30픽셀 위
g.drawString(textOverlay, x, y);
g.dispose();
// 텍스트가 추가된 이미지를 Base64 데이터 URI로 변환
return ImgUtil.toBase64DataUri(overlayImage, ImgUtil.IMAGE_TYPE_PNG); // PNG 형식으로 변환
}
// 텍스트 오버레이 없이 QR 코드만 Base64 데이터 URI로 변환
return ImgUtil.toBase64DataUri(qrImage, ImgUtil.IMAGE_TYPE_PNG);
}
// ... (main 메소드 또는 다른 유틸리티 메소드)
}