한양과학기술고등학교

에듀테크 프로젝트 대시보드

QR 코드 (구조와 Reed–Solomon)

QR 코드 — 구조와 Reed–Solomon 오류 정정

QR(Quick Response) 코드는 흑백 격자로 정보를 담는 2차원 바코드다. 검은 칸은 비트 1, 흰 칸은 비트 0에 해당하고, 8칸이 모여 하나의 코드워드(1바이트)가 된다. 놀라운 점은 코드의 일부가 찢기거나 가려져도 스캔이 된다는 것 — 데이터의 30%까지 손상돼도 원본을 되살리는 Reed–Solomon 오류 정정 덕분이다. 아래에서 직접 만들고, 하이라이트하고, 부숴 보자.

1. QR 코드 만들고 뜯어보기

오류 정정 레벨
모듈을 클릭하면 색이 뒤집힌다 (손상 테스트).

칸을 클릭해 QR을 훼손해 보자. 데이터·ECC 영역이 일정 비율 이상 망가지면 복원에 실패한다(파인더/타이밍 패턴이 깨지면 스캐너가 코드 자체를 못 찾는다).

현재 손상률 0%
아직 훼손되지 않았다. 깨끗한 코드.

2. QR 코드의 뼈대 — 고정 패턴들

데이터가 들어가기 전, QR에는 스캐너가 코드를 찾고·정렬하고·읽는 방법을 알려주는 고정 구조가 먼저 그려진다.

영역역할
파인더 패턴 (3개 모서리)큰 겹눈 모양. 어느 각도에서 찍어도 1:1:3:1:1 비율이 유지돼 코드의 위치와 회전을 즉시 인식
구분자 (Separator)파인더 둘레의 흰 테두리 1칸. 데이터와 섞이지 않게 격리
타이밍 패턴 (6번 행·열)흑백이 번갈아 찍힌 점선. 모듈 좌표 격자를 동기화하고 버전(크기)을 확인
정렬 패턴 (Alignment)버전 2 이상에 등장하는 작은 겹눈. 종이가 휘거나 비스듬히 찍혀 생긴 왜곡을 보정
포맷 정보파인더 옆 15비트. 오류 정정 레벨(L/M/Q/H)과 적용된 마스크 번호를 담고, 자체적으로도 BCH 오류 정정됨
다크 모듈왼쪽 아래 파인더 위, 항상 검은 1칸 (고정)
데이터 + ECC나머지 전부. 오른쪽 아래부터 2칸 폭으로 위·아래로 지그재그를 그리며 채워진다

3. 마스킹 — 얼룩을 흩뿌리는 이유

데이터를 그대로 배치하면 검은 칸이 뭉치거나, 파인더와 헷갈리는 무늬가 우연히 생겨 스캔이 어려워진다. 그래서 QR은 데이터 영역에 8가지 마스크 패턴 중 하나를 XOR로 덮어, 흑백을 고르게 섞는다. 인코더는 8개를 모두 시도해 벌점(penalty)이 가장 낮은 것을 고르고, 그 번호를 포맷 정보에 적어 둔다. 스캐너는 같은 마스크를 다시 XOR해서 원래 데이터를 복구한다.

각 칸의 식이 참이면 그 모듈을 뒤집는다. (행 r, 열 c)

4. Reed–Solomon 오류 정정 — 30%가 찢겨도 읽힌다

데이터 코드워드 뒤에 ECC 코드워드를 덧붙인다. 원리는 이렇다: k개의 값은 차수 k−1 다항식 하나로 정확히 표현되는데, 그 다항식을 더 많은 점(n개)에서 평가해 함께 보낸다. 일부 점이 망가져도 남은 점들이 같은 다항식을 가리키므로 원래 곡선을 되찾을 수 있다. QR은 이 연산을 유한체 GF(2⁸)(바이트 단위) 위에서 수행한다.

ECC 코드워드가 2t개면 위치를 모르는 오류 t개까지 정정한다 (지워진 위치를 아는 경우엔 2t개까지). 아래 블록에서 ■ 는 데이터, ■ 는 ECC. 클릭하거나 버튼으로 손상시켜 보자.

5. 인코딩 파이프라인

  1. 데이터 분석 — 숫자/영숫자/바이트/한자 중 가장 짧은 인코딩 모드 선택
  2. 비트 스트림 생성 — 모드 지시자 + 길이 + 데이터 비트, 이어서 패딩(0xEC 0x11 반복)
  3. ECC 생성 — 데이터를 블록으로 나눠 각 블록에 Reed–Solomon 나눗셈의 나머지를 ECC로 부착
  4. 배치 — 데이터·ECC 코드워드를 인터리빙해 오른쪽 아래부터 지그재그로 매트릭스에 기록
  5. 마스킹 — 8개 마스크 중 벌점 최소를 선택해 데이터 영역에 XOR
  6. 포맷·버전 정보 — ECC 레벨 + 마스크 번호(+버전 7 이상은 버전 비트)를 고정 위치에 기록
# 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 저장도 가능
한 줄 정리 — QR 코드는 고정 패턴(찾기·정렬·동기화)과 데이터+ECC 영역으로 나뉘고, 데이터는 마스크로 흩뿌려 배치되며, Reed–Solomon 여분 덕분에 최대 30%가 훼손돼도 원본이 복원된다.