https://github.com/ircama/pyprintlpr
LPR (RFC 1179) printer client/server with proxy support
https://github.com/ircama/pyprintlpr
epson esc-pos lpr rfc-1179
Last synced: 7 months ago
JSON representation
LPR (RFC 1179) printer client/server with proxy support
- Host: GitHub
- URL: https://github.com/ircama/pyprintlpr
- Owner: Ircama
- License: other
- Created: 2025-07-13T11:43:47.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-08-09T09:21:42.000Z (12 months ago)
- Last Synced: 2025-08-21T16:19:36.970Z (12 months ago)
- Topics: epson, esc-pos, lpr, rfc-1179
- Language: Python
- Homepage:
- Size: 44.9 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
- Security: SECURITY.md
Awesome Lists containing this project
README
# LPR printer client/server with proxy support
RFC 1179 client and server toolkits and Python library for interacting with printers via LPR protocol or RAW mode, as well as a proxy/server for debugging, job capture, and protocol analysis.
## Features
- RFC 1179 LPR protocol implementation
- Easy-to-use Python API for client and server LPR features
- LPR (515) and RAW (9100) protocol support
- Print job simulation and debugging
- Bidirectional TCP/UDP proxy and traffic inspection
- Job queue management and archiving
- Hexdump tracing and protocol analysis
- Advanced Epson ESC/P2 (if epson_escp2 is installed)
- Cross-platform (Windows, Linux, macOS)
## Installation
```bash
pip install PyPrintLpr
pip install epson_escp2 # Support advanced debugging of the Epson ESC/P2 protocol with the "server -d" option
```
## Command Line Usage
```
Usage: python -m pyprintlpr [client|server] [args...]
client: Run the print client
server: Run the proxy/server
args: use --help to get the client and server usage.
```
### Client
Run the client to send print jobs to a printer:
```
usage: pyprintlpr client [-h] -a ADDRESS [-p PORT]
(-P | -s LIST | -S LIST | -R LIST | -f PRINT_FILE) [-d]
[-e] [-q QUEUE] [-r] [-t TIMEOUT] [-b RECV_BUFFER]
[-u USERNAME] [-l LABEL] [-j JOB_NAME]
RAW and LPR print client.
optional arguments:
-h, --help show this help message and exit
-a ADDRESS, --address ADDRESS
Printer host name or IP address. (Example: -a 192.168.1.87)
-p PORT, --port PORT Printer port (default is "LPR" = 515)
-P, --print Send the "Print any waiting jobs" command (RFC1179 0x01) to
the specified queue and exit.
-s LIST, --status LIST
Send queue state (short) command with "list" attribute
(RFC1179 0x03) to the specified queue and print the result.
-S LIST, --longstatus LIST
Send queue state (long) command with "list" attribute
(RFC1179 0x04) to the specified queue and print the result.
-R LIST, --remove LIST
Remove jobs command with "list" attribute (RFC1179 0x05) to
the specified queue.
-f PRINT_FILE, --file PRINT_FILE
File to be printed
-d, --debug Print debug information
-e, --epson Use Epson header and footer
-q QUEUE, --queue QUEUE
Queue name; default queue name is "PASSTHRU"
-r, --reserved Use reserved port range 721-731 (RFC 1179 requirement)
-t TIMEOUT, --timeout TIMEOUT
Timeout (default: 5.0 seconds)
-b RECV_BUFFER, --buffer RECV_BUFFER
Receive buffer size (default: 4096 bytes)
-u USERNAME, --username USERNAME
User name (default: current user)
-l LABEL, --label LABEL
Label for the job (optional, used to set the name of source
file)
-j JOB_NAME, --job JOB_NAME
Job name (default: "LprClientJob")
RAW/LPR print client.
```
Notes:
- Use the `epson` flag to send Epson-specific headers/footers
- Use the `reserved` flag to comply with RFC 1179 reserved port requirements
- Debugging: Enable logging for protocol analysis
### Server/Proxy
Run the server/proxy to capture, forward, or analyze print jobs:
```
usage: pyprintlpr server [-h] [-a ADDRESS] [-t] [-d] [-I] [-i] [-s] [-p SAVE_PATH] [-q] [-l PORTS] [-e PORTS]
[--timeout TIMEOUT]
RAW and LPR print server with proxy, forward and local loopback features.
optional arguments:
-h, --help show this help message and exit
-a ADDRESS, --address ADDRESS
Printer IP address (if not provided, runs in local-only mode)
-t, --trace Enable hex dump tracing
-d, --decode Decode data file including Epson sequences (requires epson_escp2)
-I, --show-image When decoding, also show image (requires epson_escp2)
-i, --dump-image When decoding, also dump image (requires epson_escp2)
-s, --save-files Save received print jobs to disk
-p SAVE_PATH, --save-path SAVE_PATH
Path name of the directory including the saved jobs (defaut: "lpr_jobs")
-q, --quiet Do not print debug data
-l PORTS, --loopback PORTS
Comma-separated list of ports to loopback instead of forwarding to the target IP (e.g.,
"515,9100")
-e PORTS, --exclude PORTS
Comma-separated list of ports to exclude from tracing (e.g., "515,9100")
--timeout TIMEOUT Timeout in seconds for receiving control/data files (default: 10.0 seconds)
RAW/LPR print server.
```
## Python API Usage
### Client API
The client API allows sending print jobs, check queue status, and interact with printers programmatically.
#### Basic Usage
```python
from pyprintlpr import LprClient
with LprClient('192.168.1.100', port="LPR", queue='PASSTHRU') as printer:
# Send a print job from a file
with open('document.txt', 'rb') as f:
printer.send(f.read())
```
#### LprClient Class Reference
- `LprClient(hostname, port=515, queue='PASSTHRU', ...)` – Initialize client
- **hostname** (`str`):
Printer hostname or IP address to connect to.
- **port** (`int` or `str`, default: `9100`):
Port number for the printer. Use `9100` or `RAW` for RAW printing, `515` or `"LPR"` for LPR protocol.
- **timeout** (`float`, default: `5.0`):
Socket timeout in seconds for network operations.
- **queue** (`str`, default: `"PASSTHRU"`):
LPR queue name, used when sending jobs via LPR protocol.
- **recv_buffer** (`int`, default: `4096`):
Size of the receive buffer for socket operations.
- **username** (`str`, optional):
Username for LPR jobs. Defaults to the current system user if not specified.
- **job_name** (`str`, optional):
Job name for LPR jobs. Defaults to `"LprClientJob"` if not specified.
- **file_name** (`str`, optional):
File name for LPR jobs. Defaults to the job name if not specified.
- **use_reserved_port** (`bool`, default: `False`):
If `True`, attempts to use a reserved source port (721-731) as required by RFC 1179 for LPR protocol.
- Methods:
| **Method** | **Description** |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `connect()` | Opens a TCP socket connection to the printer at the specified host and port, with timeout. |
| `disconnect()` | Gracefully shuts down and closes the socket connection if open. |
| `send(data: bytes)` | Sends `bytes` directly to the printer over the socket connection. |
| `remote_cmd(cmd: str, args: bytes)` | Constructs a Remote Mode command: 2-byte ASCII command + 2-byte little-endian length + arguments. |
| `set_timer` | Constructs the "TI" remote command to synchronize RTC by setting the current time. |
- Context manager support: `with LprClient(...) as printer:`
#### Epson Remote Mode commands
`LprClient` can be used to send *Epson Remote Mode commands* to the printer. Notice that the LPR or RAW channels do not support receiving payload responses from the Epson printer.
Comprehensive, unified documentation for Epson’s *Remote Mode commands* does not exist: support varies by model, and command references are scattered across service manuals, programming guides and third-party sources (for example, the [Developer's Guide to Gutenprint](https://gimp-print.sourceforge.io/reference-html/x952.html) or [GIMP-Print - ESC/P2 Remote Mode Commands](http://osr507doc.xinuos.com/en/OSAdminG/OSAdminG_gimp/manual-html/gimpprint_37.html)).
General sequences:
| **Command** | **Description** | **String** |
| --------------------- | ------------------------------------------------------------ |------------- |
| `LF` | Line Feed (new line). | |
| `SP` | Space. | |
| `NUL` | b'\x00'. | |
| `FF` | Form Feed (b'\x0c'); flushes the buffer / ejects the page. | |
| `INITIALIZE_PRINTER` | Resets printer to default state (ESC @). | |
Specific Epson sequences:
| **Command** | **Description** | **String** |
| --------------------- | ------------------------------------------------------------ |------------- |
| `EXIT_PACKET_MODE` | Exit IEEE 1284.4 (D4) packet mode. See [1], 5.1.1 Exit Packet Mode. Must be sent before any other command. | |
| `REMOTE_MODE` | Enter Epson Remote Command mode. See [1], 6.1.1 Enter Remote Mode | `(R` |
| `ENTER_REMOTE_MODE` | Initialize printer and enter Epson Remote Command mode. | |
| `EXIT_REMOTE_MODE` | Exits Remote Mode. See [1], 6.1.14 Terminate Remote Mode | |
| `JOB_START` | Begins a print job. "JS", b'\x00\x00\x00\x00'. See [1], Start job “JS” nn 00H 00H m1. It is necessary to send the TI command before the JS command. | `JS` |
| `JOB_END` | Ends a print job. "JE", b'\x00'. See [1], End job “JE” 01H 00H 00H | `JE` |
| `PRINT_NOZZLE_CHECK` | Triggers a nozzle check print pattern. "NC", b'\x00\x00' | `NC` |
| (nozzle check) | "NC", b'\x00\x10' | `NC` |
| `VERSION_INFORMATION` | Requests firmware or printer version info. "VI", b'\x00\x00' | `VI` |
| `LD` | Load NVR Settings. See [1], Load Power-On Default NVR into RAM (Remote Mode) "LD" 00H 00H | `LD` |
| (Run print-head cleaning) | "CH" 02H 00H 00H | `CH` |
| (Return the printer ID) | ESC 01 @EJL [sp] ID\r\n | `ID` |
[1]: handbook named "EPSON Programming Guide For 4 Color EPSON Ink Jet Printer XP-410 (Level I)", also including the description of following remote mode commands:
Description | Command | Syntax
-------------- | -- | ----------------------------------
Set printer timer, synchronize RTC | TI | "TI" 08H 00H 00H YYYY MM DD hh mm ss
Set horizontal print position | FP | “FP” 03H 00H 00H m1 m2
Turn printer state reply on/off | ST | “ST” 02H 00H 00H m1
Set Job Name | JH | Job name set “JH” nL nH 00H m1 m2 m3 m4 m5
Paper Feed Setup | SN | Set mechanism sequence "SN" 01H 00H 00H
Set Media information | MI | Select paper media “MI” 04H 00H 00H m1 m2 m3
Set double paper print | DP | Select Duplex Printing “DP” 02H 00H 00H m1
Set user setting | US | User Setting “US” 03H 00H 00H m1 m2
Select paper path | PP | Select paper path “PP” 03H 00H 00H m1 m2
Save Setting | SV | “SV” 00H 00H
See https://gimp-print.sourceforge.io/reference-html/x952.html for other ones.
The following code prints the nozzle-check print pattern:
```python
from pyprintlpr import LprClient
with LprClient('192.168.1.100', port="LPR", queue='PASSTHRU') as lpr:
data = (
lpr.EXIT_PACKET_MODE + # Exit packet mode
lpr.ENTER_REMOTE_MODE + # Engage remote mode commands
lpr.PRINT_NOZZLE_CHECK + # Issue nozzle-check print pattern
lpr.EXIT_REMOTE_MODE + # Disengage remote control
lpr.JOB_END # Mark maintenance job complete
)
lpr.send(data)
```
Some usage examples:
```cmd
python3 -m pyprintlpr client -a 127.0.0.1 -f SECURITY.md -p lpr # Send SECURITY.md to the LPR server using the default queue
python3 -m pyprintlpr client -a 127.0.0.1 -p lpr -s user -q PASSTHRU # List queue (compact form)
python3 -m pyprintlpr client -a 127.0.0.1 -p lpr -S user -q PASSTHRU # List queue (long form)
python3 -m pyprintlpr client -a 127.0.0.1 -p lpr -P # Traverse all jobs to be printed by the default queue
python3 -m pyprintlpr client -a 127.0.0.1 -p lpr -R job # Remove a job
```
### Server/Proxy API
Capture, forward, manage LPR requests. Also process RAW requests.
#### Basic Usage
```python
from pyprintlpr import LprServer
server = LprServer(save_files=True, save_path='lpr_jobs')
# The server can be integrated into an asyncio event loop for advanced use
# For simple usage, run via command line or module interface
```
#### LprServer Class Reference
- `LprServer(save_files=True, save_path=None)` – Initialize server
- `save_files` (`bool`, default: `True`):
If `True`, received print jobs (control and data files) are saved to disk. If `False`, jobs are discarded after dumping data.
- `save_path` (`str`, default: `"lpr_jobs"`):
if `save_files` is set to `True`, directory path where received print jobs are saved. If not specified, defaults to "lpr_jobs" in the current working directory.
- `get_next_job_id()` – Generate next job ID
- `parse_control_file(content: bytes)` – Parse LPR control file
- `format_queue_status(queue: str, long_format=False)` – Format queue status
- `save_job_files(job: LPRJob)` – Save job files to disk
## Examples
### Run the server:
To open the port 161 with Linux O.S., the server shall be run as root.
```bash
python3 -m pyprintlpr server -a 192.168.1.100 -t -l 515
python3 -m pyprintlpr server -a 192.168.178.29 -e 3289,161 -d -s -l 515,9100 # decode the Epson ESC/P2 protocol.
```
### Send print job:
```python
from pyprintlpr import LprClient
with LprClient('192.168.1.100', port=9100) as printer:
printer.send(b'\x1B@Hello Printer!\x0C')
```
### Run as a module
```bash
python -m pyprintlpr client -a 192.168.1.100 -f file.txt
python -m pyprintlpr server -a 192.168.1.100 -t
```
## License
EUPL-1.2 License - See [LICENSE](LICENSE.txt) for details.