에듀테크 프로젝트 대시보드
QR 코드 (구조와 Reed–Solomon)
QR(Quick Response) 코드는 흑백 격자로 정보를 담는 2차원 바코드다. 검은 칸은 비트 1, 흰 칸은 비트 0에 해당하고, 8칸이 모여 하나의 코드워드(1바이트)가 된다. 놀라운 점은 코드의 일부가 찢기거나 가려져도 스캔이 된다는 것 — 데이터의 30%까지 손상돼도 원본을 되살리는 Reed–Solomon 오류 정정 덕분이다. 아래에서 직접 만들고, 하이라이트하고, 부숴 보자.
칸을 클릭해 QR을 훼손해 보자. 데이터·ECC 영역이 일정 비율 이상 망가지면 복원에 실패한다(파인더/타이밍 패턴이 깨지면 스캐너가 코드 자체를 못 찾는다).
데이터가 들어가기 전, QR에는 스캐너가 코드를 찾고·정렬하고·읽는 방법을 알려주는 고정 구조가 먼저 그려진다.
| 영역 | 역할 |
|---|---|
| 파인더 패턴 (3개 모서리) | 큰 겹눈 모양. 어느 각도에서 찍어도 1:1:3:1:1 비율이 유지돼 코드의 위치와 회전을 즉시 인식 |
| 구분자 (Separator) | 파인더 둘레의 흰 테두리 1칸. 데이터와 섞이지 않게 격리 |
| 타이밍 패턴 (6번 행·열) | 흑백이 번갈아 찍힌 점선. 모듈 좌표 격자를 동기화하고 버전(크기)을 확인 |
| 정렬 패턴 (Alignment) | 버전 2 이상에 등장하는 작은 겹눈. 종이가 휘거나 비스듬히 찍혀 생긴 왜곡을 보정 |
| 포맷 정보 | 파인더 옆 15비트. 오류 정정 레벨(L/M/Q/H)과 적용된 마스크 번호를 담고, 자체적으로도 BCH 오류 정정됨 |
| 다크 모듈 | 왼쪽 아래 파인더 위, 항상 검은 1칸 (고정) |
| 데이터 + ECC | 나머지 전부. 오른쪽 아래부터 2칸 폭으로 위·아래로 지그재그를 그리며 채워진다 |
데이터를 그대로 배치하면 검은 칸이 뭉치거나, 파인더와 헷갈리는 무늬가 우연히 생겨 스캔이 어려워진다. 그래서 QR은 데이터 영역에 8가지 마스크 패턴 중 하나를 XOR로 덮어, 흑백을 고르게 섞는다. 인코더는 8개를 모두 시도해 벌점(penalty)이 가장 낮은 것을 고르고, 그 번호를 포맷 정보에 적어 둔다. 스캐너는 같은 마스크를 다시 XOR해서 원래 데이터를 복구한다.
각 칸의 식이 참이면 그 모듈을 뒤집는다. (행 r, 열 c)
데이터 코드워드 뒤에 ECC 코드워드를 덧붙인다. 원리는 이렇다:
k개의 값은 차수 k−1 다항식 하나로 정확히 표현되는데,
그 다항식을 더 많은 점(n개)에서 평가해 함께 보낸다.
일부 점이 망가져도 남은 점들이 같은 다항식을 가리키므로 원래 곡선을 되찾을 수 있다.
QR은 이 연산을 유한체 GF(2⁸)(바이트 단위) 위에서 수행한다.
ECC 코드워드가 2t개면 위치를 모르는 오류 t개까지 정정한다 (지워진 위치를 아는 경우엔 2t개까지). 아래 블록에서 ■ 는 데이터, ■ 는 ECC. 클릭하거나 버튼으로 손상시켜 보자.
0xEC 0x11 반복)# Python: qrcode 라이브러리로 생성 + 콘솔 출력 import qrcode qr = qrcode.QRCode( version=None, # 데이터 길이에 맞춰 자동 error_correction=qrcode.constants.ERROR_CORRECT_M, # L/M/Q/H box_size=10, border=4, ) qr.add_data("https://offset0xf.com") qr.make(fit=True) print(f"버전 {qr.version}, 모듈 {qr.modules_count}x{qr.modules_count}") qr.print_ascii() # 터미널에 흑백 출력 img = qr.make_image() # PNG 저장도 가능