PrintDot Client is a local printing middleware developed based on Wails (Go + Vue 3). It acts as a bridge between browsers (or other clients) and the operating system's printers, receiving print instructions via the WebSocket protocol and invoking the system printer for printing.
Key Features:
- Automatically retrieves the list of installed printers in the operating system.
- Starts a WebSocket service to listen for print requests (default port 1122).
- Supports custom service ports and security keys (Secret Key).
- Print Content Requirement: Accepts Base64 encoded PDF content and invokes system printing commands.
- Supports advanced print parameters: copies, interval between copies, and more print settings.
- Provides a visual management interface to view logs and printer status in real-time.
- Real-time Log Monitoring: View system logs in real time.
You can run the compiled executable file (e.g., print-dot-client.exe) directly.
Note: The program automatically starts the WebSocket service (default port 1122) upon startup.
Windows printing note:
- Ensure the Windows printing backend is available and accessible by the app.
After startup, the interface provides the following configuration options:
- Port: WebSocket service listening port (default
1122). - Secret Key: Security key (optional). If a key is set, clients must authenticate when connecting or sending requests.
- Start/Stop Server: Click the button to start or stop the WebSocket service.
- Connection URL: After the service starts, the interface displays the full connection address (e.g.,
ws://localhost:1122/ws?key=...).
Operation Instructions:
- Exit Program: Use the menu bar
Menu->Quit(Ctrl+Q) or the tray menuQuitto completely exit the program. - Run in Background: Clicking the main window close button (X) will not exit the program but minimize it to the system tray. An icon appears in the system tray area, which can be used to quickly recall the window or exit.
- Tray Menu: Right-click the system tray icon to select
Show Main WindoworQuit. - Open Settings: Use the menu bar
Menu->Settings(Ctrl+I) to open the settings window. - View Logs: Use the menu bar
Menu->System Logs(Ctrl+L) to view logs in real time.
- Protocol: WebSocket (
ws://) - Address:
ws://localhost:<PORT>/ws - Authentication:
- If a
Secret Keyis set, it is recommended to carry it in the connection URL:ws://localhost:1122/ws?key=YOUR_PASSWORD - If the key is not carried during connection, it can also be included in the message body sent (but not recommended, as the connection might be rejected).
- If a
After the connection is established, the server immediately sends the current printer list:
{
"type": "printer_list",
"data": [
{"name": "Microsoft Print to PDF", "isDefault": true},
{"name": "ZDesigner GK888t", "isDefault": false}
]
}The client can actively request the latest printer list at any time by sending the following JSON message:
{
"type": "get_printers"
}The server will reply with a printer_list message in the same format as 3.2.1.
Request capabilities for a specific printer:
{
"type": "get_printer_caps",
"printer": "Microsoft Print to PDF"
}Example response:
{
"type": "printer_caps",
"printer": "Microsoft Print to PDF",
"data": {
"paperSizes": ["A4", "Letter"],
"printerPaperNames": ["A4", "Letter"],
"duplexSupported": false,
"colorSupported": true
}
}Note: fields vary by platform. Windows returns Win32_Printer/Win32_PrinterConfiguration info; Linux/macOS returns parsed lpoptions data.
The JSON payload is grouped by feature:
{
"printer": "Microsoft Print to PDF", // [Required] Target printer name
"content": "data:application/pdf;base64,JVBERi...", // [Required] Base64 encoded PDF content (Supports Data URI prefix or raw Base64)
"key": "123456", // [Optional] Auth key (can be omitted if verified during connection)
"job": {
"name": "My Print Job 001", // [Optional] Job name (for logging only)
"copies": 2, // [Optional] Number of copies, default 1
"intervalMs": 1000 // [Optional] Delay between copies (ms)
},
"pages": {
"range": "1-3,5", // [Optional] Page range (N / N-M / N,M / reverse ranges)
"set": "odd" // [Optional] odd | even
},
"layout": {
"scale": "fit", // [Optional] noscale | shrink | fit
"orientation": "portrait" // [Optional] portrait | landscape
},
"color": {
"mode": "color" // [Optional] color | monochrome
},
"sides": {
"mode": "duplex" // [Optional] simplex | duplex | duplexshort | duplexlong
},
"paper": {
"size": "A4" // [Optional] A4 | letter | legal | tabloid | statement | A2 | A3 | A5 | A6
},
"tray": {
"bin": "2" // [Optional] Tray number or name, e.g. 2 / Manual
}
}Note:
- The
contentfield must be a Base64 encoded string of a PDF file.
- Supports standard Data URI format:
data:application/pdf;base64,JVBERi...- Also supports raw Base64 string:
JVBERi...- The server automatically strips the
data:prefix (if present) and validates that the decoded content starts with
| Field | Type | Description |
|---|---|---|
printer |
String | Target printer name. |
content |
String | Base64 encoded PDF content. |
job.name |
String | Print job name. |
job.copies |
Integer | Number of copies. If intervalMs is 0, handled by the system command. |
job.intervalMs |
Integer | Interval (ms). When > 0, the server prints one copy per run. |
pages.range |
String | Page range: N / N-M / N,M / reverse ranges. |
pages.set |
String | Odd/Even: odd / even. |
layout.scale |
String | Scaling: noscale / shrink / fit. |
layout.orientation |
String | Orientation: portrait / landscape. |
color.mode |
String | Color mode: color / monochrome. |
sides.mode |
String | Duplex: simplex / duplex / duplexshort / duplexlong. |
paper.size |
String | Paper size: e.g. A4, letter, legal. If omitted, we try to auto-detect common sizes from PDF MediaBox. |
tray.bin |
String | Tray: number or name. |
Windows
pages.range/pages.set/layout.scale/layout.orientation/color.mode/sides.mode/paper.size/tray.bin/job.copiesare converted to Windows print options.
Linux/macOS (lp/CUPS)
pages.range->-P.pages.set->-o page-set=odd|even.layout.scale->fit-to-page/scaling=100(shrinkuses default behavior).layout.orientation->-o orientation-requested=3|4(may be ignored by drivers).color.mode->-o ColorModel=Gray/-o ColorModel=RGB(may be ignored by drivers).sides.mode->-o sides=....paper.size->-o media=....tray.bin->-o InputSlot=...(depends on driver support).
The server returns the result of each print:
Success Response:
{
"status": "success",
"message": "Printed successfully"
}Failure Response:
{
"status": "error",
"message": "Content must be a PDF file"
}Windows queue tracking note:
On Windows, the server waits for the print job to appear in the printer queue and complete before returning success.
If the job does not appear within 120 seconds, or does not complete within 5 minutes, it returns error with a timeout message.
const socket = new WebSocket('ws://localhost:1122/ws?key=123456');
socket.onopen = () => {
console.log('Connected');
};
socket.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'printer_list') {
console.log('Available printers:', msg.data);
const targetPrinter = msg.data.find(p => p.isDefault) || msg.data[0];
// Example: Actively refresh printer list
// socket.send(JSON.stringify({ type: 'get_printers' }));
// Fetch printer capabilities (paper/duplex/color, etc.)
socket.send(JSON.stringify({
type: 'get_printer_caps',
printer: targetPrinter?.name
}));
} else if (msg.type === 'printer_caps') {
const caps = msg.data || {};
const sizes = caps.printerPaperNames || caps.paperSizes || [];
const paperSize = sizes[0] || 'A4';
// Send print job (grouped by feature)
socket.send(JSON.stringify({
printer: msg.printer,
content: "JVBERi0xLjQKJ...", // Base64 PDF Data
job: {
name: "Test Job",
copies: 2,
intervalMs: 0
},
pages: {
range: "1-3,5",
set: "odd"
},
layout: {
scale: "fit",
orientation: "portrait"
},
color: {
mode: "color"
},
sides: {
mode: "duplex"
},
paper: {
size: paperSize
},
tray: {
bin: "2"
}
}));
} else {
console.log('Response:', msg);
}
};