# lpd print filters



## wblock@ (Jul 3, 2013)

free-and-bsd said:
			
		

> So it prints finally from Firefox using "Print to LPR" using a simple `lpr` command. What I did is modifying the first line in /etc/printcap to look like this:
> 
> 
> 
> ...



Yes, the first printer should always be lp.  But printing with Firefox is a different matter (mine core dumped, until I deinstalled print/cups-client, and now it prints fine).



> Only, I can't yet make it use printer's duplex, as `-Z duplex` added to `lpr`doesn't work.



That would only work with CUPS.  Again, base and CUPS printing don't mix well.  I blame CUPS for using the same names for commands that are wildly different and not compatible.

To do double sided with the base lpd(8), I'd create a second print queue for the same printer, and have the double-sided option be part of the options for gs(1) in that queue.  Then select that queue to print double-sided.


----------



## free-and-bsd (Jul 3, 2013)

wblock@ said:
			
		

> Yes, the first printer should always be lp.  But printing with Firefox is a different matter (mine core dumped, until I deinstalled print/cups-client, and now it prints fine).


For me it's so far so good, cups-client not interfering much so far. Only installed it to compile CUPS support into libreoffice-3.5.7 -- all to no avail. Except that now I know how long it takes to build and it doesn't look so scary any longer... but spadmin still doesn't start, even when cupsd is running!


> To do double sided with the base lpd(8), I'd create a second print queue for the same printer, and have the double-sided option be part of the options for gs(1) in that queue.  Then select that queue to print double-sided.


Good to know it is possible after all . I was about to fall back to CUPS and just forget about the problem. But now I'm ready to keep on fighting...


----------



## free-and-bsd (Jul 3, 2013)

So far I could only find out that a PS command to do duplex printing is pretty simple:`<< /Duplex true /Tumble false >> setpagedevice`.
This is exactly the one found in the foomatic PPD file for my printer model, so there's nothing radically new in what it is doing. That's good to know...

But how to add this to lpr command line? I'll keep studying myself, too.


----------



## wblock@ (Jul 3, 2013)

It's not the lpr(1) command line, it should be part of the gs(1) filter used as an input filter in printcap.


----------



## free-and-bsd (Jul 3, 2013)

So far I could get this command to print at least something:`echo "<< /Duplex true /Tumble false >> setpagedevice" | gs -q -dNOPAUSE -dSAFER -sOutputFile=\|lpr -sDEVICE=pswrite myfile.ps`

Yet the `echo...` part doesn't seem to affect the resulting output for it's printed on only one side.

Trying to output this to a file shows no effect on the file of the prepended `echo` command.


----------



## wblock@ (Jul 3, 2013)

Found a file earlier that set duplex mode with PJL... which may or may not work on a Samsung, and may or may not work with PostScript.

I think your approach is very close.  Should add -dBATCH.  I'll keep looking.


----------



## wblock@ (Jul 3, 2013)

Wait, you're using a PostScript printer.  So gs(1) is not needed.  One way to do this would be to modify the PS code in a filter, inserting the needed line.  For example, replace %!PS with %!PS\n<< /Duplex true /Tumble false >> setpagedevice\n.


----------



## free-and-bsd (Jul 3, 2013)

Well well, it seems this PS command `<</Duplex true /Tumble false>>setpagedevice` (spaces removed ) must be added in some special way. In MS Win version of ghostscript one can use `-c "<</Duplex... etc."`. 

Here's the corresponding section from the PPD file:
	
	



```
*OpenUI *Duplex/Double-Sided Printing: PickOne
[CMD]*OrderDependency: 130 AnySetup *Duplex[/CMD]
*DefaultDuplex: None
*Duplex DuplexNoTumble/Long Edge (Standard): "<</Duplex true /Tumble false>>setpagedevice"
*Duplex DuplexTumble/Short Edge (Flip): "<</Duplex true /Tumble true>>setpagedevice"
*Duplex None/Off: "<</Duplex false>>setpagedevice"
*CloseUI: *Duplex
```
This line `*OrderDependency: 130 AnySetup *Duplex` seems to be related to the particular place that code must occupy. Have to read Adobe docs.


