Make the HP Laser 1003 / 1006 / 1008 (a/w), HP's rebadged Samsung SPL3 laser, print
from Apple Silicon macOS like a normal printer. Cmd-P from any app. No terminal,
no per-job scripts.
HP never shipped a working macOS driver for these. They are not AirPrint, they do not speak PostScript or PCL, and until recently the open-source SPL/QPDL drivers did not produce a stream this exact unit accepts. This project fixes that with a small patch to SpliX and drives the printer natively.
Tested on macOS 26 (Apple Silicon). USB-connected 1003 / 1006 / 1008 (a and w).
It got progressively more native, and the current version is the real deal:
rastertospl inside a Docker/colima Linux VM
(the only thing that produced correct output at the time).This is what the repo ships and what we use. The entire runtime is two compiled
pieces on Apple's own frameworks: a patched SpliX rastertoqpdl CUPS filter (C++, system
libcups) and hpl1008-usbd (C, IOKit + CoreFoundation). No Docker, no VM, no vendor
binary, no Python, no Homebrew libraries. The SPL3 fix is being upstreamed to SpliX
(issue #1).
Plug the printer in over USB, then paste this into Terminal:
git clone https://github.com/Kuberwastaken/hp-laser-1008a-macos.git && cd hp-laser-1008a-macos && ./install.sh
It asks for your password once, builds the two native binaries, and sets up the printer
as "HP Laser 1008a". Print from any app with Cmd-P. Prerequisites: Homebrew
and the Xcode command line tools (xcode-select --install), both build-time only.
Test from the terminal: lp -d HP_Laser_1008a /etc/hosts. Remove everything: ./uninstall.sh.
flowchart LR
A[Any app, Cmd-P] --> B[CUPS]
B --> C[cgpdftoraster<br/>CUPS raster]
C --> D[rastertoqpdl<br/>patched SpliX, C++]
D -->|SPL3 / QPDL| E[hpl100x backend<br/>C + IOKit, root]
E -->|USB bulk write| F[(HP Laser 1008a)]
Two non-obvious pieces make this work:
The backend runs as root. On recent macOS only root can drive USB, and the usb
backend that ships with macOS refuses this printer (it mis-reads the port status as
permanently "offline"). So the USB write lives in a small CUPS backend (hpl100x:/)
installed 0700 root-owned: CUPS runs it as root and it does the raw write with IOKit
(IOUSBInterfaceOpenSeize + WritePipe). The rest of the chain is a normal native CUPS
filter. (The backend sandbox does permit IOKit USB; only the filter sandbox blocks it.)
The printer is dual-mode and macOS flips it. Interface 0 has alt 0 = 7/1/2 (classic
raw printing) and alt 1 = 7/1/4 (IPP-over-USB), sharing bulk-OUT endpoint 0x02. macOS
often leaves the interface on the IPP-USB alt, where the printer expects HTTP framing and
silently drops raw SPL3. The backend reads the config descriptor, finds the classic
interface/alt, and SetAlternateInterfaces back to it before writing. Run
sudo /usr/libexec/cups/backend/hpl100x probe to dump the descriptor.
Earlier versions streamed SPL3 to a root LaunchDaemon over
127.0.0.1:9108because the backend sandbox was assumed to block USB. It does not, so the socket and daemon are gone (seeROADMAP.md, V2). The daemon variant still lives indaemon/+launchd/as a fallback.
The HP Laser 100 series is a genuinely awkward printer on a Mac:
| What you'd try | What happens |
|---|---|
| AirPrint / driverless | Not offered. Its USB HTTP endpoint serves no IPP |
| Generic PCL / PostScript | Printer speaks neither, the CUPS backend hangs "offline" |
| SpliX 2.0.1 | No HP Laser 10x support at all |
| SpliX 2.0.2 (out of the box) | Garbled: striped raster at the page origin, repeated sheets |
| HP's macOS driver | Does not exist |
SpliX 2.0.2 added HP Laser 10x support (QPDL v3, a band-width table), but on the 1008a it
still printed a striped patch at the top-left of every sheet and then ejected and
repeated. We diagnosed it without the printer by feeding an identical raster through both
HP's rastertospl and SpliX and diffing the output:
2480 x 3507
(a 300-dpi grid), SpliX emitted 4960 x 6912 (600-dpi). This printer reads the header
size on a 300-dpi grid, so SpliX's value looked like a ~16 x 23 inch page. It laid one
band at the top, hit the real A4 edge, ejected, believed a giant page remained, and
repeated. Exactly the symptom.HP's own binary confirmed it: disassembling rastertospl shows it computes the header as
points * 300.0 / 72.0. SpliX already had that 300-dpi code; it was just wrongly coupled
to JBIG. The fix (patches/300dpi-header.patch) decouples it and gates it on
specialBandWidth, which is already true for these models. Bands stay 0x11. Ten lines.
hpl1008-usbd matches HP vendor 0x03F0 and the classic
printer-class interface by descriptor, so other 1003/1008 PIDs work as-is.sudo cupsctl --debug-logging) and watch
tail -f /var/log/cups/error_log for the backend's hpl100x: lines. no classic bulk-out interface means the printer re-enumerated in IPP-USB mode; the alt-setting switch handles
it, and sudo /usr/libexec/cups/backend/hpl100x probe shows the current descriptor.error_log (via stderr); the legacy daemon logs to
/private/tmp/hpl1008-daemon.log.Thanks to SpliX (the SPL/QPDL engine), @ValdikSS
for the HP Laser 10x support in SpliX 2.0.2, @janrueth / photovirus for the macOS build
patch, and Pierov's HP Laser 107a on Linux
writeup. The 300dpi-header.patch here is the missing piece for the 1003/1008 series.
MIT for this glue (see LICENSE). SpliX and the patches are GPLv2.
16 commits
C
59.1%
Shell
27.4%
Python
13.4%
Make the HP Laser 1003 / 1006 / 1008 (a/w), HP's rebadged Samsung SPL3 laser, print
from Apple Silicon macOS like a normal printer. Cmd-P from any app. No terminal,
no per-job scripts.
HP never shipped a working macOS driver for these. They are not AirPrint, they do not speak PostScript or PCL, and until recently the open-source SPL/QPDL drivers did not produce a stream this exact unit accepts. This project fixes that with a small patch to SpliX and drives the printer natively.
Tested on macOS 26 (Apple Silicon). USB-connected 1003 / 1006 / 1008 (a and w).
It got progressively more native, and the current version is the real deal:
rastertospl inside a Docker/colima Linux VM
(the only thing that produced correct output at the time).This is what the repo ships and what we use. The entire runtime is two compiled
pieces on Apple's own frameworks: a patched SpliX rastertoqpdl CUPS filter (C++, system
libcups) and hpl1008-usbd (C, IOKit + CoreFoundation). No Docker, no VM, no vendor
binary, no Python, no Homebrew libraries. The SPL3 fix is being upstreamed to SpliX
(issue #1).
Plug the printer in over USB, then paste this into Terminal:
git clone https://github.com/Kuberwastaken/hp-laser-1008a-macos.git && cd hp-laser-1008a-macos && ./install.sh
It asks for your password once, builds the two native binaries, and sets up the printer
as "HP Laser 1008a". Print from any app with Cmd-P. Prerequisites: Homebrew
and the Xcode command line tools (xcode-select --install), both build-time only.
Test from the terminal: lp -d HP_Laser_1008a /etc/hosts. Remove everything: ./uninstall.sh.
flowchart LR
A[Any app, Cmd-P] --> B[CUPS]
B --> C[cgpdftoraster<br/>CUPS raster]
C --> D[rastertoqpdl<br/>patched SpliX, C++]
D -->|SPL3 / QPDL| E[hpl100x backend<br/>C + IOKit, root]
E -->|USB bulk write| F[(HP Laser 1008a)]
Two non-obvious pieces make this work:
The backend runs as root. On recent macOS only root can drive USB, and the usb
backend that ships with macOS refuses this printer (it mis-reads the port status as
permanently "offline"). So the USB write lives in a small CUPS backend (hpl100x:/)
installed 0700 root-owned: CUPS runs it as root and it does the raw write with IOKit
(IOUSBInterfaceOpenSeize + WritePipe). The rest of the chain is a normal native CUPS
filter. (The backend sandbox does permit IOKit USB; only the filter sandbox blocks it.)
The printer is dual-mode and macOS flips it. Interface 0 has alt 0 = 7/1/2 (classic
raw printing) and alt 1 = 7/1/4 (IPP-over-USB), sharing bulk-OUT endpoint 0x02. macOS
often leaves the interface on the IPP-USB alt, where the printer expects HTTP framing and
silently drops raw SPL3. The backend reads the config descriptor, finds the classic
interface/alt, and SetAlternateInterfaces back to it before writing. Run
sudo /usr/libexec/cups/backend/hpl100x probe to dump the descriptor.
Earlier versions streamed SPL3 to a root LaunchDaemon over
127.0.0.1:9108because the backend sandbox was assumed to block USB. It does not, so the socket and daemon are gone (seeROADMAP.md, V2). The daemon variant still lives indaemon/+launchd/as a fallback.
The HP Laser 100 series is a genuinely awkward printer on a Mac:
| What you'd try | What happens |
|---|---|
| AirPrint / driverless | Not offered. Its USB HTTP endpoint serves no IPP |
| Generic PCL / PostScript | Printer speaks neither, the CUPS backend hangs "offline" |
| SpliX 2.0.1 | No HP Laser 10x support at all |
| SpliX 2.0.2 (out of the box) | Garbled: striped raster at the page origin, repeated sheets |
| HP's macOS driver | Does not exist |
SpliX 2.0.2 added HP Laser 10x support (QPDL v3, a band-width table), but on the 1008a it
still printed a striped patch at the top-left of every sheet and then ejected and
repeated. We diagnosed it without the printer by feeding an identical raster through both
HP's rastertospl and SpliX and diffing the output:
2480 x 3507
(a 300-dpi grid), SpliX emitted 4960 x 6912 (600-dpi). This printer reads the header
size on a 300-dpi grid, so SpliX's value looked like a ~16 x 23 inch page. It laid one
band at the top, hit the real A4 edge, ejected, believed a giant page remained, and
repeated. Exactly the symptom.HP's own binary confirmed it: disassembling rastertospl shows it computes the header as
points * 300.0 / 72.0. SpliX already had that 300-dpi code; it was just wrongly coupled
to JBIG. The fix (patches/300dpi-header.patch) decouples it and gates it on
specialBandWidth, which is already true for these models. Bands stay 0x11. Ten lines.
hpl1008-usbd matches HP vendor 0x03F0 and the classic
printer-class interface by descriptor, so other 1003/1008 PIDs work as-is.sudo cupsctl --debug-logging) and watch
tail -f /var/log/cups/error_log for the backend's hpl100x: lines. no classic bulk-out interface means the printer re-enumerated in IPP-USB mode; the alt-setting switch handles
it, and sudo /usr/libexec/cups/backend/hpl100x probe shows the current descriptor.error_log (via stderr); the legacy daemon logs to
/private/tmp/hpl1008-daemon.log.Thanks to SpliX (the SPL/QPDL engine), @ValdikSS
for the HP Laser 10x support in SpliX 2.0.2, @janrueth / photovirus for the macOS build
patch, and Pierov's HP Laser 107a on Linux
writeup. The 300dpi-header.patch here is the missing piece for the 1003/1008 series.
MIT for this glue (see LICENSE). SpliX and the patches are GPLv2.
16 commits
C
59.1%
Shell
27.4%
Python
13.4%