내 QR 코드는 모든 테스트를 통과했지만, 사용자 스캐너에서는 실패했습니다 — Quiet Zone은 장식이 아닙니다
요약
QR/바코드 생성 API를 개발하는 과정에서, 자체 테스트는 통과했으나 실제 사용자 환경(OpenCV 등)에서 실패한 원인을 분석했습니다. 핵심 문제는 QR 사양에 필수적인 'Quiet Zone'(빈 공간 마진)의 누락이었습니다. 이로 인해 발생하는 조용한 실패를 방지하기 위해 API가 기본적으로 4모듈 마진을 포함하도록 수정하고, 테스트 환경을 강화했습니다.
핵심 포인트
- QR 코드는 주변 여백(Quiet Zone)이 필수입니다.
- 테스트 시 디코더의 허용 범위에만 의존하면 안 됩니다.
- 실제 사용 환경에서의 실패 모드를 예측해야 합니다.
- 높은 오류 수정 레벨(H)을 사용하는 것이 인쇄물에는 안전합니다.
얼마 전 저는 QR/바코드 생성기 API를 만들었습니다. 이 API는 qrcode부터 EAN-13까지의 심볼로지를 포함하는 PNG 또는 SVG 파일을 한 번의 호출로 base64 인코딩하여 반환합니다. 첫 번째 버그 보고는 사람이 아니라 소비 에이전트로부터 왔습니다. 그들의 OpenCV QRCodeDetector는 제가 생성한 모든 이미지에서 아무것도 반환하지 않았지만, 저의 자체 테스트 스위트는 출력물의 100%를 디코드했습니다.
문제의 원인은 'Quiet Zone'이었습니다. QR 사양(ISO/IEC 18004)은 심볼의 모든 측면에 네 모듈(four modules), 즉 빈 공간인 작은 정사각형 마진을 요구합니다. 저는 PNG 파일을 외부 파인더 패턴에 딱 맞게 크롭하여, 패딩을 호출자(caller)의 레이아웃 문제로 취급했습니다. 제가 선택한 디코더는 누락된 마진을 허용했기 때문에, 저의 왕복 테스트는 계속 녹색이었지만 실제 파이프라인은 조용히 실패하고 있었습니다.
실제 환경에서 두 가지 실패 모드가 나타났습니다:
-
타이트하게 크롭된 가장자리(Tight-cropped edges). 어두운 테두리 모듈이 이미지 가장자리에 밀착되어 있을 때, 일부 고정 임계값 분할 알고리즘은 파인더 패턴을 프레임으로부터 격리하지 못하고 그냥 포기해버립니다.
-
호출자 측 컨텍스트(Caller-side context). 제가 마진을 추가하지 않았고 호출자가 CSS 패딩을 추가했음에도 불구하고, 어두운 페이지 배경 위에서 그 패딩이 인접한 어두운 UI와 섞여서 사실상 Quiet Zone을 삭제해버리는 경우도 있었습니다.
가장 짜증나는 부분은 다음과 같습니다: API는 항상 완벽하게 좋은 이미지와 함께 유효한 200 코드를 반환한다는 것입니다. 조용한 실패(Silent failures)는 에이전트에게 최악입니다. 작동하는 파일과 깨진 결과물을 얻게 되고, 생성기 자체를 의심하기 전에 비전 라이브러리를 몇 시간 동안 디버깅하게 됩니다.
해결책은 다음과 같습니다: API가 이제 기본적으로 4모듈 마진을 포함(설정 가능)하여 반환하며, 저는 어떤 출시 전에도 CI에서 어두운 배경과 인접한 복합체에 대해 렌더링하고 두 개의 독립적인 라이브러리로 디코드합니다.
같은 디버깅 세션에서 얻은 부가 교훈: 누군가가 코드 위에 로고를 찍는 순간 오류 수정 레벨(error correction level)이 중요해집니다. L과 M은 10% 커버만 되어도 간신히 살아남지만, H는 약 30%까지 복구할 수 있습니다. 인쇄물로 갈 것이라면 저는 무조건 Q를 기본값으로 사용합니다.
결국 이 전체를 QR Code Generator API로 https://x402.freeq.one/tools/qr_generator.html로 패키징하게 되었습니다. 이제 마진 기본값은 그 교훈을 인코딩하므로, 디코드 실패에 대한 고고학적 발굴 과정을 건너뛰고 링크가 실제로 스캔되는 부분으로 바로 이동할 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기