----------



## free-and-bsd (Jul 3, 2013)

Documentation says, we need the following in the PS level 2 document:
	
	



```
%%LanguageLevel: 2
%%Requirements: duplex
...
%%EndProlog
%%BeginSetup
....
<< /Duplex true /Tumble false >> setpagedevice
...
```
This is the order in which duplex-related statements need to be place in the document body, and `duplex` must be placed after `collate color` if these exist. 

Good news: this addition to a *.ps really makes it print double-sided.


----------



## free-and-bsd (Jul 4, 2013)

I must add, the above only works for that particular model (Samsung ML-2850) and is taken from the PPD supplied for this one at OpenPrinting page.

At work I have Samsung ML-2950, whose PPD contains different declarations. Which I'll report as soon as I get that one to work using this approach (non-CUPS).


----------



## free-and-bsd (Jul 5, 2013)

Thanks a lot .
You know my problem was that I couldn't figure out how to make my script accept the data fed to it, rather than appended as a command line argument. Just never needed this, so I thought `read variable` was the only way to go. But now I realize most of these text processing utilities accept data both ways...

Commenting on the printer's ability to print from this filter, I've realized this one is NOT a PS printer! I kind of assumed it was, but here it says in the manual: "PCL6/5e SPL." The PS model is ML-2*8*50, this one is ML-2*9*50 and somehow I automatically assumed it was PS as well.

Accordingly in the PPD file (named as "pxlmono") I find this interesting data:
	
	



```
*%========== Ghostscript Command line ==========

*FoomaticRIPCommandLine: "(printf '\033%%-12345X@PJL SET COPIES=&copies;\n'%G|perl -p -e "s/\x26copies\x3b/1/");
(gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -dNOINTERPOLATE %B%A%C %D%E | perl -p -e "s/^\x1b\x25-12345X//" | perl -p -e "s/\xc1\x01\x00\xf8\x31\x44/\x44/g");"
```
Does this tell you anything about how to feed data to this printer, be it through smbclient or directly? Because foomatic-rip uses gs and other already existing programs.


----------



## kpa (Jul 5, 2013)

Well if you did have a PS printer you wouldn't need print/ghostscript9 at all since you could just send the PS directly to the printer


----------



## free-and-bsd (Jul 5, 2013)

Which I don't -- with my PS printer. But now I want to finish this question with the one that's _not_ PS. Just for the sake of experience and also because the non-PS one is in my room, whilst the PS in another.


----------



## wblock@ (Jul 5, 2013)

Posts moved.  Please, let's try to keep the subject of filters which modify print files separate from the means of getting those files to the printer.

The contents of the filter shown in post #11 pretty much give the parameters needed for gs(1).  They are also adding a PJL header and using Perl to modify some characters, but these are not critical.  The ps2pcl filter shown in lpd Printing With FreeBSD will probably work unchanged.  Substituting ljet4 with pxlmono might make it faster, using PCL6 rather than PCL5.  I've never seen much difference, though.

Step 1 is to make sure that this filter produces output the printer accepts.  Connect the printer locally and pipe the output directly to it for a test:

```
% printf "%%\!PS\n/Helvetica findfont 24 scalefont setfont \
72 72 moveto (PostScript tested.) show showpage" \
| gs -dSAFER -dNOPAUSE -q -sDEVICE=ljet4 -sOutputFile=- - > /dev/unlpt0
```

That last part assumes the printer is the only one connected to a USB port.

If that prints, the filter is done.  Then we can go back to the other thread about sending that through smbclient.


----------



## free-and-bsd (Jul 5, 2013)

free-and-bsd said:
			
		

> Documentation says, we need the following in the PS level 2 document:
> 
> 
> 
> ...


For inserting these needed lines into a PS code to enable duplex printing with lpr on the printer supporting PS I've written this filter, which does just that:
	
	



