Skip to content

Fix HP LaserJet 1018 raster scaling on Apple Silicon macOS - #1

Open
greenflute wants to merge 1 commit into
faradayfury:mainfrom
greenflute:fix/lj1018-macos-raster-resolution
Open

Fix HP LaserJet 1018 raster scaling on Apple Silicon macOS#1
greenflute wants to merge 1 commit into
faradayfury:mainfrom
greenflute:fix/lj1018-macos-raster-resolution

Conversation

@greenflute

@greenflute greenflute commented Aug 10, 2026

Copy link
Copy Markdown

Summary

Fix severely undersized output from the HP LaserJet 1018 when using the native ARM64 rastertozjs CUPS filter on Apple Silicon macOS.

This change adds an ARM64-specific PPD that correctly configures the raster resolution. It also adds controlled diagnostic logging and an optional way to capture the generated ZjStream without changing the
data written to CUPS stdout.

Tested environment

  • Printer: HP LaserJet 1018
  • Connection: USB
  • USB URI: usb://Hewlett-Packard/HP%20LaserJet%201018?serial=KP3DDRP
  • Operating system: macOS Tahoe 26.x
  • Hardware: Apple Silicon M5 Max
  • Architecture: native ARM64
  • Rosetta: not installed
  • Filter: rastertozjs
  • Tested resolutions:
    • 600x600 dpi
    • 1200x600 dpi
  • Firmware: sihp1018.img converted with arm2hpdl and uploaded before printing

Symptoms

The native ARM64 rastertozjs filter compiled and executed successfully. CUPS completed the print job, and the printer accepted data and fed paper.

However, the printed content occupied only a very small area of the page and appeared almost blank.

Explicitly selecting A4 and requesting 600x600 dpi did not initially resolve the problem.

Root cause

The ARM64 PPD was derived from the original Foomatic PPD. Its resolution choices still contained Foomatic-only comments:

%% FoomaticRIPOptionSetting: Resolution=600x600dpi

The ARM64 printing pipeline bypasses foomatic-rip:

PDF
-> cgpdftoraster
-> rastertozjs
-> CUPS USB backend
-> printer

Because cgpdftoraster does not interpret the Foomatic comments as PostScript resolution settings, it generated a 100x100 dpi CUPS raster even when 600x600 dpi was requested.

The issue was reproduced offline. Before the fix, an A4 page requested at 600x600 dpi produced:

HWResolution: 100x100 dpi
cupsWidth: 795
cupsHeight: 1138
cupsBytesPerLine: 100

The filter then generated a ZjStream page header containing:

VIDEO_X: 795
VIDEO_Y: 1138
VIDEO_BPP: 1
RASTER_X: 795
RASTER_Y: 1138
RESOLUTION_X: 600
RESOLUTION_Y: 100

The raster contained approximately 100 dpi worth of page pixels, while the printer was told to interpret the horizontal raster at 600 dpi. This caused the page content to be rendered at a fraction of its
intended physical size.

Fix

Add an ARM64-specific HP LaserJet 1018 PPD using the native CUPS raster filter:

*cupsFilter: "application/vnd.cups-raster 0 rastertozjs"

Replace the Foomatic-only resolution comments with standard PostScript setpagedevice instructions:

*Resolution 600x600dpi/600x600 dpi: "<</HWResolution[600 600]>>setpagedevice"
*Resolution 1200x600dpi/1200x600 dpi: "<</HWResolution[1200 600]>>setpagedevice"

After this change, cgpdftoraster correctly applies the selected resolution.

ZjStream calculations

The following HP 1018/1020 calculations were compared with the original foo2zjs MODEL_HP1020 implementation:

bpp = resX / 600;
resX = 600;
VIDEO_X = realWidth / bpp;
VIDEO_BPP = bpp;
RASTER_X = realWidth;

Although this behavior initially appeared suspicious, it matches the original upstream foo2zjs implementation.

This PR therefore does not change the existing VIDEO_X, RASTER_X, VIDEO_BPP, or HP 1018/1020 resolution calculations.

Diagnostics

rastertozjs now writes detailed per-page diagnostics using the prefix:

DEBUG: LJ1018:

The diagnostics include:

  • Page number
  • cupsWidth
  • cupsHeight
  • cupsBytesPerLine
  • cupsBitsPerPixel
  • cupsBitsPerColor
  • cupsColorSpace
  • HWResolution
  • Page size name
  • Integer and floating-point page dimensions
  • ImagingBoundingBox
  • cupsImagingBBox
  • Computed real width
  • Padded JBIG width
  • JBIG height
  • Input and padded bytes per line
  • Computed video bits per pixel
  • Selected model
  • Final ZjStream page-header fields
  • Paper, media, source, plane, and copy values

