Skip to content

Instantly share code, notes, and snippets.

@bradmartin333
Created November 14, 2025 15:58
Show Gist options
  • Select an option

  • Save bradmartin333/e0d9889cf46fde0d70080cdf9cb588c0 to your computer and use it in GitHub Desktop.

Select an option

Save bradmartin333/e0d9889cf46fde0d70080cdf9cb588c0 to your computer and use it in GitHub Desktop.
downscale PNG and print on bluetooth printer from Windows
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "pillow>=11.2.1",
# ]
# ///
# usage: uv run this_script.py <path_to_png>
import sys
import socket
from PIL import Image
def print_png(file_path):
# Printer config
printer_mac = "00:02:5B:21:28:53" # Your printer's MAC address
printer_width = 384 # pixels, adjust for your printer
# Windows Bluetooth constants
BTPROTO_RFCOMM = 3
# Open and process image
img = Image.open(file_path)
img = img.convert('1') # 1-bit pixels, black and white
# Resize to printer width, keep aspect ratio
w, h = img.size
new_h = int((printer_width / w) * h)
img = img.resize((printer_width, new_h), Image.LANCZOS)
# Each ESC * line can print up to 24 dots (vertical) at once
rows = img.height
# Connect to printer via Bluetooth socket
try:
# Create Bluetooth RFCOMM socket
sock = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, BTPROTO_RFCOMM)
print(f"Connecting to {printer_mac}...")
# Connect to printer (port 1 is standard for SPP)
sock.connect((printer_mac, 1))
print("Connected!")
sock.send(b'\x1B\x33\x00') # Set line spacing
# For each chunk of 24 rows
for y in range(0, rows, 24):
# Prepare 24 rows of data
slice_height = min(24, rows - y)
line_data = bytearray()
for x in range(printer_width):
# For each column, pack 24 bits into 3 bytes (top byte first)
column_bytes = [0, 0, 0]
for b in range(slice_height):
pixel = img.getpixel((x, y + b))
if pixel == 0: # Black pixel
column_bytes[b // 8] |= (1 << (7 - (b % 8)))
line_data.extend(column_bytes)
# ESC * m nL nH [d1...dk]
m = 33 # 24-dot double-density
nL = printer_width & 0xFF
nH = (printer_width >> 8) & 0xFF
cmd = bytes([0x1B, 0x2A, m, nL, nH])
sock.send(cmd)
sock.send(bytes(line_data))
sock.send(bytes([0x0A])) # Line feed
print("Image sent to printer.")
sock.close()
except Exception as e:
import traceback
print(f"Could not print image: {e}")
traceback.print_exc()
if __name__ == "__main__":
if sys.platform != "win32":
print("This script only works on Windows.")
sys.exit(1)
if len(sys.argv) != 2:
print("Usage: python print_png.py <path_to_png>")
else:
print_png(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment