FileSharer 개발 노트 6 — QR 코드의 한계를 글자 수가 아닌 바이트로 확인하기

FileSharer 개발 노트 · 06 / 10

English version

세 개발자가 QR의 입력 용량과 여백을 설명합니다. 그림 속 모자이크는 개념 표현입니다.
AI 일러스트 · 세 개발자가 QR의 입력 용량과 여백을 설명합니다. 그림 속 모자이크는 개념 표현입니다.

공유 링크 옆에 QR 이미지를 붙이면 휴대전화로 주소를 옮기기 편해집니다. 하지만 이미지가 나타났다고 성공한 것은 아닙니다. 카메라가 해독한 문자열이 원래 링크와 같은지, 한글이나 긴 주소에서 다른 경로로 처리되지는 않는지까지 확인해야 합니다.

원본 오프라인 QR 생성 함수로 만든 데모 QR과 디코딩 결과. QR은 접속 시험용이 아닌 예시 주소이며, 온라인 QR 서비스는 호출하지 않았습니다.
원본 오프라인 QR 생성 함수로 만든 데모 QR과 디코딩 결과. QR은 접속 시험용이 아닌 예시 주소이며, 온라인 QR 서비스는 호출하지 않았습니다.

FileSharer의 QrCodeHelper는 먼저 로컬에서 QR 생성을 시도합니다. 이번에는 그중 오프라인 생성 함수만 따로 실행해 경계값을 확인했습니다. 실제 공유 주소나 복호화 키를 외부 서비스로 보내지 않았습니다.

지원 범위를 줄여 구현을 단순하게 만든 선택

이 구현은 QR 버전 1~5의 일부 조합을 사용합니다. 버전 1~3은 오류 정정 수준 M, 버전 4~5는 L을 선택하며, 한 개의 Reed–Solomon 블록으로 처리하는 범위로 제한합니다. 바이트 모드에서 이 코드가 수용하는 최대 입력은 106바이트입니다.

여기서 106은 모든 QR 코드의 최대 용량이 아닙니다. 이 프로젝트가 구현한 조합의 한계입니다. 더 큰 버전이나 다른 데이터 모드를 지원하는 QR 생성기와 구분해야 합니다.

코드는 여덟 마스크 후보에 벌점을 계산해 선택하고, 그림 바깥에 여백을 둡니다. QR 주변에는 네 모듈의 여백이 필요하다는 설명은 DENSO WAVE의 QR 코드 배치 안내에서도 확인할 수 있습니다. 이 여백을 디자인 때문에 잘라 내면 인식 조건이 달라집니다.

같은 글자 수라도 입력 바이트는 다르다

오프라인 함수는 문자열을 UTF-8 바이트로 변환해 처리합니다. 영어 대문자 A와 한글이 같은 비용을 쓰지 않습니다. 실제 함수에 넣은 네 입력은 다음과 같습니다.

입력 UTF-8 길이 원본 함수 결과
데모 로컬 공유 주소 32바이트 이미지 생성
A를 106개 반복 106바이트 이미지 생성
A를 107개 반복 107바이트 null
파일 공유 데모 20바이트 이미지 생성

생성된 세 이미지는 OpenCV QR 디코더에 넣어 원래 문자열과 일치함을 확인했습니다. 단순히 파일이 만들어졌는지만 검사하지 않은 이유입니다. 이 세 건의 성공을 모든 문자 조합, 인쇄 크기, 카메라 환경의 성공으로 확대할 수는 없습니다.

null 뒤에 무엇을 하는지까지 읽어야 한다

상위 Generate 함수는 오프라인 생성이 성공하면 바로 반환합니다. 실패하거나 null을 받으면 온라인 QR API를 호출하는 대체 경로로 넘어갑니다. 주석에는 긴 URL을 위한 경로라고 설명돼 있지만, 코드상 오프라인 생성에서 예외가 발생한 경우에도 같은 대체 경로가 가능합니다.

이 차이는 공유 링크에 비밀이 포함될 때 중요합니다. 외부 다운로드 링크의 # 뒤에 복호화 정보가 있다면, 그 전체 문자열을 QR API의 data 매개변수로 인코딩해 보내는 순간 서비스가 입력 문자열을 받게 됩니다. 브라우저의 일반적인 fragment 처리와 QR 생성 API에 문자열을 전달하는 동작은 다릅니다.

따라서 “오프라인 우선”과 “언제나 외부 전송 없음”을 같은 뜻으로 소개해서는 안 됩니다. 이번 실행에서는 온라인 대체 경로를 호출하지 않았습니다.

실패를 사용자에게 설명하는 편이 나을 때

개인 자료 공유 도구라면 QR 생성 실패 시 링크를 외부로 보내는 동작보다, 길이 제한과 복사 버튼을 안내하는 선택이 더 적합할 수 있습니다. 또는 충분한 범위의 검증된 로컬 인코더로 대체할 수 있습니다. 이것은 현재 기능이 아니라 개선 방향입니다.

테스트 입력도 길이만 채우는 것으로 끝내지 않는 편이 좋습니다. ASCII 경계, 한글, URL 인코딩으로 길어진 주소, 실제 공유 링크 형식, 작은 화면에서 표시한 결과를 따로 확인해야 합니다. 특히 키나 PIN이 있는 링크를 테스트 데이터로 사용할 때는 실제 값 대신 공개해도 되는 예시를 사용해야 합니다.

QR 이미지의 완성 조건

이 프로젝트에서 확인한 결과는 명확합니다. 선택한 입력 세 개는 로컬 생성과 재해독에 성공했고, 107바이트 ASCII 입력은 해당 함수의 범위를 넘었습니다. 사용자에게 필요한 것은 복잡한 QR 내부 구현보다, 생성됐는지·같은 내용인지·어디로 입력이 전달됐는지를 분명하게 알려 주는 동작입니다.

소스 근거
FileSharer.cs:279–321 QrCodeHelper.Generate · FileSharer.cs:404–568 GenerateStandardOfflineQR · FileSharer.cs:614–736 마스크 및 벌점 계산
본문의 개선안은 현재 구현된 기능과 구분합니다.

댓글