Plan 9: Network Printer (HP Deskjet Ink Advantage 3545)
Internet Printing Protocol
Printing with Internet Printing Protocol (IPP) involves sending a Unirast Format (URF) image with appropriate protocol headers to port 631. It is the basis for standards like Windows Mopria Alliance, Apple AirPrint, and IPP Everywhere. It is also called Driverless Printing since this doesn't involve installing any printer specific driver.
On Plan 9, printing involves three steps:
- Convert the document to PDF using lp
- Convert the PDF to URF using gs
- Send the request to the printer using hget
IPP header (req.bin in the below script) contains page output options like paper size, margins etc. This is generated using ippenc.c.
HOST=$1
FILE=$2
TFILE=/tmp/a.pdf
URL=(http://$HOST:631/ipp/print/)
if (! ~ $#* 2)
echo 'Usage: $0 <printer-ip> <file>'
lp -d stdout $FILE > $TFILE
gs -dNOPAUSE -dBATCH '-sDEVICE=urfgray' -r600 '-sOutputFile=/tmp/out.urf' $TFILE
gzip < /tmp/out.urf > /tmp/a.urf
cat $FILE | hget -r 'Content-Type: application/ipp' -b $URL -P post
LEN1=`{wc -c req.bin | awk '{print $1}'}
LEN2=`{wc -c /tmp/a.urf | awk '{print $1}'}
LEN=`{echo $LEN1 + $LEN2 | bc}
Code
- https://gitlab.com/atamariya/plan9front/-/blob/dev/sys/src/cmd/lp/ippenc.c
- https://gitlab.com/atamariya/plan9front/-/blob/dev/sys/src/cmd/lp/ipp
- https://gitlab.com/atamariya/plan9front/-/blob/dev/sys/src/cmd/gs/src/gdevurf.c
Ghostscript
Ghostscript on 9front is a stripped down version. URF device has to be added from the upstream.
Adding a new device involves the following steps:
- Add urfgray to the DRIVERS variable in mkfile
- Add device definition to contrib9.mak
$(GLOBJ)gdevurf.$(OBJ) : $(GLSRC)gdevurf.c $(PDEVH) $(gsparam_h) $(gxlum_h)
$(GLCC) $(GLO_)gdevurf.$(OBJ) $(C_) $(GLSRC)gdevurf.c
$(DD)urfgray.dev : $(DEVS_MAK) $(urf_) $(GLD)page.dev
$(SETPDEV) $(DD)urfgray $(urf_)
- Add device implementation gdevurf.c to the src directory.
- Run mk fake-make once. Run mk for repeated builds after that. There's a startover target as well to start from a clean slate.
Linux
Script for printing PDF:
FILE=$2
gs -dNOPAUSE -dBATCH '-sDEVICE=urfgray' -r600 '-sOutputFile=out.urf' $FILE
gzip - < out.urf > a.urf
LEN1=$(wc -c < req.bin)
LEN2=$(wc -c < a.urf)
LEN=$(($LEN1 + $LEN2))
{
echo -ne "POST /ipp/print HTTP/1.1\r\n"
echo -ne "Host: $HOST\r\n"
echo -ne "Content-Type: application/ipp\r\n"
echo -ne "Content-Length: $LEN\r\n"
echo -ne "Connection: close\r\n"
echo -ne "\r\n"
cat req.bin
cat a.urf
} | nc $HOST 631
Lessons Learnt
- Printer image is approximately six times larger than screen image (600 vs 96 ppi). So you need efficient processing. As much as possible avoid storage and convert on the fly.
- IPP uses gzip compression on top of run-length compression in URF.
References

Comments
Post a Comment