```
#!/bin/sh
my_code="<< /Duplex true /Tumble false >> setpagedevice"

sed -e '/LanguageLevel/a\
%%Requirements: duplex
' -e '/EndProlog/a\
%%BeginSetup \
'"$my_code"' \
%%EndSetup
'
```
(so far tested on stdout only).
But then there may happen to be PS code that already _has_ %%BeginSetup clause in it. In that case I'll need the evaluation done in the smart filter by @wblock@.


----------



## free-and-bsd (Jul 5, 2013)

wblock@ said:
			
		

> Posts moved.  Please, let's try to keep the subject of filters which modify print files separate from the means of getting those files to the printer.
> 
> The contents of the filter shown in post #11 pretty much give the parameters needed for gs(1).  They are also adding a PJL header and using Perl to modify some characters, but these are not critical.  The ps2pcl filter shown in lpd Printing With FreeBSD will probably work unchanged.  Substituting ljet4 with pxlmono might make it faster, using PCL6 rather than PCL5.  I've never seen much difference, though.
> 
> ...


Thanks, I'll try once in the office.


----------



## free-and-bsd (Jul 9, 2013)

@wblock, your code works perfectly well, thanks a lot . And duplex printing in this case is resolved the same way: using the filter mentioned in [post=225850]#15[/post] before piping it to your gs command line and then to smbclient.

OK, here's my full setup for my PCL6 (non-PostScript) printer connected to a MS Windows Vista machine. 
/etc/printcap:
	
	



```
lp|samsung|Samsung ML-2950 Samba printer:\
	:lp=/dev/null:\
	:if=/usr/local/libexec/samba-if:\
	:sd=/var/spool/output/lpd:\
	:lf=/var/log/lpd-errs:\
	:sh:mx#0:


lp-duplex|samsung-duplex|Samsung ML-2950 Samba duplex:\
	:lp=/dev/null:\
	:if=/usr/local/libexec/if-duplex:\
	:sd=/var/spool/output/lpd-duplex:\
	:lf=/var/log/lpd-errs:\
	:sh:mx#0:
```
lpd startup script kept complaining until I added a separate spool for the second printer (logical). chkprintcap proved to be helpful.

Now here are the filters used. samba-if for non-duplex printing:
	
	



```
#!/bin/sh
gs -dSAFER -dNOPAUSE -q -sDEVICE=pxlmono -sOutputFile=- - \
| smbclient "//VLAD/Samsung_ML-2950" -c "print -" -N && exit 0
```

and if-duplex for duplex:
	
	



```
#!/bin/sh
my_code=" << /Duplex true /Tumble false >> setpagedevice"

sed -e '/LanguageLevel/a\
%%Requirements: duplex
' -e '/EndProlog/a\
%%BeginSetup \
'"$my_code"' \
%%EndSetup
' | gs -dSAFER -dNOPAUSE -q -sDEVICE=pxlmono -sOutputFile=- - \
| smbclient "//VLAD/Samsung_ML-2950" -c "print -" -N && exit 0
```
In this example the needed string is saved into $my_code variable, so
that some more page-processing code can be added. As I read in Adobe documentation, there is some "device setup for a particular printer and document" that goes into %%Requirements: ... and %%BeginSetup...%%EndSetup sections...

CONCLUSION.Don't mind if you add this example to your lpd printing article, if you wish. I really couldn't find _any_ documentation on this particular setup, duplex & smb printing. The documentation mentions "filters" yet gives few examples, so people like myself don't quite get it don't feel very sure about how to write them... `lp=/dev/null` setting in /etc/printcap is also quite logical, but not obvious. 

So, because of lack of documentation many think that BSD lpd is all but dead. From this little experience, however, I understood that CUPS and foomatic are doing more or less the same thing as lpd + filters, only the latter using much less code.
And this is more instructive, too .

So, thank you everyone for your kind assistance.


----------



## free-and-bsd (Jul 9, 2013)

Only want to add a couple of words on how the setup described above proves to be superior to that of MS Windows, at least in my office.

The MS Windows guys, when printing to those (Windows-connected) printers via Windows, every now and then experience some sort of problems: now it starts printing fifteen copies instead of just one, now it can't be set to print two-sided/one-sided, now it doesn't print at all...

Clearly then, Unix and FreeBSD with its ancient lpd is far more in control .


----------



## wblock@ (Jul 9, 2013)

This is excellent--it's always great when somebody takes something and runs with it!

It could be a bit of information overload for the original article.  But another article on more advanced lpd(8) filters, maybe...  And these forums are indexed by the search engines, so that information is already going out.


----------



## free-and-bsd (Jul 9, 2013)

I'm glad to be helpful .


----------



## free-and-bsd (Aug 22, 2013)

This topic will not be complete without mentioning _multiple copies printing_. Not expecting much from the FreeBSD lpr(1) command I was all set to modify the filter above to add such functionality... but in the nick of time read the man page .

Thankfully, among such few command line options as it _does_ actually accept lpr(1) command accepts a one to print a certain  number of copies *N*:
	
	



```
lpr -P<printer name> -#[B]N[/B]
```
 Which is very good, because adding corresponing code to the filter above would be problematic, since it's not possible to supply a command line option to a filter used in /etc/printcap.

And although LibreOffice doesn't want to accept LPD as printing option, it can export files into PDF, which then can be opened using evince document viewer, which _can_ print to LPD.


----------



## free-and-bsd (Aug 23, 2013)

free-and-bsd said:
			
		

> ... adding corresponing code to the filter above would be problematic...


Well actually I _did_ write this code... As I first found the option above to supply the _number of copies_ to lpr(1) command I initially thought the code to be useless, but it seems it can be used yet. Here it is: 


```
#!/bin/sh
while getopts ":dc:" opt; do               #parsing here for command line options "-d" or "-c"
   case $opt in 
        d)  
             a="/Duplex true /Tumble false "
             b="duplex";;
        c) 
             e="numcopies ("$OPTARG") collate"
             f="/NumCopies "$OPTARG" ";;
    esac
done

my_code="<< $a $f>> setpagedevice"

if [ -n "$a" ] || [ -n "$e" ]; then         #if no parameters were given, do nothing here 
sed -e '/LanguageLevel/a\       
%%Requirements: '"$b"' '"$e"'
' -e '/EndProlog/a\
%%BeginSetup \
'"$my_code"' \
%%EndSetup
'
fi
```

Possible use: it seems  print/ghostscript doesn't specify any option to add _duplex_ and _number of copies_ to its PostScript-formatted output in a way that would work. This I found out trying previously and this is also confirmed by unanswered questions in various forums on the web. The script above, then, accomplishes the task like this:
	
	



```
gs <some parameters> | [B]$myscript[/B] -[B]d[/B](duplex) -[B]c[/B](copies) <number>
```
 At least one of the parameters, of course, must be there, or you don't really need this .
This filter can be used both before and after gs command, whether we're converting _from_ PS input to, say, PCL6, or something else _to_ PS.


----------



## wblock@ (Aug 23, 2013)

```
if [ -n "$a" ] || [ -n "$e" ]; then
```
can probably be optimized to a single call:

```
if [ -n "$a" -o -n "$e" ]; then
```
(untested).


----------



## free-and-bsd (Aug 23, 2013)

Haven't tried this yet ...

EDIT: yes, it works fine. Interesting post about compound tests of possibly empty strings here:





> ... in a compound test, even quoting the string variable might not suffice. *[ -n "$string" -o "$a" = "$b" ] *may cause an error with *some versions of Bash* if *$string* is empty. The safe way is to append an extra character to possibly empty variables, *[ "x$string" != x -o "x$a" = "x$b" ] *(the "x's" cancel out).


But since we're not using bash we must be safe with it, and so we are.


But I really spent much time trying to make the getopts block work the way I wanted. It would always accept only one parameter of the two... Still not sure what was wrong and why it works now .


----------

