A native, driverless print & scan center for Linux.
PrintCenter works with printers that support IPP Everywhere and eSCL/AirScan — the same standards behind AirPrint and Mopria. In other words: most network printers made in the last decade.
No vendor software. No proprietary drivers. No Wine. No pretending a printer needs a 600 MB "device experience suite" to put ink on paper.
I built this after discovering that my printer supposedly had "no Linux support." Turns out that mostly meant the manufacturer couldn't be bothered to make a Linux application. The printer itself speaks perfectly normal, standardized protocols.
So Linux could already talk to it. What was missing was a decent application.
PrintCenter is my attempt at fixing that: one native PyQt6 application for printing, scanning, printer status, usage statistics, and device information, instead of bouncing between CUPS's web interface, a separate scanning application, and whatever embedded web UI the printer shipped with.
More projects like this are probably on the way, because fuck Windows. I want the hardware I own to work with a normal operating system. Apparently this remains a controversial demand.
"No, here you go" — Claude
-
Print PDFs, images, and documents with the options your printer actually supports. Paper size and type, orientation, color, duplex, quality, scaling, copies, etc. Capabilities are queried directly from the printer rather than being hardcoded into the application.
-
Edit opens the file in an actual editor instead of trying to reinvent one. PDFs go to Okular, images to GIMP, documents to LibreOffice. Save the file and PrintCenter refreshes the preview automatically.
-
Scan directly from the printer's flatbed using eSCL/AirScan. Choose color mode, resolution, and format, preview the result, then save it or throw it straight back into the print flow.
-
Multiple printers are supported. Switch between existing CUPS destinations or add a printer directly by IP address/hostname. The latter is particularly useful on networks where mDNS/Bonjour discovery mysteriously disappears into the void because of client isolation, mesh networking, or other networking "features."
-
Live status without constant useless noise. PrintCenter shows a warning when the printer actually has something to complain about: low ink, paper out, jams, and similar conditions. Otherwise it stays out of the way.
-
Usage statistics track total sheets, color vs. monochrome printing, monthly usage, and recent jobs per printer. Statistics are collected from completed CUPS jobs, including jobs that weren't submitted through PrintCenter.
-
Device Info & Advanced exposes model information, network/signal details, MAC address, maintenance box level, and installed firmware version. It's deliberately kept away from the normal print flow because you probably don't need your printer's MAC address while printing a PDF.
Firmware updates are intentionally not automated. PrintCenter will show the installed version and take you to the printer's actual update page. Automating firmware flashing for the sake of saving two clicks seemed like an impressively stupid trade.
- Linux with CUPS
- A printer configured as a CUPS destination
- Python 3.10+
- PyQt6, including
QtPdf/QtPdfWidgets pycups
Scanning and device information use only Python's standard library. No additional scanning SDK or vendor dependency is required.
sudo pacman -S --needed cups python-pyqt6 python-pycups
git clone https://github.com/henriksb/printcenter.git
cd printcenter
./install.shinstall.sh checks the required dependencies and adds PrintCenter to your application menu.
Package names vary slightly because apparently agreeing on names would have been too convenient.
For Debian/Ubuntu:
# Verify the exact PyQt6 package names for your release
sudo apt install cups python3-pyqt6 python3-pyqt6.qtpdf python3-pycupsFedora:
sudo dnf install cups python3-pyqt6 python3-pycupsIf your distribution doesn't package pycups, you can install it with pip instead. Building it requires the CUPS development headers, for example libcups2-dev on Debian/Ubuntu or cups-devel on Fedora.
pip install --user PyQt6 pycupsThen install PrintCenter normally:
git clone https://github.com/henriksb/printcenter.git
cd printcenter
./install.shThe installer is optional. If you'd rather not install anything:
python3 main.pyThat works too.
PrintCenter primarily uses printers already configured in CUPS. It can also add IPP printers through its own Add Printer dialog.
If your printer isn't configured yet, any IPP Everywhere-capable printer can usually be added manually with:
lpadmin -p YourPrinterName -E -v ipp://<printer-ip>/ipp/print -m everywhereIf your printer advertises AirPrint or Mopria support, there's a very good chance this is all you need.
You can also use your desktop environment's normal printer settings if mDNS discovery works properly on your network.
- Start PrintCenter from your application menu or run
python3 main.py. - Click Open File…, drag a file into the window, or use Scan… to scan something directly from the printer.
- Select whatever print options you want. The available controls come from the capabilities reported by the selected printer.
- Click Print.
That's basically it. Printing really shouldn't require more ceremony than this.
Usage Statistics and Device Info & Advanced are available from the toolbar if you want them, and otherwise stay out of your way.
PrintCenter follows semantic versioning.
The installed version is visible through Check for Updates…, which checks the latest GitHub release. Nothing is downloaded or installed behind your back.
If PrintCenter was cloned from the official repository, it can fast-forward the local checkout after you confirm the update. Other installations are directed to the corresponding GitHub release, where the source archive and Linux binary can be downloaded manually.
Restart PrintCenter after updating.
Every vX.Y.Z Git tag automatically creates a GitHub release containing:
- the source for that exact version;
- a Linux x86_64 binary archive;
- generated release notes.
User-visible changes are documented in CHANGELOG.md, and previous releases remain available through GitHub Releases.
Probably because one of these sounds familiar:
-
Your printer supposedly has "no Linux support", despite supporting AirPrint, Mopria, IPP Everywhere, or eSCL. The hardware works fine. The vendor just didn't give you an application.
-
You'd rather have printing, scanning, status, and device information in one place than use CUPS for one thing, a scanning application for another, and the printer's embedded website for everything else.
-
You have multiple network printers and want to switch between them or add another one without digging through system settings.
-
You want to see ink levels and usage statistics without creating an account, installing a vendor application, or sending telemetry into somebody's cloud because apparently printers need accounts now too.
There are no proprietary printer drivers or vendor SDKs hiding underneath this.
PrintCenter talks to the printer using open protocols wherever possible.
Printing goes through CUPS using pycups and driverless IPP Everywhere.
Printer capabilities are queried at runtime, so PrintCenter doesn't need a database containing every printer model and whatever arbitrary collection of features its manufacturer decided to expose.
Scanning talks directly to the printer's eSCL endpoint over HTTP(S).
The eSCL client is implemented from scratch in scan_backend.py using only Python's urllib and xml.etree. No SANE wrapper, vendor scanning SDK, or external scanning library is required.
Additional device information is read from the printer's embedded web server.
Unlike IPP and eSCL, this part isn't standardized, so it's intentionally best-effort. See the limitations below.
| File | Purpose |
|---|---|
printer_backend.py |
CUPS/pycups wrapper: capabilities, status, jobs, and printer management |
scan_backend.py |
eSCL/AirScan client, implemented using the standard library |
ews_client.py |
Best-effort parser for the printer's embedded web interface |
usage_tracker.py |
Per-printer SQLite usage history |
config.py |
Persistent configuration and printer selection |
constants.py |
Human-readable mappings for IPP/PWG values |
main_window.py, *_dialog.py |
UI |
workers.py |
Keeps backend/network operations off the GUI thread |
main.py |
Entry point and application-wide styling |
A project interacting with printers was never going to escape without a limitations section.
Printers are added using their IP address or hostname.
This is deliberate.
Some networks use AP/client isolation, mesh configurations, or other setups that block the multicast traffic mDNS relies on while ordinary unicast communication with the printer works perfectly.
Rather than having discovery work most of the time and mysteriously fail the rest, PrintCenter lets you point directly at the printer.
Printing and scanning use standardized protocols.
Device Info does not.
Some additional information is obtained by parsing the printer's embedded web interface, which is obviously more fragile. A manufacturer can change that HTML in a firmware update and suddenly the parser no longer knows where a particular value lives.
For that reason, every field is independent. If PrintCenter can't find something, that field becomes Unavailable instead of taking the entire panel down with it.
PrintCenter uses the ink levels reported through IPP.
During development, I found at least one printer where the value exposed through IPP disagreed with the value displayed by the printer's own embedded web page at the exact same time.
I have no idea why.
Rather than display two contradictory answers and make you decide which version of reality your cyan tank occupies, PrintCenter uses the IPP value consistently. It's also the value CUPS itself sees.
PrintCenter can display the installed firmware version and link to the printer's official update interface.
It does not flash firmware itself.
A failed print job wastes a sheet of paper. A failed firmware flash can turn a perfectly good printer into an unusually ugly paperweight. Saving a few clicks isn't worth owning that failure mode.
PDFs and images can be previewed natively.
Office documents such as .docx and .odt currently cannot. Use Edit to open them in LibreOffice instead.
PrintCenter has primarily been developed and tested against an Epson EcoTank ET-2951/ET-2950.
The standards-based parts should work with other printers supporting IPP Everywhere and eSCL, but I obviously do not own every printer ever manufactured.
If yours does something weird, open an issue. If you fix the weird thing, PRs are even better.
Do whatever useful thing you want with it.
Built with the help of Claude Code.
Turns out AI is pretty useful when directed toward the noble cause of making printers slightly less shit.