Java QR 코드 생성 및 텍스트/이미지 삽입

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 메소드 또는 다른 유틸리티 메소드)
}
    

태그: java QR 코드 이미지 처리 ZXing Hutool

8월 10일 09:25에 게시됨