Programming/Java

[JAVA] zxing 활용해 QR코드 생성하기

📝 작성 : 2022.06.30  ⏱ 수정 : 
반응형

Intro

COVID 19 이후로 정말 많은것이 달라졌습니다. 하나하나 나열하기도 힘든 만큼 일상 생활 속에서 달라진 것 들이 많지만 그 중 하나의 기술을 뽑자면 QR 코드가 아닐까 싶습니다.

아주 오래전부터 있었지만 별다른 주목을 받지 못했고 그렇게 잊혀지는가 했는데 코로나로 인한 방문 기록, 전자문진표 등 조금씩 많이 쓰이는가 싶더니 카카오페이를 비롯한 여러가지 간편결제 서비스가 많아지면서 없어서는 안 될 기술이 되었습니다.

어플리케이션을 만들 때에도 곳곳에 QR코드를 활용 할 일이 많아졌는데요, QR코드 생성 한다면 크게 두가지 방법이 있습니다.

  1. 구글의 QR Codes API 에 요청
  2. QR 코드를 작성하는 OpenSource를 활용해 로컬에서 생성

얼핏 보면 외부 API를 활용 하는게 간단해 보이는데 사실 생성해서 내보내는 것도 생각보다 쉽습니다. 아무리 구글이라고는 하지만 API를 유지 해 줄 의무가 있는건 아니기때문에 QR 코드를 직접 생성해서 내보내는 방식으로 진행 해 보도록 하겠습니다.

ZXING

https://github.com/zxing/zxing

Zxing(Zebra Crossing)는 구글에서 제공하는 오픈 소스인데요, 사실상 QR 코드를 스캔 하는 거의 대부분의 어플리케이션이 해당 프로젝트로 부터 파생되었다고 합니다.

image-20220630175630246

QR Code를 비롯한 다양한 Format을 지원 합니다.

실습

바로 간단한 예제코드를 통해 QR 코드 생성을 해 보도록 하겠습니다. 스프링 부트 프로젝트로 작성 하였습니다.

의존성 추가

pom.xml 파일에 zxing core와 javase 를 추가 해 줍니다.

<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.5.0</version>
</dependency>
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>javase</artifactId>
    <version>3.5.0</version>
</dependency>

요청 페이지

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  QR CODE
  <form action="/qr", method="get">
    <input type="text" name="url"/><button type="submit">create</button>
  </form>
</body>
</html>

QR 코드로 만들 URL 주소를 입력할 페이지를 생성 해 주었습니다. form 태그를 활용했습니다.

image-20220630180019810

위와 같은 간단히 URL을 적을 수 있는 페이지를 만들어 줍니다.

Controller

이번에는 요청을 처리할 컨트롤러를 만들어 줍니다.

QrController.java

@RestController
public class QrController {

    @GetMapping("qr")
    public Object createQr(@RequestParam String url) throws WriterException, IOException {
        int width = 200;
        int height = 200;
        BitMatrix matrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height);

        try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
            MatrixToImageWriter.writeToStream(matrix, "PNG", out);
            return ResponseEntity.ok()
                    .contentType(MediaType.IMAGE_PNG)
                    .body(out.toByteArray());
        }
    }
}

url을 특정 높이와 너비의 BitMatrix 로 생성 한 후, MatrixToImageWriter를 활용해서 이미지로 출력 해 주는 코드 입니다.

image-20220630181230674

File로 작성 할 수도 있지만, 보통 일회성 이기 때문에 Stream에 작성 한 뒤에 응답 하도록 했습니다.

이제 프로젝트를 실행 해서 확인해 보겠습니다.

확인

image-20220630180725448

https://shanepark.tistory.com 를 넣고 create 버튼을 클릭 했습니다.

image-20220630181118949

QR 코드가 생성 된 것이 확인 됩니다.

이제 핸드폰 카메라로 확인 해 보면

image-20220630181048291

정상적으로 입력한 페이지로 이동 하는 것이 확인 됩니다.

Documents

마지막으로 QR 코드 이미지 생성에 사용 할 수 있는 필요한 옵션들 몇 가지 알아보겠습니다.

MatrixToImageConfig

image-20220701112654002

https://zxing.github.io/zxing/apidocs/com/google/zxing/client/j2se/MatrixToImageConfig.html

QR코드 이미지 생성 시 색상 옵션을 설정 할 수 있습니다.

image-20220701112423989

MatrixToImageWriter의 writeToStream을 호출 할 때, 마지막 파라미터로 넣어 줄 수 있습니다.

MatrixToImageConfig conf = new MatrixToImageConfig(MatrixToImageConfig.BLACK,-1);

기본적으로는 위에 보이는 기본 세팅으로 되어 있습니다.

public static final int BLACK = -16777216;

public static final int WHITE = -1;

BLACK, WHITE로 되어 있는 기본 값을 원하는 컬러로 설정 할 수 있습니다. 하지만 ARGB 값으로 넣어야 하기 때문에 약간의 변환이 필요합니다. 저는 아래와 같이 코드를 작성해서 입력 받은 HEX값을 변환하도록 했습니다.

int rgb = Color.white.getRGB();
if (offColor != null && offColor.length() == 6) {
    try {
        int r = Integer.parseInt(offColor.substring(0, 2), 16);
        int g = Integer.parseInt(offColor.substring(2, 4), 16);
        int b = Integer.parseInt(offColor.substring(4, 6), 16);
        rgb = new Color(r, g, b).getRGB();
    } catch (NumberFormatException e) {
        rgb = Color.white.getRGB();
    }
}

QR Code의 배경 색상을 커스터마이징 할 수 있도록 했습니다.

Map<EncodeHintType, Object>

EncodeHintType을 이용해 마진을 설정 하거나 필요한 몇 가지 설정을 할 수 있습니다.

image-20220701112933950

해당 옵션은 MultiFormatWriter의 encode 메서드를 호출 할 때에 hints를 마지막 파라미터로 넣어서 사용 할 수 있습니다.

Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
hints.put(EncodeHintType.MARGIN, 0);
BitMatrix matrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, width, height, hints);

저는 위의 코드를 작성해 Margin을 0으로 변경했습니다.



위의 작성된 코드와 구조를 활용 한다면 대부분의 경우에서 필요한 결과를 얻을 수 있을 거라고 생각합니다.

이상입니다.

reference

반응형