pharmacy-pos-qr-system/backend/test_qr_methods.py
시골약사 161f826380 feat: 실험 파일 영수증에 방법 번호 표시 추가
각 영수증에 "*** 방법 1 ***" 형식으로 번호 표시
어떤 방법이 QR을 성공적으로 인쇄했는지 쉽게 확인 가능

출력 예:
================================
     *** 방법 1 ***
  내장 QR (GS ( k)
================================

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-29 20:12:54 +09:00

299 lines
8.7 KiB
Python

"""
ESC/POS QR 코드 인쇄 방식 테스트
여러 가지 방법을 한 번에 시도하여 어떤 방식이 작동하는지 확인
"""
import socket
import qrcode
import time
from PIL import Image
# 프린터 설정 (고정)
PRINTER_IP = "192.168.0.174"
PRINTER_PORT = 9100
# 테스트 URL (짧은 버전)
TEST_URL = "https://mile.0bin.in/test"
def send_to_printer(data, method_name):
"""프린터로 데이터 전송"""
try:
print(f"\n{'='*60}")
print(f"[{method_name}] 전송 시작...")
print(f"데이터 크기: {len(data)} bytes")
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
sock.connect((PRINTER_IP, PRINTER_PORT))
sock.sendall(data)
sock.close()
print(f"[{method_name}] ✅ 전송 완료!")
time.sleep(2) # 프린터 처리 대기
return True
except Exception as e:
print(f"[{method_name}] ❌ 실패: {e}")
return False
def method_1_native_qr_model2():
"""
방법 1: 프린터 내장 QR 생성 (GS ( k) - Model 2
가장 안정적이지만 프린터 지원 필요
"""
ESC = b'\x1b'
GS = b'\x1d'
commands = []
# 초기화
commands.append(ESC + b'@')
# 헤더
commands.append("\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append(" *** 방법 1 ***\n".encode('euc-kr'))
commands.append(" 내장 QR (GS ( k)\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append("\n".encode('euc-kr'))
# QR 설정
# GS ( k pL pH cn fn n (QR Code)
# cn = 49 (Model 1/2 선택)
# fn = 65 (모델 선택)
# n = 50 (Model 2)
# 모델 설정
commands.append(GS + b'(k' + bytes([3, 0, 49, 65, 50])) # Model 2
# 에러 정정 레벨 설정 (fn=69, n=48=L)
commands.append(GS + b'(k' + bytes([3, 0, 49, 69, 48]))
# 모듈 크기 설정 (fn=67, n=8)
commands.append(GS + b'(k' + bytes([3, 0, 49, 67, 8]))
# QR 데이터 저장 (fn=80)
qr_data = TEST_URL.encode('utf-8')
data_len = len(qr_data) + 3
pL = data_len & 0xFF
pH = (data_len >> 8) & 0xFF
commands.append(GS + b'(k' + bytes([pL, pH, 49, 80, 48]) + qr_data)
# QR 인쇄 (fn=81)
commands.append(GS + b'(k' + bytes([3, 0, 49, 81, 48]))
# 푸터
commands.append("\n".encode('euc-kr'))
commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
commands.append("\n\n\n".encode('euc-kr'))
# 용지 커트
commands.append(GS + b'V' + bytes([1]))
return b''.join(commands)
def method_2_raster_bitmap_gs_v():
"""
방법 2: Raster Bit Image (GS v 0)
"""
ESC = b'\x1b'
GS = b'\x1d'
commands = []
# 초기화
commands.append(ESC + b'@')
# 헤더
commands.append("\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append(" *** 방법 2 ***\n".encode('euc-kr'))
commands.append(" Raster (GS v 0)\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append("\n".encode('euc-kr'))
# QR 이미지 생성 (작게: 80x80)
qr = qrcode.QRCode(version=1, box_size=2, border=2)
qr.add_data(TEST_URL)
qr.make(fit=True)
qr_image = qr.make_image(fill_color="black", back_color="white")
qr_image = qr_image.resize((80, 80))
# 1비트 흑백으로 변환
qr_image = qr_image.convert('1')
width, height = qr_image.size
pixels = qr_image.load()
# GS v 0 명령어
width_bytes = (width + 7) // 8
commands.append(GS + b'v0' + bytes([0])) # 보통 모드
commands.append(bytes([width_bytes & 0xFF, (width_bytes >> 8) & 0xFF])) # xL, xH
commands.append(bytes([height & 0xFF, (height >> 8) & 0xFF])) # yL, yH
# 이미지 데이터
for y in range(height):
for x in range(0, width, 8):
byte = 0
for bit in range(8):
if x + bit < width:
if pixels[x + bit, y] == 0: # 검은색
byte |= (1 << (7 - bit))
commands.append(bytes([byte]))
# 푸터
commands.append("\n".encode('euc-kr'))
commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
commands.append("\n\n\n".encode('euc-kr'))
# 용지 커트
commands.append(GS + b'V' + bytes([1]))
return b''.join(commands)
def method_3_bit_image_esc_star():
"""
방법 3: Bit Image (ESC *) - 24-dot double-density
현재 사용 중인 방식
"""
ESC = b'\x1b'
GS = b'\x1d'
commands = []
# 초기화
commands.append(ESC + b'@')
# 헤더
commands.append("\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append(" *** 방법 3 ***\n".encode('euc-kr'))
commands.append(" Bit Image (ESC *)\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append("\n".encode('euc-kr'))
# QR 이미지 생성 (작게: 80x80)
qr = qrcode.QRCode(version=1, box_size=2, border=2)
qr.add_data(TEST_URL)
qr.make(fit=True)
qr_image = qr.make_image(fill_color="black", back_color="white")
qr_image = qr_image.resize((80, 80))
# 1비트 흑백으로 변환
qr_image = qr_image.convert('1')
width, height = qr_image.size
pixels = qr_image.load()
# ESC * 명령어로 라인별 인쇄
for y in range(0, height, 24):
line_height = min(24, height - y)
# ESC * m nL nH
nL = width & 0xFF
nH = (width >> 8) & 0xFF
commands.append(ESC + b'*' + bytes([33, nL, nH])) # m=33 (24-dot double-density)
# 라인 데이터
for x in range(width):
byte1, byte2, byte3 = 0, 0, 0
for bit in range(line_height):
pixel_y = y + bit
if pixel_y < height:
if pixels[x, pixel_y] == 0: # 검은색
if bit < 8:
byte1 |= (1 << (7 - bit))
elif bit < 16:
byte2 |= (1 << (15 - bit))
else:
byte3 |= (1 << (23 - bit))
commands.append(bytes([byte1, byte2, byte3]))
commands.append(b'\n')
# 푸터
commands.append("\n".encode('euc-kr'))
commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
commands.append("\n\n\n".encode('euc-kr'))
# 용지 커트
commands.append(GS + b'V' + bytes([1]))
return b''.join(commands)
def method_4_simple_text_only():
"""
방법 4: 텍스트만 (비교용)
"""
ESC = b'\x1b'
GS = b'\x1d'
commands = []
# 초기화
commands.append(ESC + b'@')
# 헤더
commands.append("\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append(" *** 방법 4 ***\n".encode('euc-kr'))
commands.append(" 텍스트만 (비교용)\n".encode('euc-kr'))
commands.append("================================\n".encode('euc-kr'))
commands.append("\n".encode('euc-kr'))
commands.append("QR 이미지 대신 URL만 출력\n".encode('euc-kr'))
commands.append("\n".encode('euc-kr'))
commands.append(f"URL: {TEST_URL}\n".encode('euc-kr'))
commands.append("\n\n\n".encode('euc-kr'))
# 용지 커트
commands.append(GS + b'V' + bytes([1]))
return b''.join(commands)
def main():
"""메인 실행"""
print("="*60)
print("ESC/POS QR 코드 인쇄 방식 테스트")
print("="*60)
print(f"프린터: {PRINTER_IP}:{PRINTER_PORT}")
print(f"테스트 URL: {TEST_URL}")
print("="*60)
methods = [
("방법 1: 프린터 내장 QR (GS ( k)", method_1_native_qr_model2),
("방법 2: Raster Bitmap (GS v 0)", method_2_raster_bitmap_gs_v),
("방법 3: Bit Image (ESC *)", method_3_bit_image_esc_star),
("방법 4: 텍스트만", method_4_simple_text_only),
]
results = []
for name, method_func in methods:
try:
data = method_func()
success = send_to_printer(data, name)
results.append((name, success))
except Exception as e:
print(f"[{name}] ❌ 함수 실행 오류: {e}")
results.append((name, False))
# 결과 요약
print("\n" + "="*60)
print("테스트 결과 요약")
print("="*60)
for name, success in results:
status = "✅ 성공" if success else "❌ 실패"
print(f"{name}: {status}")
print("\n인쇄된 영수증을 확인하여 어떤 방법이 QR을 제대로 출력했는지 확인하세요!")
print("="*60)
if __name__ == "__main__":
main()