A small, driver-independent macOS app that prints PDF and PostScript files on an HP LaserJet 1020 connected directly over USB.
Tested on Apple Silicon with macOS 27. It does not use a legacy HP package, Gutenprint, a CUPS printer queue, or Rosetta.
Important
This project supports HP LaserJet 1020 (USB VID 03f0, PID 2b17).
Despite similar names and partially compatible drivers, the 1020 and 1022
are different devices.
The LaserJet 1020 is a host-based printer with very little onboard storage. After every power cycle, the host must upload firmware before the printer can accept a print job. A printer without firmware still appears in the USB device list, which makes the failure look like an ordinary driver problem.
The old HP, Apple, and Gutenprint packages depend on printing components that are no longer reliable on current macOS releases. This project replaces that path with a small userspace pipeline:
flowchart TD
A[PDF or PostScript] --> B[Ghostscript / ps2write]
B --> C[foo2zjs<br/>-P -z1 -L0 · A4 · 600 dpi]
C --> D[ZjStream + JBIG raster data]
D --> E[libusb bulk OUT]
E --> F[HP LaserJet 1020]
- Direct USB printing without a CUPS queue.
- Automatic firmware detection and upload after power-on.
- PDF and PostScript input.
- Configurable copy count from 1 to 99.
- Finder drag-and-drop application.
- Native Apple Silicon executables.
- Partial USB write handling: already-transferred bytes are not resent after a timeout.
- Statically linked
libusbin the built application.
- Apple Silicon/macOS only. The USB code is portable, but Windows and Linux packaging has not been added.
- A4, monochrome, 600 dpi.
- The app does not register a system printer queue; see the legacy Apple driver
alternative below if a normal
Cmd+Pdestination is required. - One print job at a time.
- Ghostscript is a runtime dependency.
- Only the LaserJet 1020 USB ID has been tested.
- Apple Silicon Mac.
- HP LaserJet 1020 connected over USB and powered on.
- Xcode Command Line Tools.
- Homebrew.
- Ghostscript and libusb:
brew install ghostscript libusblibusb is needed when building the app and is then linked statically.
Ghostscript remains a runtime dependency.
Clone this repository together with its foo2zjs submodule:
git clone --recurse-submodules YOUR_REPOSITORY_URL
cd hp_printerPrepare the HP firmware locally:
./prepare-firmware.shThe script verifies the downloaded archive against a pinned SHA-256 checksum before extracting or converting it.
Build and ad-hoc sign the application:
./build-app.shOutput:
HP 1020 Print.app
The build script compiles the required ARM64 binaries, copies the printing
pipeline into the application bundle, validates Info.plist, and applies a
local ad-hoc signature.
Drag a PDF or PostScript file onto HP 1020 Print.app, choose the number of
copies, and click Print.
Alternatively, double-click the app and choose a file. A notification appears after the job has been sent to the printer. Errors are shown in a dialog.
Command-line printing is also available:
./print.sh document.pdf
./print.sh --copies 3 document.pdfThe app looks for Ghostscript in:
- the process
PATH; /opt/homebrew/bin/gs;/usr/local/bin/gs.
Apple's legacy HP 5.1.1 driver can provide a normal macOS print destination. This was tested with an HP LaserJet 1020 on Apple Silicon and macOS 27.0. Its filters are Intel-only, so Rosetta is required. The normal installer rejects macOS versions newer than 15.0; extract only the required runtime files instead of installing the full 933 MB package.
Install Rosetta if it is not already present:
softwareupdate --install-rosetta --agree-to-licenseDownload the official Apple HP 5.1.1 package, mount it, and extract it using built-in macOS tools:
work=$(mktemp -d -t hp1020-apple-driver)
pkgutil --expand-full \
/Volumes/HP_PrinterSupportManual/HewlettPackardPrinterDrivers.pkg \
"$work/package"
payload="$work/package/HewlettPackardPrinterDrivers.pkg/Payload/Library/Printers"
sudo mkdir -p /Library/Printers/hp/laserjet
sudo ditto \
"$payload/hp/laserjet/hplaserjetzjs.bundle" \
/Library/Printers/hp/laserjet/hplaserjetzjs.bundle
sudo install -m 644 \
"$payload/PPDs/Contents/Resources/HP LaserJet 1022.gz" \
"/Library/Printers/PPDs/Contents/Resources/HP LaserJet 1022.gz"Pacifist can install the same two paths if a graphical package browser is preferred. Do not select the entire package. See also ValdikSS's Sequoia guide.
Open System Settings → Printers & Scanners → Add Printer, select the
LaserJet 1020, then choose Select Software… → HP LaserJet 1022, 1.6.1.
The bundle contains the hp1020.acl firmware init file and the
rasterToHPZJS CUPS filter. On the first print, macOS may require approval for
the old HP bundle in Privacy & Security.
hp1020_usbopens USB device03f0:2b17.- It requests the IEEE 1284 Device ID from the printer.
- If the ID lacks
FWVER, it uploadssihp1020.dland waits eight seconds for the printer to initialize. - Ghostscript normalizes the input into PostScript using
ps2write. foo2zjs-wrapperrasterizes it at 600 dpi and runsfoo2zjswith the LaserJet 1020-specific flags-P -z1 -L0and the selected copy count.hp1020_usb --sendwrites the resulting ZjStream data to the bulk OUT USB endpoint.
A successfully initialized printer reports a Device ID containing:
FWVER:20050309
Firmware is stored in printer RAM. Turning the printer off removes it; this is normal, and the next print uploads it again automatically.
app/HP1020Print Finder launcher, file picker, notifications
app/Info.plist macOS application metadata and supported document types
hp1020_usb.c firmware detection and direct USB transfer
print.sh PDF/PS -> PostScript -> ZjStream -> USB pipeline
prepare-firmware.sh local firmware download and conversion
build-app.sh ARM64 build and .app assembly
upstream/ foo2zjs Git submodule (GPLv2)
Generated files are intentionally ignored by Git:
firmware/
HP 1020 Print.app/
hp1020_usb
Confirm the USB identity:
ioreg -p IOUSB -l -w 0 | grep -A 25 "HP LaserJet 1020"Expected values:
idVendor = 1008 # 0x03f0
idProduct = 11031 # 0x2b17
Try a direct cable or a different powered USB adapter if the device is absent.
Install it:
brew install ghostscriptThen verify:
/opt/homebrew/bin/gs --versionRun the command-line path to see the complete log:
./print.sh document.pdfThe log should show FWVER:20050309 before Print data sent.
If a malformed or interrupted job leaves the printer endpoint stalled:
- Turn the printer off.
- Wait ten seconds.
- Turn it on and wait for the green light.
- Retry once.
The app handles partial writes, but it cannot recover printer firmware that has stopped parsing an already-corrupted job.
Release builds are only ad-hoc signed unless the maintainer signs and notarizes them with an Apple Developer ID. Building from source is the safest option. For a downloaded build, use Finder's Open context-menu action only after verifying that it came from the expected repository/release.