4P by GN⁺ | ★ favorite | 댓글 1개
  • QR 코드를 손으로 해독할 수 있도록 버전 1의 21×21 모듈 구조부터 마스크 해제와 바이트 변환까지 단계별 절차를 정리함
  • 위치 찾기 패턴, 타이밍 패턴, 형식 정보, quiet zone 같은 특수 영역은 인식에는 필요하지만 실제 데이터 읽기에서는 건너뛰어야 함
  • 데이터는 형식 정보에서 마스크 패턴과 오류 정정 수준을 확인한 뒤, 마스크의 검은 모듈 위치마다 QR 코드 모듈을 뒤집어 복원함
  • 오른쪽 아래에서 시작해 두 열씩 지그재그 순서로 읽으며, Byte 모드에서는 길이 8비트 뒤의 8비트 묶음들이 문자 바이트가 됨
  • 오류 정정 영역까지 손으로 풀 필요는 없으며, 단순 QR 코드는 길이 필드가 가리키는 만큼 바이트를 읽고 ASCII 표로 바꾸면 해독 가능함

손으로 읽을 QR 코드 준비

  • 연습용 QR 코드는 세 가지 방식으로 준비할 수 있음
    • 임의의 텍스트를 입력해 아래에서 설명할 QR 코드를 갱신
    • 카메라로 기존 QR 코드를 스캔해 읽는 법을 학습
    • 무작위 영어 단어로 연습하되, 단어는 표시되지 않아 훈련용으로 사용 가능
  • 예시 QR 코드는 21×21 모듈 크기임
  • QR 코드에서 픽셀에 해당하는 단위는 모듈(module) 이라 부름
  • QR 코드 크기는 버전(version) 으로 구분됨
    • 가장 작은 버전은 21×21 모듈
    • 이후 버전마다 한 변의 크기가 4씩 증가
    • 21×21 모듈 QR 코드는 버전 1임

QR 코드에서 건너뛸 특수 영역

  • 위치 찾기 패턴(finder pattern) 은 스캐너가 QR 코드를 먼저 식별하는 데 도움을 줌
  • 위치 찾기 패턴 주변의 빈 줄은 내용을 읽을 때 건너뛰어야 함
  • 버전 1 QR 코드에는 정렬 패턴(alignment pattern) 이 없음
    • 정렬 패턴은 스캐너가 QR 코드를 올바르게 읽도록 돕는 추가 패턴임
  • 타이밍 패턴(timing pattern) 은 흑백 모듈이 항상 번갈아 나타나는 두 줄로, 스캐너가 QR 코드를 올바르게 읽는 데 도움을 줌
  • 형식 정보는 마스크 패턴오류 정정 수준을 결정함
    • 세로 형식 정보와 가로 형식 정보가 있음
    • 타이밍 패턴은 두 줄을 모두 끊고 지나감
  • quiet zone은 QR 코드 주변의 흰색 테두리임
    • 스캐너가 QR 코드의 시작과 끝을 식별하는 데 도움을 줌

마스크 패턴 해제

  • QR 코드는 큰 검은 덩어리나 흰 덩어리를 피하기 위해 마스크(mask) 를 사용함
  • 마스크에는 총 8가지 선택지가 있음
  • 예시에서는 검은 모듈을 1, 흰 모듈을 0으로 읽어 마스크 패턴 비트를 확인함
    • 예시 비트는 이진수 110
    • 110은 십진수 6에 해당함
  • 각 마스크 유형에는 미리 정의된 패턴이 있음
  • 예시 QR 코드의 패턴은 흑백 무지개의 일부처럼 보이는 패턴임
  • 마스크를 데이터 영역 위에 반복해서 놓은 뒤, 마스크에서 검은 모듈인 위치마다 QR 코드 모듈을 뒤집음
  • 모든 마스크 유형의 치트시트를 담은 DIY zine이 제공됨

인코딩 모드와 읽기 순서

  • 내용 해독은 먼저 인코딩 모드를 확인하는 데서 시작함
  • 인코딩 정보는 항상 오른쪽 아래 구석에 있음
  • 인코딩 모드도 먼저 마스크를 적용해 해제해야 함
    • 예시에서는 치트시트를 보고 두 박스를 XOR함
  • 인코딩 모드에는 Numeric, Alphanumeric, Byte, ECI, Kanji 등이 있음
  • 예시 QR 코드의 인코딩 모드는 Byte(4)
  • 내용은 오른쪽 아래 구석에서 시작함
    • 두 열 사이를 지그재그로 오르며 읽음
    • 그다음 왼쪽의 다음 두 열에서 지그재그로 내려감
    • 모든 특수 영역은 항상 건너뜀

길이와 바이트 해독

  • 4비트는 인코딩 모드임
  • Byte 모드에서는 다음 8비트가 내용 길이를 지정함
  • 이후에는 8비트마다 하나의 내용 바이트가 됨
  • 길이 정보도 마스크를 적용해 해제해야 함
  • 예시의 마스크 해제된 길이 정보는 00001100
    • 십진수로 12
    • 전체 내용 길이가 12바이트라는 뜻임
  • 첫 번째 마스크 해제 바이트는 01001000
    • 16진수로 0x48
    • 대응하는 ASCII 문자는 H
  • 두 번째 마스크 해제 바이트는 01100101
    • 16진수로 0x65
    • 대응하는 ASCII 문자는 e
  • 나머지 바이트는 연습용으로 남겨져 있으며, 앞서 읽은 길이 필드가 가리키는 문자 수만큼 읽으면 멈출 수 있음

ASCII 표와 오류 정정

  • ASCII 표를 사용해 16진수 값을 문자로 변환할 수 있음
  • 소문자는 a0x61에서 시작하고 z0x7A에서 끝남
    • 중간 문자는 세어서 찾을 수 있음
  • 모든 남은 영역이 내용은 아님
  • QR 코드에는 오류 정정(error correction) 도 포함됨
    • 일부가 손상되거나 흐리거나 빠져도 QR 코드를 읽을 수 있게 함
    • 오류 정정은 수학으로 생성되지만, 손으로 읽는 목적에서는 다루지 않음
  • 단순 QR 코드를 손으로 해독하는 절차를 익힌 뒤에는 무작위 코드 버튼으로 짧은 영어 단어를 연습하거나, Scan code 버튼으로 실제 QR 코드를 스캔할 수 있음
  • 소스 코드는 Codeberg에 있음
    • UTF-8 인코딩 모드를 설명하는 PR을 특히 환영함

댓글과 토론