Existing CUPS logging is preserved.

Optional ZjStream capture

Setting the following environment variable saves an identical copy of the generated ZjStream:

RASTERTOZJS_DEBUG_FILE=/tmp/lj1018.zjs

The filter continues writing normally to stdout so that CUPS printing behavior is unchanged.

All binary output paths use shared output helpers to ensure that stdout and the optional debug file receive the same bytes.

The captured file and stdout output were verified with cmp and SHA-256 and were byte-for-byte identical.

No file is written unless RASTERTOZJS_DEBUG_FILE is explicitly set.

Offline verification

The following offline test path was successfully established:

testpage.pdf
-> cupsfilter
-> cgpdftoraster
-> CUPS raster
-> rastertozjs
-> ZjStream file
-> zjsdecode

Example raster generation:

cupsfilter \
  -i application/pdf \
  -m application/vnd.cups-raster \
  -p PPD/HP-LaserJet_1018-arm64.ppd \
  -o PageSize=A4 \
  -o Resolution=600x600dpi \
  testpage.pdf > /tmp/lj1018.raster

Example ZjStream generation:

RASTERTOZJS_DEBUG_FILE=/tmp/lj1018.zjs \
./rastertozjs \
  1 tester offline 1 \
  "PageSize=A4 Resolution=600x600dpi Model=1" \
  /tmp/lj1018.raster \
  > /tmp/lj1018-stdout.zjs

600x600 dpi result

The 600x600 dpi path was validated both offline and on the physical HP LaserJet 1018.

After the PPD fix, the A4 CUPS raster reports:

HWResolution: 600x600 dpi
cupsWidth: 4769
cupsHeight: 6828
cupsBytesPerLine: 597

The generated ZjStream reports:

VIDEO_X: 4769
VIDEO_Y: 6828
VIDEO_BPP: 1
RASTER_X: 4769
RASTER_Y: 6828
RESOLUTION_X: 600
RESOLUTION_Y: 600
JBIG BIH: 4864x6828

The JBIG width is padded to the alignment required by the HP 1018/1020 path, while the logical raster and video widths remain correct.

The physical printer produced a correctly sized page at 600x600 dpi.

1200x600 dpi result

The 1200x600 dpi path was validated both offline and on the physical HP LaserJet 1018.

The A4 CUPS raster and generated ZjStream report:

HWResolution: 1200x600 dpi
cupsWidth: 9539
cupsHeight: 6828
cupsBytesPerLine: 1193
VIDEO_X: 4769
VIDEO_Y: 6828
VIDEO_BPP: 2
RASTER_X: 9539
RASTER_Y: 6828
RESOLUTION_X: 600
RESOLUTION_Y: 600
JBIG BIH: 9600x6828

These values match the expected upstream MODEL_HP1020 behavior.

The physical printer produced a correctly sized page at 1200x600 dpi without horizontal compression, stretching, or other visible scaling errors.

Physical printer verification

The corrected output was verified on a physical HP LaserJet 1018 at both supported resolutions:

  • 600x600 dpi
  • 1200x600 dpi

At both resolutions, the page printed at the expected physical size instead of being reduced to a very small area.

The tests were performed over USB on macOS Tahoe 26.x running natively on an Apple Silicon M5 Max without Rosetta.

Because the HP LaserJet 1018 stores its firmware in volatile memory, the firmware must be uploaded again after the printer is powered off or restarted. Firmware loading is separate from the raster-scaling fix
in this PR.

Build verification

The repository CI build path was reproduced locally:

make clean
make

All nine filters compiled successfully:

rastertoxqx
rastertozjs
rastertohiperc
rastertoqpdl
rastertolava
rastertohbpl2
rastertohp
rastertooak
rastertoslx

All generated filters were verified as:

Mach-O 64-bit executable arm64

The rastertozjs dynamic dependencies remain limited to macOS system libraries:

/usr/lib/libcups.2.dylib
/usr/lib/libcupsimage.2.dylib
/usr/lib/libSystem.B.dylib

No Rosetta, x86_64-only libraries, Intel Homebrew libraries, or additional third-party dynamic dependencies are required.

PPD validation

The new PPD passes cupstestppd.

The remaining warnings concern pre-existing non-standard media names inherited from the original Foomatic PPD and are unrelated to this fix.

Scope

This change is intentionally limited to:

  • The HP LaserJet 1018 ARM64 PPD
  • Diagnostic output in rastertozjs
  • Optional ZjStream capture support

It does not delete or modify existing HP drivers, CUPS queues, system security settings, SIP configuration, or firmware files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant