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:

  1. Convert the document to PDF using lp
  2. Convert the PDF to URF using gs
  3. 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.   


 

#!/bin/rc

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}
cat req.bin /tmp/a.urf | hget -r 'Content-Type: application/ipp' -b $URL -P post 2>&1
    


Code

 

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

urf_=$(GLOBJ)gdevurf.$(OBJ)

$(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:

HOST=$1
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

  1. 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.
  2. IPP uses gzip compression on top of run-length compression in URF. 

 

References

  1. HP DesignJet T230 large-format printer and URF format support 

 

Comments

Popular posts from this blog

Plan 9 : The Infinity Notebook

Emacs: Binary File Viewer

Plan 9 Remote File Access from Emacs