Recent Posts
Recent Comments
Link
06-22 04:51
Today
Total
관리 메뉴

삶 가운데 남긴 기록 AACII.TISTORY.COM

String을 QR코드로 변환 com.google.zxing 라이브러리 본문

DEV&OPS/Java

String을 QR코드로 변환 com.google.zxing 라이브러리

ALEPH.GEM 2024. 1. 19. 09:29

 

com.google.zxing 라이브러리

아래는 Zxing Core 3.5.x 버전을 기반으로 한 예제입니다.

maven이나 gradle 등을 통해 라이브러리를 프로젝트에 추가할 수 있습니다.

다만 너무 최근 버전보다 안정화된 버전을 사용하는 것을 권장드립니다.

 

이 zxing 라이브러리는 String을 QR 코드로, 다시 QR코드를 String으로 복원할 수 있습니다.

QR 코드 스펙상 문자열의 길이의 제한이 있을 수 있습니다. 

인코딩 방식이나 오류 레벨 설정 라이브러리 종류나 버전 등에 따라 차이가 있을 수 있지만 수백 글자에서 수천 자까지만 가능합니다.

따라서 긴 문자열은 QR코드를 여러개로 분할하여 변환해야 합니다.

 

아래 예제는 긴 문자열을 1000 글자로 나누어서 QR 코드로 변환 후 다시 String으로 복원하는 예제입니다.

import com.google.zxing.*;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class QRCodeExample {

    public static void main(String[] args) {
        String longString = "긴 문자열 내용..."; // 여기에 실제 긴 문자열을 넣으세요.

        // 문자열을 1000글자씩 나누어 QR 코드 이미지로 변환
        String[] dividedStrings = divideString(longString, 1000);
        for (int i = 0; i < dividedStrings.length; i++) {
            String text = dividedStrings[i];
            generateQRCode(text, "QRCodePart" + (i + 1) + ".png");
        }

        // QR 코드 이미지를 읽어서 문자열로 복원
        StringBuilder reconstructedString = new StringBuilder();
        for (int i = 0; i < dividedStrings.length; i++) {
            String decodedText = decodeQRCode("QRCodePart" + (i + 1) + ".png");
            reconstructedString.append(decodedText);
        }

        System.out.println("Reconstructed String: " + reconstructedString.toString());
    }

    private static String[] divideString(String input, int chunkSize) {
        int length = input.length();
        int numOfChunks = (int) Math.ceil((double) length / chunkSize);
        String[] result = new String[numOfChunks];

        for (int i = 0; i < numOfChunks; i++) {
            int start = i * chunkSize;
            int end = Math.min((i + 1) * chunkSize, length);
            result[i] = input.substring(start, end);
        }

        return result;
    }

    private static void generateQRCode(String text, String filePath) {
        String format = "png";

        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        try {
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, 0, 0, hints);

            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();

            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }

            File qrCodeFile = new File(filePath);
            ImageIO.write(image, format, qrCodeFile);

            System.out.println("QR Code generated successfully: " + filePath);

        } catch (WriterException | IOException e) {
            e.printStackTrace();
        }
    }

    private static String decodeQRCode(String filePath) {
        BufferedImage bufferedImage;
        Result result = null;

        try {
            bufferedImage = ImageIO.read(new File(filePath));

            BinaryBitmap binaryBitmap = new BinaryBitmap(
                    new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage)));

            result = new MultiFormatReader().decode(binaryBitmap);

        } catch (IOException | NotFoundException e) {
            e.printStackTrace();
        }

        if (result != null) {
            return result.getText();
        } else {
            return "";
        }
    }
}

 

 

ErrorCorrectionLevel

generateQRCode() 메서드에서 QR코드로 변환할 때의 ErrorCorrectionLevel은 QR 코드의 오류 정정 레벨을 나타냅니다. 

오류 정정 레벨은 QR 코드가 불완전하거나 손상된 상태에서도 정확하게 읽을 수 있도록 하는 기술입니다. 

이 ErrorCorrectionLevel에 따라서 변환할 수 있는 String의 길이가 달라질 수 있으므로 검토 후 결정해야 합니다.

  • H (High): 가장 높은 오류 정정 레벨입니다. 높은 오류 정정 레벨은 데이터에 대한 추가적인 비트를 사용하여 더 많은 오류를 감지하고 수정할 수 있습니다. 하지만, QR 코드로 변환할 수 있는 데이터 용량이 감소할 수 있습니다.
  • L (Low): 가장 낮은 오류 정정 레벨입니다. 낮은 오류 정정 레벨은 추가 오류 정정을 최소화하고 QR 코드로 변환할 수 있는 데이터 용량을 최대화합니다. 그러나 손상된 상태에서 읽기가 어려울 수 있습니다.
  • M (Medium): 중간 수준의 오류 정정 레벨입니다. M은 오류 정정과 데이터 용량 사이의 균형을 제공합니다. 일반적으로 대부분의 상황에서 적절한 선택입니다.
  • Q (Quartile): 중간에서 높은 수준의 오류 정정 레벨입니다. Q는 높은 정정 능력을 가지면서도 H보다는 데이터 용량을 보다 효율적으로 사용합니다.

 

UTF-8의 경우 변환 상 주의 할 점

UTF-8에서 각 문자는 1바이트에서 4바이트까지의 길이가 달라질 수 있는 특성이 있습니다. 

  • 숫자: 1자리당 1바이트
  • 알파벳 및 특수 문자: 1자리당 1바이트
  • 한글 등 다국어 문자: 1자리당 3바이트

그래서 UTF-8로 인코딩 된 문자열의 경우, QR 코드의 데이터 용량은 한글이 많은 경우와 그렇지 않은 경우에 따라서 변환할 수 있는 문자열의 길이가 변할 수 있는 것입니다. 
일반적으로 3,000 ~ 4,000바이트 정도의 데이터를 담을 수 있는 QR 코드를 생성하는 것이 가능합니다.

그러나 한글이 들어가있는 경우인가 아닌가에 따라서 글자수 길이를 적절히 제한해야 합니다. 

QR 코드의 레벨 및 버전 등을 고려하여 테스트해 보는 것이 가장 확실한 방법입니다.

 

아래는 테스트로 생성한 QR코드입니다. 위 내용으로 되어있습니다.

 

 

 

 

 

 

 

728x90