Hacker News 의견들
  • 90년대 말이나 2000년대 초에 Atari 8비트 디스크 내용을 PC로 옮기고 싶었음
    Atari의 SIO 포트와 PC 직렬 포트를 연결하는 SIO2PC 케이블과 소프트웨어는 알고 있었지만, 당시엔 직접 만들 전자공학 실력이 없었음
    결국 Atari에서 Basic 프로그램을 짜서 디스크를 섹터 단위로 읽고, 그래픽 모드 3의 큼직한 4색 픽셀로 화면에 그렸고, PC의 TV 카드에 Atari를 연결한 뒤 Delphi 프로그램으로 스크린샷을 계속 찍어 데이터를 복호화하게 만듦
    빈 섹터 때문에 픽셀 위치 보정이 틀어져서 마스크 패턴과 체크섬, 섹터 주소까지 넣었고, 그 방식으로 모든 디스크 내용을 PC로 옮길 수 있었음
    지금도 이걸 내 최고의 엔지니어링 성취로 생각함
    10년쯤 뒤에는 AspeQt라는 SIO2PC 프로그램을 만들었고, 더 최신 커뮤니티 포크인 RespeQt가 여전히 이 분야에서 가장 많이 쓰이는 도구이며 AtariAge에 전용 하위 포럼도 있음: https://forums.atariage.com/forum/184-respeqt-sio2pc-softwar...

    • 1세대 iPod 펌웨어와 키를 역공학한 방식이 떠오름
      LCD 백라이트로 비트 패턴을 깜빡이게 하고 카메라로 그 데이터를 읽어냈다고 함: https://mastodon.social/@bagder/111538350617290554
    • 잠긴 시스템이 더 흔해질수록, 이런 식의 디스플레이 기반 데이터 유출은 분명 미래가 있어 보임
  • “오류 정정은 복잡한 수학이라 손으로 읽는 데서는 신경 쓰지 않는다”는 설명은 좀 더 자세해야 함
    수학이 어렵다는 건 알겠지만, 오류 정정 데이터가 끝에 붙는지, 매 바이트 뒤에 붙는지, 중간에 들어가는지 정도는 궁금함
    손상되지 않은 QR 코드라면 오류 정정이 있어도 수학 부분만 건너뛰고 손으로 읽을 수 있는지도 알고 싶음

    • 바코드는 마지막 숫자를 체크섬으로 쓰고, 숫자들을 더하고 곱한 뒤 % 10 같은 계산을 해서 0~9 중 하나가 됨
      그래서 데이터가 틀렸는데도 우연히 체크섬이 맞을 확률이 1/10 있고, 어쨌든 마지막 숫자는 실제 상품의 고유 바코드 ID에는 중요하지 않음
      Home Depot에 반품하던 물건의 바코드가 찢어져 체크섬 숫자가 해진 적이 있었는데, 직원이 수동 조회하기 전에 계산해보려고 필사적으로 서둘렀지만 결국 직원이 이겼고 잊을 수가 없음
      https://www.gs1.org/services/how-calculate-check-digit-manua...
      https://www.simplybarcodes.com/barcode_check_digit_calculato...
    • QR 코드 안의 데이터는 여러 알파벳 중 하나로 비트스트림으로 인코딩되며, 바이트는 그중 하나일 뿐임
      그다음 크기와 오류 정정 수준에 따라 비트스트림을 블록으로 나누고, 각 블록에 대한 오류 정정 데이터를 계산한 뒤 블록들을 인터리브함
      그래서 이 방식은 오류 정정 수준과 관계없이 QR 버전 5를 넘으면 실패하고, 버전 3~5에서도 높은 오류 정정 수준이면 실패함
    • An Artisanal QR Code는 긴 나눗셈과 비슷한 산술로 체크섬을 손으로 계산하는 방법을 보여줌
      실제로는 정보 종류에 따라 Reed-Solomon과 BCH라는 약간 다른 두 코드가 쓰임
      https://www.quaxio.com/an_artisanal_qr_code.html
  • 관련 글들:
    Decoding small QR codes by hand (2012) - https://news.ycombinator.com/item?id=36173441 - 2023년 6월, 댓글 69개
    How a QR code works - https://news.ycombinator.com/item?id=32837565 - 2022년 9월, 댓글 114개
    Creating a QR Code step by step - https://news.ycombinator.com/item?id=24119124 - 2020년 8월, 댓글 41개
    Creating a QR Code step by step - https://news.ycombinator.com/item?id=18360847 - 2018년 11월, 댓글 34개

  • 글 자체도 훌륭하지만, 입력값에 따라 모든 그림을 동적으로 생성한다는 점이 더 멋짐

  • QR 코드를 읽는 방법에 대한 설명이 좋았고, 일반적인 UPC 같은 1차원 바코드를 해독하는 글로는 이것도 괜찮음:
    https://scanbot.io/blog/how-do-barcodes-work/

  • 10년쯤 전에 QR 코드를 손으로 읽어보려 했지만 마스크 패턴 때문에 포기했음
    데이터 타입을 알아내기 전에도 마스크 패턴을 XOR로 적용해야 함
    이 마스크 패턴이 실제 QR 코드 리더에 얼마나 도움이 되는지 궁금함
    지난달에는 최적의 오류 정정 설정을 찾아봤는데, 화면에 표시되는 온전한 매트릭스처럼 손상되지 않은 경우에는 답이 “없음”이었고, 이 결론을 찾기가 쉽지 않았음
    여러 설정과 스캐닝 구현을 실제 환경에서 비교한 자료를 찾지 못했고, 직접 화면의 작은 QR을 여러 오류 정정 수준으로 띄운 뒤 카메라를 흔들어 읽기 문제를 흉내 내봤지만 설정 간 유의미한 차이를 못 봄
    정렬 마커가 최소 네 개 있고, 큰 여백과 타이밍 패턴까지 있는데, 마스크가 없어서 흰 덩어리가 생기는 게 정말 큰 차이를 만들까 싶음
    시각적으로 QR을 읽는 시도를 포기한 두 번째 이유는 대개 아래에 URL이 대체 텍스트로 적혀 있었기 때문인데, 이후 대체 텍스트가 없는 경우도 몇 번 보긴 했지만 매우 드묾

    • 오류 정정은 묘함
      쓰지 않으면 메시지가 공간을 덜 차지하고 QR이 더 작아짐
      스티커 인쇄처럼 고정된 공간에 맞춰야 한다면 픽셀을 물리적으로 더 크게 만들 수 있고, 안정적인 판독에는 오류 정정보다 더 큰 픽셀이 더 도움이 됐음
      메시지 길이에 따라 최종 QR 크기를 바꾸지 않고 오류 정정 수준을 올릴 수 있는 경우가 있는데, 그때는 둘 다 얻는 셈임
    • 오류 정정은 “메시지를 더 작게 만들어 QR 코드 가독성을 높이려면 어떻게 해야 할까”를 고민하는 사람들을 위한 게 아님
      추적 파라미터가 잔뜩 붙은 URL 전체를 버전 25, 117x117 코드에 넣고 큰 간판에 붙였는데, 새똥이 떨어지고 누군가 스티커를 붙여도 데이터가 살아남게 하려는 사람들을 위한 것임
    • 작년에 비슷한 실험을 했고, 적어도 3D 프린팅 QR 코드에서는 오류 정정이 없는 편이 가장 좋았음
      얼마나 작게 출력해도 감지 가능한지 보려던 실험이었고, 옆 댓글처럼 개별 픽셀이 더 커지기 때문으로 보임
  • 10년 전쯤 올라온 QR 해독 영상: https://www.youtube.com/watch?v=KA8hDldvfv0 (20분)
    QR 코드를 단계별로 만드는 내 인터랙티브 웹 페이지도 있음. 기본적으로는 역방향 과정임: https://www.nayuki.io/page/creating-a-qr-code-step-by-step

  • 오류 정정이 궁금해졌는데, QR 코드는 복구 가능 비율을 7%에서 30%까지 다르게 설계할 수 있다고 함
    흥미로움: https://docs.beaconstac.com/en/articles/6018654-what-is-erro...

    • 오류 정정은 정말 흥미로운 주제임
      Shannon이 20세기 중반에 이론적 한계를 찾아냈지만, 그 한계에 도달하는 방법은 아무도 몰랐음
      1990년대에 터보 코드 특허로 갑자기 그 한계에 가까워지자 학계가 믿기 어렵다는 반응을 보였음
      물론 이런 기술 덕분에 빠르고 신뢰성 높은 모바일 네트워크가 가능해짐
  • 2023 Mystery Hunt의 파생 퍼즐 중에, 오류 정정으로도 복구할 수 없을 만큼 망가진 QR 코드를 손으로 해독해야 하는 문제가 있었음
    이 댓글란에 나온 가이드를 전부 살펴봤고 유용하긴 했지만 아주 훌륭하진 않았음
    그래서 이렇게 더 자세한 글이 늘어나는 건 좋고, 이 글은 확실히 완성도가 높아 보임
    궁금하면 퍼즐은 여기 있으며, QR 해독은 후반부에 나옴: https://puzzles.mit.edu/2023/abcde.puzzlefactory.place/puzzl...

  • Wikipedia를 보니 QR 코드는 1994년에 일본 자동차 부품 제조사가 자동차 부품 라벨링을 위해 발명했다고 함
    만약 오늘 발명됐다면 더 개선할 수 있었을지 궁금함
    더 작게 만들거나 더 쉽게 읽게 할 수 있었을까?

    • 충분히 더 나은 새 설계를 막는 건 없음
      1994년에도 바코드는 이미 어디에나 있었지만 QR 코드가 뜨는 걸 막지 못했음
      어쩌면 더 개선할 여지가 별로 없을 수도 있음. 개념을 크게 바꿔서 NFC 같은 것으로 가는 경우가 아니라면
    • 오늘 발명됐다면 육각형이었을 듯함