A production-ready, standalone Python script that acts as an AirPrint and IPP (Internet Printing Protocol) bridge server. It enables iOS (AirPrint) and Android (IPP Everywhere) devices connected to the same network to print documents to Windows printers—including legacy, offline printers that don't support Ethernet or Wi-Fi connections. Transform any offline printer into a network-accessible device, enabling seamless printing from phones and tablets over your local network.
- Native Zero-Configuration Discovery: Broadcasts strictly compliant mDNS
_ipp._tcp.local.and Apple AirPrint_universal._sub._ipp._tcp.local.services. Automatically binds to your active network interface. - Strict iOS 18 Compatibility: Implements Apple's required TXT record properties (like deterministic
UUIDmatching and URF capability strings) to pass the strict iOS 18 discovery validation checks. - HTTP/1.1 & Chunked Transfer Encoding: A custom HTTP server that natively handles the
Expect: 100-continueand chunked HTTP payloads sent by iOS for large print jobs. - Robust Headless PDF Rendering: Avoids unreliable Windows shell commands (like
ShellExecute printto) which break when Microsoft Edge is the default PDF viewer. Instead, it usesPyMuPDFto render documents natively. - Scale-to-Fit & DPI-Aware 1:1 Rendering: Dynamically parses IPP
mediapaper size attributes (A4, A5, A6, 4×6" labels, etc.) and configures Windows printerDEVMODEsettings per print job. Renders at true physical 1:1 scale using the printer's native DPI with automatic safety clamping, fixing shrunken prints on thermal label printers (like Zebra ZD220D).
By strictly adhering to Apple AirPrint and standard IPP Everywhere requirements, this service achieves seamless driverless printing across platforms:
- iOS & iPadOS: Fully tested and verified on iPhone (works fine). Supports virtually all versions from iOS 4.2 up through iOS 18+. Passes strict zero-configuration checks introduced in iOS 16–18.
- macOS: Natively supported via Bonjour / AirPrint discovery.
- Android: Implemented via standard IPP Everywhere / Mopria specifications (untested by the author; see Android Testing Disclaimer).
Tip
v1.4.2 Release Highlights:
- Smart Default Printer Resolution (Issue #7): Detects the logged-in user's default printer from
HKEY_USERSeven when running as theSYSTEMWindows Service, validates printers againstEnumPrintersso deleted printers are never selected, automatically prefers physical printers over virtual printers (Microsoft Print to PDF), and adds an optional"printer_name"override inconfig.json. - Automatic Windows Firewall Rules in Installer (Issue #8): The setup wizard now includes a built-in option to automatically configure inbound Windows Firewall rules for IPP (
TCP 631) and mDNS (UDP 5353) on installation and remove them on uninstallation. - Banded GDI Rendering, 4-Pixel Stride Alignment & Raster Fixes (Issue #9): Eliminates ~90 MB/page monolithic GDI
StretchDIBitsallocations by capping default rasterization at300DPI (max_render_dpiinconfig.json), aligning bitmap widths to 4-pixel boundaries to prevent 24-bit scanline shearing, drawing pages in 256-row horizontal bands, and fixing Apple URF / PWG Raster PackBits decoding. - Full macOS/CUPS Media Collection & Landscape Conformance (Issue #10): Advertises
media-col-default,media-col-ready,media-size-supported,media-col-database,orientation-requested-supported, and completeoperations-supportedso macOS exposesA4and all supported paper sizes natively and prints Landscape jobs accurately.
AirPrint Bridge automatically detects your network interface, default physical printer, and paper dimensions with zero configuration required. For advanced features, a config.json file is automatically created in the application directory on first launch:
{
"printer_name": "",
"max_render_dpi": 300,
"reverse_page_order": false,
"auto_rotate_to_fit": false
}| Setting | Default | Description |
|---|---|---|
printer_name |
"" |
Optional explicit Windows printer name to bridge. When empty (""), automatically selects the active user's default physical printer. |
max_render_dpi |
300 |
Maximum rasterization DPI (clamped 72..1200). Keeps GDI spool memory compact (~20 MB vs ~90 MB per page on 600 DPI inkjets) while preserving 1:1 physical scaling. |
reverse_page_order |
false |
When true, prints multi-page documents in reverse order (N → 1). Ideal for printers that output pages face-up so the resulting stack is ordered 1..N. |
auto_rotate_to_fit |
false |
When true, automatically rotates landscape PDF pages 90° clockwise to fit portrait paper (and vice-versa). Eliminates manual rotation on iOS which lacks an orientation dialog. |
Note
Changes to config.json take effect immediately on the next print job without requiring a service restart.
Important
Hardware Testing Disclaimer: The features for Reverse Page Order (Issue #4) and Auto-Rotate Landscape Pages (Issue #5) were implemented in response to community requests. Because the maintainer does not possess every specific printer hardware setup (e.g., vintage face-up printers such as the Canon BJC-85), these options are provided as experimental features based on protocol and raster specifications. Community testing reports and feedback across different printer models are welcome!
Important
Android Testing Disclaimer: The author does not own an Android device, so Android printing has not been tested firsthand. This project has been tested only on iPhone, where it works fine. Android support is implemented in accordance with standard IPP Everywhere and Mopria specifications. Feedback and test results from Android users are warmly welcomed!
Unlike iOS (where AirPrint is always enabled by default in the sharing sheet), Android often has its built-in print service disabled by default depending on the device manufacturer (e.g., Samsung, Xiaomi, OnePlus, Motorola).
To make your Windows printer discoverable on Android:
- Open Settings on your Android device.
- Navigate to Connected devices → Connection preferences → Printing (or search for "Printing" in the Settings search bar).
- Tap Default Print Service and toggle the switch to ON.
- Now, open any photo, document, or webpage, tap Share → Print (or menu Print), and your Windows printer (
<Printer Name> (<PC-Hostname>)) will appear in the printer selection dropdown.
Note
- Alternative Print Service: If your device manufacturer removed the Default Print Service, install the official Mopria Print Service app from Google Play.
- Wi-Fi Network / AP Isolation: Ensure your Android phone and Windows PC are connected to the same Wi-Fi network and subnet. Make sure "AP Isolation" / "Client Isolation" or "Guest Network" is disabled in your Wi-Fi router settings so mDNS (UDP 5353) multicast traffic can pass between devices.
The easiest way to install and run AirPrint Bridge on Windows is using the pre-compiled installer. No Python installation or dependencies are required. Everything is bundled into a self-contained background Windows Service that automatically starts when your PC boots.
- Download the latest
AirPrintBridge_Setup_v1.4.2.exefrom the Releases page. - Run the installer as Administrator and follow the setup wizard.
- The AirPrint Bridge service will automatically start in the background.
- On your iOS or Android device (connected to the same Wi-Fi network), open a document or photo, tap Print, and select your Windows printer.
If you prefer to run from source code or contribute to development:
- Windows OS
- Python 3.8+
Install required dependencies:
pip install zeroconf pymupdf pillow pywin32- Set the printer you want to share as your Default Printer in Windows.
- Run the bridge script:
python airprint_bridge.py- The server will detect your local IP address and default printer, bind to port
631(the standard IPP port), and begin broadcasting on your local network.
To build the standalone executable and setup wizard from source:
# 1. Build PyInstaller single-file console executable
.\build.ps1
# 2. Compile Inno Setup installer wizard (requires Inno Setup 6)
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" .\installer.issIf your device cannot find the printer, you can run the included diagnostic script:
python diagnose.py- Firewall Blocking: Ensure that TCP Port 631 (IPP) and UDP Port 5353 (mDNS/Bonjour) are allowed through the Windows Defender Firewall for inbound connections.
- Ghost Processes: If the script crashes or is terminated forcefully, a zombie Python process might hold port
631open, preventing the script from restarting. You can forcefully kill any process using the port with:$pidToKill = (netstat -ano | Select-String ":631" | Select-String "LISTENING").Line.Split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)[-1]; if ($pidToKill) { Stop-Process -Id $pidToKill -Force }
- Different Subnets: Your mobile device and Windows PC must be on the exact same local Wi-Fi subnet for mDNS multicast packets to reach the device.
- Virtual Printers (e.g. RustDesk, PDF Printers): If the service is running but printing does nothing (or you see a virtual printer name), a program likely changed your Windows Default Printer. To fix:
- Open the Windows Settings app.
- Go to Bluetooth & devices > Printers & scanners.
- Under "Printer preferences", make sure "Let Windows manage my default printer" is turned OFF.
- Click on your actual, physical printer in the list.
- Click the "Set as default" button at the top.
- mDNS Registration: Uses a dual-instance
zeroconfapproach to simultaneously register the primary IPP service and the Apple-specific_universalsubtype pointing to the same instance name in the local domain. - IPP Binary Protocol: The server implements a minimal IPP 1.1 / 2.0 binary protocol parser, handling
Print-Job,Validate-Job, andGet-Printer-Attributesoperations. It responds with mandatory and extended attributes required by modern iOS releases. - Print Spooling: When a document is received, it is dumped to a temporary file.
win32uiandwin32printare used in combination withfitz(PyMuPDF) to draw the document natively into the printer's device context, bypassing the problematic shell-based PDF printing methods.