""" 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()