about summary refs log tree commit diff
path: root/converter/pbm/pbmtoppa
diff options
context:
space:
mode:
Diffstat (limited to 'converter/pbm/pbmtoppa')
-rw-r--r--converter/pbm/pbmtoppa/CREDITS12
-rw-r--r--converter/pbm/pbmtoppa/INSTALL-MORE187
-rw-r--r--converter/pbm/pbmtoppa/LICENSE342
-rw-r--r--converter/pbm/pbmtoppa/Makefile25
-rw-r--r--converter/pbm/pbmtoppa/README.Netpbm30
-rw-r--r--converter/pbm/pbmtoppa/README.REDHAT29
-rw-r--r--converter/pbm/pbmtoppa/cutswath.c360
-rw-r--r--converter/pbm/pbmtoppa/cutswath.h4
-rw-r--r--converter/pbm/pbmtoppa/defaults.h65
-rw-r--r--converter/pbm/pbmtoppa/pbm.c135
-rw-r--r--converter/pbm/pbmtoppa/pbmtoppa.c449
-rw-r--r--converter/pbm/pbmtoppa/pbmtoppa.conf.hp100018
-rw-r--r--converter/pbm/pbmtoppa/pbmtoppa.conf.hp72018
-rw-r--r--converter/pbm/pbmtoppa/pbmtoppa.conf.hp82018
-rw-r--r--converter/pbm/pbmtoppa/ppa.c526
-rw-r--r--converter/pbm/pbmtoppa/ppa.h74
-rw-r--r--converter/pbm/pbmtoppa/ppapbm.h29
17 files changed, 2321 insertions, 0 deletions
diff --git a/converter/pbm/pbmtoppa/CREDITS b/converter/pbm/pbmtoppa/CREDITS
new file mode 100644
index 00000000..007d9a09
--- /dev/null
+++ b/converter/pbm/pbmtoppa/CREDITS
@@ -0,0 +1,12 @@
+CREDITS
+-------
+
+This project would not be where it is without the help of the following
+people:
+
+Ben Boule - first contacted me about the 720 series and helped with testing
+
+Jim Peterson - spent hours modifying the code for the 720 and adding lots of
+features, including all the configurability options.
+
+Kirk Reiten - helped with testing the 1000 series code
diff --git a/converter/pbm/pbmtoppa/INSTALL-MORE b/converter/pbm/pbmtoppa/INSTALL-MORE
new file mode 100644
index 00000000..2565c740
--- /dev/null
+++ b/converter/pbm/pbmtoppa/INSTALL-MORE
@@ -0,0 +1,187 @@
+Installation of ppa-0.8.5 with S.u.S.E. Linux
+(Special Installation with Hp820 and paper size A4)
+___________________________________________________
+
+
+0. Introduction
+
+This text describes how to use the package pbm2ppa written by Tim Norman
+with the S.u.S.E Linux System. This program allows the use of GDI (Winows
+only) printers with Linux. The program pbm2ppa is actually a converter
+between the two formats pbm (an output format from ghostscript) and the
+format understood by the HP printers 720, 820 and 1000. So anyway we have to
+use ghostscript to produce pbm (or faster: pbmraw) files. To print ascii
+files there is an extra step invoking enscript to convert the ascii to
+postscript files.  I rather constructed two new printer spoolers in printcap
+from scratch then using apsfilter: one for postscript files and another for
+ascii files. I welcome solutions in combination with the apsfilter script.
+The installation is quiet easy - after seven steps you should be ready to
+print postscript and ascii files, but it may take some time to adjust the
+constants properly, don't despair.
+
+0.1. Modifications
+
+This was modified on October 18, 1998 by Tim Norman to conform to the new
+A4 paper support in version 0.8.5.
+
+
+1. Installation of program package ppa-0.8.5
+
+Get the packate at http://www.rpi.edu/~normat/technical/ppa/ and compile it
+with
+
+# make 820
+
+or put in your printer number (720, 820 or 1000) (see also INSTALL and README
+file).
+
+
+2. To adjust the paper size to DIN A4, use the -s a4 option to pbm2ppa or
+change your pbm2ppa.conf file to read "papersize a4" (see step 5).
+
+
+3. You can now calibrate the printer with 
+
+For US size paper:
+# pbmtpg | pbm2ppa > /dev/lp1 ( as root )
+For A4 size paper:
+# pbmtpg -a4 | pbm2ppa -s a4 > /dev/lp1 ( as root )
+
+or you try first printing some sample files and calibrate in step 5.
+
+
+4. Now you can print (postscript) files with a shell script like this:
+
+Contents of print:
+
+cat $1 | gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \
+pbm2ppa - - >/dev/lp1
+
+After changing the file modes (i.e. chmod 755 print) you are able to print
+a postscript file invoking the shell script print like:
+
+# print filename.ps
+
+
+To print ascii files just extend the script print with the use of enscript:
+
+Contents of printascii:
+
+enscript -2rj -p- $1 | \
+gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \
+pbm2ppa - - >/dev/lp1
+
+
+Check the manpage for enscript to adjust the options to your flavour.
+Now you can also print ascii files with
+
+# printascii filename.ascii
+
+
+5. It may be possible that you have to recalibrate your printer (see 3.)
+
+Here follow the results from my calibration after printing ascii files with the
+shell script printascii (see 4.). The program pbm2ppa takes the arguments in the
+following order:
+
+1. shell arguments
+2. config file /etc/pbm2ppa.conf
+3. Compiled options from default.h
+
+So whenever you invoke pbm2ppa without arguments the program uses the options
+stored in the file /etc/pbm2ppa.conf, so I suggest to leave there a copy of
+this file.
+
+# Sample configuration file for the HP820 and DIN A4 paper size
+#
+# This file will be automatically read upon startup if it's placed in
+# /etc/pbm2ppa.conf
+#
+
+version  820
+
+papersize	a4
+
+xoff      0 # \ Adjust these for your printer.
+yoff    -600 # / (see CALIBRATE)
+
+# 1/4 inch margins all around (at 600 DPI)
+top       50
+bottom    50
+left      50
+right     50
+
+
+6. To integrate the converter into the Linux system we create two printer
+spooler in /etc/printcap. One to print postscript files and another to print
+plain ascii files.
+
+Contents of /etc/printcap:
+
+lp:\
+        :lp=/dev/lp1:\
+        :sd=/var/spool/lpd/lp:\
+        :lf=/var/spool/lpd/lp/log:\
+        :af=/var/spool/lpd/lp/acct:\
+        :if=/usr/local/bin/ps.if:\
+        :la:mx#0:\
+        :sh:sf:
+
+ascii:\
+        :lp=/dev/lp1:\
+        :sd=/var/spool/lpd/ascii:\
+        :lf=/var/spool/lpd/ascii/log:\
+        :af=/var/spool/lpd/ascii/acct:\
+        :if=/usr/local/bin/ascii.if:\
+        :la:mx#0:\
+        :sh:sf:
+
+
+Here follow some explanations (for more information consult the printcap
+manpage). We use the lp1 device, have two spool directories
+/var/spool/lpd/ascii and /var/spool/lpd/lp (better you create them now) a log
+file (lf) an accounting file (af), suppress form feeds (sf), suppress printing
+of burst page header (sh) and the maximum file size is unlimited (mx#0). To
+integrate the converter pbm2ppa into the system we use two input filters. Maybe
+you have a better solution in combination with apsfilter but until then try
+this way. Actually, the two input filter files are almost identical with the
+shell scripts print and printascii we created in step 4.
+
+File /usr/local/bin/ascii.if:
+
+#! /bin/sh
+enscript -2rj -p- | \
+gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \
+/usr/local/bin/pbm2ppa - -
+
+
+File /usr/local/bin/ps.if:
+
+#! /bin/sh
+gs -sDEVICE=pbmraw -q -dNOPAUSE -r600 -sOutputFile=- - | \
+/usr/local/bin/pbm2ppa - -
+
+
+7. Place pbm2ppa in the directory /usr/local/bin. Now you are ready to print
+files with
+
+# lpr filename.ps
+
+and
+
+# lpr -P ascii filename.ascii
+
+like you are used to it.
+
+Enjoy
+
+
+19. May 1998
+
+Michael Buehlmann
+Badenerstrasse 285
+8003 Zuerich
+Switzerland
+
+mbuehlma@stud.ee.ethz.ch
+
diff --git a/converter/pbm/pbmtoppa/LICENSE b/converter/pbm/pbmtoppa/LICENSE
new file mode 100644
index 00000000..b8512125
--- /dev/null
+++ b/converter/pbm/pbmtoppa/LICENSE
@@ -0,0 +1,342 @@
+

+                    GNU GENERAL PUBLIC LICENSE

+                       Version 2, June 1991

+

+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.

+                          675 Mass Ave, Cambridge, MA 02139, USA

+ Everyone is permitted to copy and distribute verbatim copies

+ of this license document, but changing it is not allowed.

+

+                            Preamble

+

+  The licenses for most software are designed to take away your

+freedom to share and change it.  By contrast, the GNU General Public

+License is intended to guarantee your freedom to share and change free

+software--to make sure the software is free for all its users.  This

+General Public License applies to most of the Free Software

+Foundation's software and to any other program whose authors commit to

+using it.  (Some other Free Software Foundation software is covered by

+the GNU Library General Public License instead.)  You can apply it to

+your programs, too.

+

+  When we speak of free software, we are referring to freedom, not

+price.  Our General Public Licenses are designed to make sure that you

+have the freedom to distribute copies of free software (and charge for

+this service if you wish), that you receive source code or can get it

+if you want it, that you can change the software or use pieces of it

+in new free programs; and that you know you can do these things.

+

+  To protect your rights, we need to make restrictions that forbid

+anyone to deny you these rights or to ask you to surrender the rights.

+These restrictions translate to certain responsibilities for you if you

+distribute copies of the software, or if you modify it.

+

+  For example, if you distribute copies of such a program, whether

+gratis or for a fee, you must give the recipients all the rights that

+you have.  You must make sure that they, too, receive or can get the

+source code.  And you must show them these terms so they know their

+rights.

+

+  We protect your rights with two steps: (1) copyright the software, and

+(2) offer you this license which gives you legal permission to copy,

+distribute and/or modify the software.

+

+  Also, for each author's protection and ours, we want to make certain

+that everyone understands that there is no warranty for this free

+software.  If the software is modified by someone else and passed on, we

+want its recipients to know that what they have is not the original, so

+that any problems introduced by others will not reflect on the original

+authors' reputations.

+

+  Finally, any free program is threatened constantly by software

+patents.  We wish to avoid the danger that redistributors of a free

+program will individually obtain patent licenses, in effect making the

+program proprietary.  To prevent this, we have made it clear that any

+patent must be licensed for everyone's free use or not licensed at all.

+

+  The precise terms and conditions for copying, distribution and

+modification follow.

+

+                    GNU GENERAL PUBLIC LICENSE

+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+

+  0. This License applies to any program or other work which contains

+a notice placed by the copyright holder saying it may be distributed

+under the terms of this General Public License.  The "Program", below,

+refers to any such program or work, and a "work based on the Program"

+means either the Program or any derivative work under copyright law:

+that is to say, a work containing the Program or a portion of it,

+either verbatim or with modifications and/or translated into another

+language.  (Hereinafter, translation is included without limitation in

+the term "modification".)  Each licensee is addressed as "you".

+

+Activities other than copying, distribution and modification are not

+covered by this License; they are outside its scope.  The act of

+running the Program is not restricted, and the output from the Program

+is covered only if its contents constitute a work based on the

+Program (independent of having been made by running the Program).

+Whether that is true depends on what the Program does.

+

+  1. You may copy and distribute verbatim copies of the Program's

+source code as you receive it, in any medium, provided that you

+conspicuously and appropriately publish on each copy an appropriate

+copyright notice and disclaimer of warranty; keep intact all the

+notices that refer to this License and to the absence of any warranty;

+and give any other recipients of the Program a copy of this License

+along with the Program.

+

+You may charge a fee for the physical act of transferring a copy, and

+you may at your option offer warranty protection in exchange for a fee.

+

+  2. You may modify your copy or copies of the Program or any portion

+of it, thus forming a work based on the Program, and copy and

+distribute such modifications or work under the terms of Section 1

+above, provided that you also meet all of these conditions:

+

+    a) You must cause the modified files to carry prominent notices

+    stating that you changed the files and the date of any change.

+

+    b) You must cause any work that you distribute or publish, that in

+    whole or in part contains or is derived from the Program or any

+    part thereof, to be licensed as a whole at no charge to all third

+    parties under the terms of this License.

+

+    c) If the modified program normally reads commands interactively

+    when run, you must cause it, when started running for such

+    interactive use in the most ordinary way, to print or display an

+    announcement including an appropriate copyright notice and a

+    notice that there is no warranty (or else, saying that you provide

+    a warranty) and that users may redistribute the program under

+    these conditions, and telling the user how to view a copy of this

+    License.  (Exception: if the Program itself is interactive but

+    does not normally print such an announcement, your work based on

+    the Program is not required to print an announcement.)

+

+These requirements apply to the modified work as a whole.  If

+identifiable sections of that work are not derived from the Program,

+and can be reasonably considered independent and separate works in

+themselves, then this License, and its terms, do not apply to those

+sections when you distribute them as separate works.  But when you

+distribute the same sections as part of a whole which is a work based

+on the Program, the distribution of the whole must be on the terms of

+this License, whose permissions for other licensees extend to the

+entire whole, and thus to each and every part regardless of who wrote it.

+

+Thus, it is not the intent of this section to claim rights or contest

+your rights to work written entirely by you; rather, the intent is to

+exercise the right to control the distribution of derivative or

+collective works based on the Program.

+

+In addition, mere aggregation of another work not based on the Program

+with the Program (or with a work based on the Program) on a volume of

+a storage or distribution medium does not bring the other work under

+the scope of this License.

+

+  3. You may copy and distribute the Program (or a work based on it,

+under Section 2) in object code or executable form under the terms of

+Sections 1 and 2 above provided that you also do one of the following:

+

+    a) Accompany it with the complete corresponding machine-readable

+    source code, which must be distributed under the terms of Sections

+    1 and 2 above on a medium customarily used for software interchange; or,

+

+    b) Accompany it with a written offer, valid for at least three

+    years, to give any third party, for a charge no more than your

+    cost of physically performing source distribution, a complete

+    machine-readable copy of the corresponding source code, to be

+    distributed under the terms of Sections 1 and 2 above on a medium

+    customarily used for software interchange; or,

+

+    c) Accompany it with the information you received as to the offer

+    to distribute corresponding source code.  (This alternative is

+    allowed only for noncommercial distribution and only if you

+    received the program in object code or executable form with such

+    an offer, in accord with Subsection b above.)

+

+The source code for a work means the preferred form of the work for

+making modifications to it.  For an executable work, complete source

+code means all the source code for all modules it contains, plus any

+associated interface definition files, plus the scripts used to

+control compilation and installation of the executable.  However, as a

+special exception, the source code distributed need not include

+anything that is normally distributed (in either source or binary

+form) with the major components (compiler, kernel, and so on) of the

+operating system on which the executable runs, unless that component

+itself accompanies the executable.

+

+If distribution of executable or object code is made by offering

+access to copy from a designated place, then offering equivalent

+access to copy the source code from the same place counts as

+distribution of the source code, even though third parties are not

+compelled to copy the source along with the object code.

+

+  4. You may not copy, modify, sublicense, or distribute the Program

+except as expressly provided under this License.  Any attempt

+otherwise to copy, modify, sublicense or distribute the Program is

+void, and will automatically terminate your rights under this License.

+However, parties who have received copies, or rights, from you under

+this License will not have their licenses terminated so long as such

+parties remain in full compliance.

+

+  5. You are not required to accept this License, since you have not

+signed it.  However, nothing else grants you permission to modify or

+distribute the Program or its derivative works.  These actions are

+prohibited by law if you do not accept this License.  Therefore, by

+modifying or distributing the Program (or any work based on the

+Program), you indicate your acceptance of this License to do so, and

+all its terms and conditions for copying, distributing or modifying

+the Program or works based on it.

+

+  6. Each time you redistribute the Program (or any work based on the

+Program), the recipient automatically receives a license from the

+original licensor to copy, distribute or modify the Program subject to

+these terms and conditions.  You may not impose any further

+restrictions on the recipients' exercise of the rights granted herein.

+You are not responsible for enforcing compliance by third parties to

+this License.

+

+  7. If, as a consequence of a court judgment or allegation of patent

+infringement or for any other reason (not limited to patent issues),

+conditions are imposed on you (whether by court order, agreement or

+otherwise) that contradict the conditions of this License, they do not

+excuse you from the conditions of this License.  If you cannot

+distribute so as to satisfy simultaneously your obligations under this

+License and any other pertinent obligations, then as a consequence you

+may not distribute the Program at all.  For example, if a patent

+license would not permit royalty-free redistribution of the Program by

+all those who receive copies directly or indirectly through you, then

+the only way you could satisfy both it and this License would be to

+refrain entirely from distribution of the Program.

+

+If any portion of this section is held invalid or unenforceable under

+any particular circumstance, the balance of the section is intended to

+apply and the section as a whole is intended to apply in other

+circumstances.

+

+It is not the purpose of this section to induce you to infringe any

+patents or other property right claims or to contest validity of any

+such claims; this section has the sole purpose of protecting the

+integrity of the free software distribution system, which is

+implemented by public license practices.  Many people have made

+generous contributions to the wide range of software distributed

+through that system in reliance on consistent application of that

+system; it is up to the author/donor to decide if he or she is willing

+to distribute software through any other system and a licensee cannot

+impose that choice.

+

+This section is intended to make thoroughly clear what is believed to

+be a consequence of the rest of this License.

+

+  8. If the distribution and/or use of the Program is restricted in

+certain countries either by patents or by copyrighted interfaces, the

+original copyright holder who places the Program under this License

+may add an explicit geographical distribution limitation excluding

+those countries, so that distribution is permitted only in or among

+countries not thus excluded.  In such case, this License incorporates

+the limitation as if written in the body of this License.

+

+  9. The Free Software Foundation may publish revised and/or new versions

+of the General Public License from time to time.  Such new versions will

+be similar in spirit to the present version, but may differ in detail to

+address new problems or concerns.

+

+Each version is given a distinguishing version number.  If the Program

+specifies a version number of this License which applies to it and "any

+later version", you have the option of following the terms and conditions

+either of that version or of any later version published by the Free

+Software Foundation.  If the Program does not specify a version number of

+this License, you may choose any version ever published by the Free Software

+Foundation.

+

+  10. If you wish to incorporate parts of the Program into other free

+programs whose distribution conditions are different, write to the author

+to ask for permission.  For software which is copyrighted by the Free

+Software Foundation, write to the Free Software Foundation; we sometimes

+make exceptions for this.  Our decision will be guided by the two goals

+of preserving the free status of all derivatives of our free software and

+of promoting the sharing and reuse of software generally.

+

+                            NO WARRANTY

+

+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY

+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN

+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES

+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED

+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF

+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS

+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE

+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,

+REPAIR OR CORRECTION.

+

+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING

+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR

+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,

+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING

+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED

+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY

+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER

+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE

+POSSIBILITY OF SUCH DAMAGES.

+

+                     END OF TERMS AND CONDITIONS

+

+        Appendix: How to Apply These Terms to Your New Programs

+

+  If you develop a new program, and you want it to be of the greatest

+possible use to the public, the best way to achieve this is to make it

+free software which everyone can redistribute and change under these terms.

+

+  To do so, attach the following notices to the program.  It is safest

+to attach them to the start of each source file to most effectively

+convey the exclusion of warranty; and each file should have at least

+the "copyright" line and a pointer to where the full notice is found.

+

+    <one line to give the program's name and a brief idea of what it does.>

+    Copyright (C) 19yy  <name of author>

+

+    This program is free software; you can redistribute it and/or modify

+    it under the terms of the GNU General Public License as published by

+    the Free Software Foundation; either version 2 of the License, or

+    (at your option) any later version.

+

+    This program is distributed in the hope that it will be useful,

+    but WITHOUT ANY WARRANTY; without even the implied warranty of

+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

+    GNU General Public License for more details.

+

+    You should have received a copy of the GNU General Public License

+    along with this program; if not, write to the Free Software

+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

+

+Also add information on how to contact you by electronic and paper mail.

+

+If the program is interactive, make it output a short notice like this

+when it starts in an interactive mode:

+

+    Gnomovision version 69, Copyright (C) 19yy name of author

+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.

+    This is free software, and you are welcome to redistribute it

+    under certain conditions; type `show c' for details.

+

+The hypothetical commands `show w' and `show c' should show the appropriate

+parts of the General Public License.  Of course, the commands you use may

+be called something other than `show w' and `show c'; they could even be

+mouse-clicks or menu items--whatever suits your program.

+

+You should also get your employer (if you work as a programmer) or your

+school, if any, to sign a "copyright disclaimer" for the program, if

+necessary.  Here is a sample; alter the names:

+

+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program

+  `Gnomovision' (which makes passes at compilers) written by James Hacker.

+

+  <signature of Ty Coon>, 1 April 1989

+  Ty Coon, President of Vice

+

+This General Public License does not permit incorporating your program into

+proprietary programs.  If your program is a subroutine library, you may

+consider it more useful to permit linking proprietary applications with the

+library.  If this is what you want to do, use the GNU Library General

+Public License instead of this License.

+

+

diff --git a/converter/pbm/pbmtoppa/Makefile b/converter/pbm/pbmtoppa/Makefile
new file mode 100644
index 00000000..c4be08b7
--- /dev/null
+++ b/converter/pbm/pbmtoppa/Makefile
@@ -0,0 +1,25 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/pbm/pbmtoppa
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+all: pbmtoppa
+
+BINARIES = pbmtoppa
+
+MERGEBINARIES = $(BINARIES)
+
+OBJECTS = pbmtoppa.o ppa.o pbm.o cutswath.o
+MERGE_OBJECTS = pbmtoppa.o2 ppa.o pbm.o cutswath.o
+
+include $(SRCDIR)/Makefile.common
+
+pbmtoppa: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
+	$(LD) $(LDFLAGS) -o pbmtoppa $(OBJECTS) \
+	  -lm $(shell $(LIBOPT) $(NETPBMLIB)) $(LDLIBS) \
+	  $(RPATH) $(LADD)
+
diff --git a/converter/pbm/pbmtoppa/README.Netpbm b/converter/pbm/pbmtoppa/README.Netpbm
new file mode 100644
index 00000000..46c781e2
--- /dev/null
+++ b/converter/pbm/pbmtoppa/README.Netpbm
@@ -0,0 +1,30 @@
+Pbmtoppa was integrated into the Netpbm package in May 2000 by Bryan
+Henderson.  He took it from Tim Norton's pbm2ppa-0.8.6 package dated
+October 1998.
+
+Tim licenses the subject package to the public as described in the
+LICENSE file.
+
+The difference between what's in Netpbm and what was distributed by 
+Tim is:
+
+  - Tim called it 'pbm2ppa' Netpbm calls it 'pbmtoppa', to fit Netpbm
+    naming conventions.
+
+  - Tim's package included the program Pbmtpg, but the Netpbm directory
+    doesn't include that.  The program was integrated separately into
+    Netpbm as Pbmpage.
+
+  - Tim's package generated 3 different versions of Pbmtoppa, one for
+    each of the 720, 820 or 1000 printer models.  (They only differed
+    in their default parameters).  The netpbm version has only one
+    Pbmtoppa, and the (existing) -v option selects defaults for the 
+    specified printer model.
+
+  - Tim didn't have a man page.  His package had several other
+    documentation files, though, which are not in the Netpbm package
+    because the information is either specific to Tim's packaging or
+    the information in in the Netpbm man page.
+
+  - Jozsef Marak's extension to handle draft (300 dpi) printing is 
+    included.
diff --git a/converter/pbm/pbmtoppa/README.REDHAT b/converter/pbm/pbmtoppa/README.REDHAT
new file mode 100644
index 00000000..3586aea2
--- /dev/null
+++ b/converter/pbm/pbmtoppa/README.REDHAT
@@ -0,0 +1,29 @@
+RedHat users may find the following tip from Panayotis Vryonis <vrypan@hol.gr>
+helpful!
+
+Here is a tip to intergrate HP720C support in RedHat's printtool:
+
+Install pbm2ppa. Copy pbm2ppa to /usr/bin.
+Edit "printerdb" (in my system it is found in
+/usr/lib/rhs/rhs-printfilters )
+and append the following lines:
+----------------------Cut here
+-------------------------------------------
+StartEntry: DeskJet720C
+  GSDriver: pbm
+  Description: {HP DeskJet 720C}
+  About: { \
+           This driver supports the HP DeskJet 720C inkjet printer. \
+           It does does not support color printing. \
+           IMPORTANT! Insert \
+                "- | pbm2ppa -" \
+           in the "Extra GS Otions" field.\
+         }
+  Resolution: {600} {600} {}
+EndEntry
+--------------------------------------------------------------------------
+
+Now you can add an HP720C printer just like any other, using printtool.
+
+[Author's Note: The same should work for the 820 and 1000, but it hasn't
+been tested.  Also, use the pbmraw GSDriver if you have it; it's faster. ]
diff --git a/converter/pbm/pbmtoppa/cutswath.c b/converter/pbm/pbmtoppa/cutswath.c
new file mode 100644
index 00000000..0d44ce45
--- /dev/null
+++ b/converter/pbm/pbmtoppa/cutswath.c
@@ -0,0 +1,360 @@
+/* cutswath.c
+ * functions to cut a swath of a PBM file for PPA printers
+ * Copyright (c) 1998 Tim Norman.  See LICENSE for details.
+ * 3-15-98
+ *
+ * Mar 15, 1998  Jim Peterson  <jspeter@birch.ee.vt.edu>
+ *
+ *     Structured to accommodate both the HP820/1000, and HP720 series.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppa.h"
+#include "ppapbm.h"
+#include "cutswath.h"
+
+extern int Width;
+extern int Height;
+extern int Pwidth;
+
+/* sweep_data->direction must be set already */
+/* Upon successful completion, sweep_data->image_data and
+   sweep_data->nozzle_data have been set to pointers which this routine
+   malloc()'d. */
+/* Upon successful completion, all members of *sweep_data have been set
+   except direction, vertical_pos, and next. */
+/* Returns: 0 if unsuccessful
+            1 if successful, but with non-printing result (end of page)
+            2 if successful, with printing result */
+int 
+cut_pbm_swath(pbm_stat* pbm,ppa_stat* prn,int maxlines,ppa_sweep_data* sweep_data)
+{
+  unsigned char *data, *ppa, *place, *maxplace;
+  int p_width, width8, p_width8;
+  int i, j, left, right, got_nonblank, numlines;
+  int horzpos, hp2;
+  int shift;
+  ppa_nozzle_data nozzles[2];
+
+  /* shift = 6 if DPI==300  */
+  /* shift = 12 if DPI==600 */ 
+  shift = ( prn->DPI == 300 ? 6:12 ) ;
+  
+  /* safeguard against the user freeing these */
+  sweep_data->image_data=NULL;
+  sweep_data->nozzle_data=NULL;
+
+  /* read the data from the input file */
+  width8 = (pbm->width + 7) / 8;
+ 
+/* 
+  fprintf(stderr,"cutswath(): width=%u\n",pbm->width);
+  fprintf(stderr,"cutswath(): height=%u\n",pbm->height);
+*/
+
+  if ((data=malloc(width8*maxlines)) == NULL)
+  {
+    fprintf(stderr,"cutswath(): could not malloc data storage\n");
+    return 0;
+  }
+
+  /* ignore lines that are above the upper margin */
+  while(pbm->current_line < prn->top_margin)
+    if(!pbm_readline(pbm,data))
+    {
+      fprintf(stderr,"cutswath(): A-could not read top margin\n");
+      free(data);
+      return 0;
+    }
+
+  /* eat all lines that are below the lower margin */
+  if(pbm->current_line >= Height - prn->bottom_margin)
+  {
+    while(pbm->current_line < pbm->height)
+      if(!pbm_readline(pbm,data))
+      {
+	fprintf(stderr,"cutswath(): could not clear bottom margin\n");
+	free(data);
+	return 0;
+      }
+    free(data);
+    return 1;
+  }
+
+  left = Pwidth-prn->right_margin/8;
+  right = prn->left_margin/8;
+
+  /* eat all beginning blank lines and then up to maxlines or lower margin */
+  got_nonblank=numlines=0;
+  while( (pbm->current_line < Height-prn->bottom_margin) &&
+	 (numlines < maxlines) )
+  {
+    if(!pbm_readline(pbm,data+width8*numlines))
+    {
+      fprintf(stderr,"cutswath(): B-could not read next line\n");
+      free(data);
+      return 0;
+    }
+    if(!got_nonblank)
+      for(j=prn->left_margin/8; j<left; j++)
+	if(data[j])
+	{
+	  left = j;
+	  got_nonblank=1;
+	  break;
+	}
+    if(got_nonblank)
+      {
+	int newleft = left, newright = right;
+
+	/* find left-most nonblank */
+	for (i = prn->left_margin/8; i < left; i++)
+	  if (data[width8*numlines+i])
+	    {
+	      newleft = i;
+	      break;
+	    }
+	/* find right-most nonblank */
+	for (i = Pwidth-prn->right_margin/8-1; i >= right; i--)
+	  if (data[width8*numlines+i])
+	    {
+	      newright = i;
+	      break;
+	    }
+	numlines++;
+
+	if (newright < newleft)
+	  {
+	    fprintf (stderr, "Ack! newleft=%d, newright=%d, left=%d, right=%d\n",
+		     newleft, newright, left, right);
+	    free (data);
+	    return 0;
+	  }
+
+	/* if the next line might push us over the buffer size, stop here! */
+	/* ignore this test for the 720 right now.  Will add better */
+	/* size-guessing for compressed data in the near future! */
+	if (numlines % 2 == 1 && prn->version != HP720)
+	  {
+	    int l = newleft, r = newright, w;
+	    
+	    l--;
+	    r+=2;
+	    l*=8;
+	    r*=8;
+	    w = r-l;
+	    w = (w+7)/8;
+	    
+	    if ((w+2*shift)*numlines > prn->bufsize)
+	      {
+		numlines--;
+		pbm_unreadline (pbm, data+width8*numlines);
+		break;
+	      }
+	    else
+	      {
+		left = newleft;
+		right = newright;
+	      }
+	  }
+	else
+	  {
+	    left = newleft;
+	    right = newright;
+	  }
+      }
+  }
+
+  if(!got_nonblank)
+  {
+    /* eat all lines that are below the lower margin */
+    if(pbm->current_line >= Height - prn->bottom_margin)
+    {
+      while(pbm->current_line < pbm->height)
+	if(!pbm_readline(pbm,data))
+	{
+	  fprintf(stderr,"cutswath(): could not clear bottom margin\n");
+	  free(data);
+	  return 0;
+	}
+      free(data);
+      return 1;
+    }
+    free(data);
+    return 0; /* error, since didn't get to lower margin, yet blank */
+  }
+
+  /* make sure numlines is even and >= 2 (b/c we have to pass the printer 
+     HALF of the number of pins used */
+  if (numlines == 1)
+    {
+      /* there's no way that we only have 1 line and not enough memory, so
+	 we're safe to increase numlines here.  Also, the bottom margin should
+	 be > 0 so we have some lines to read */
+      if(!pbm_readline(pbm,data+width8*numlines))
+	{
+	  fprintf(stderr,"cutswath(): C-could not read next line\n");
+	  free(data);
+	  return 0;
+	}
+      numlines++;
+    }
+  if (numlines % 2 == 1)
+    {
+      /* decrease instead of increasing so we don't max out the buffer */
+      numlines--;
+      pbm_unreadline (pbm, data+width8*numlines);
+    }
+
+  /* calculate vertical position */
+  sweep_data->vertical_pos = pbm->current_line;
+
+  /* change sweep params */
+  left--;
+  right+=2;
+  left *= 8;
+  right *= 8;
+
+  /* construct the sweep data */
+  p_width = right - left;
+  p_width8 = (p_width + 7) / 8;
+
+  if ((ppa = malloc ((p_width8+2*shift) * numlines)) == NULL)
+    {
+      fprintf(stderr,"cutswath(): could not malloc ppa storage\n");
+      free (data);
+      return 0;
+    }
+
+  place = ppa;
+
+  /* place 0's in the first 12 columns */
+  memset (place, 0, numlines/2 * shift);
+  place += numlines/2 * shift;
+
+
+  if(sweep_data->direction == right_to_left)  /* right-to-left */
+  {
+    for (i = p_width8+shift-1; i >= 0; i--)
+    {
+      if (i >= shift)
+      {
+	for (j = 0; j < numlines/2; j++)
+	  *place++ = data[j*2*width8 + i + left/8-shift];
+      }
+      else
+      {
+	memset (place, 0, numlines/2);
+	place += numlines/2;
+      }
+
+      if (i < p_width8)
+      {
+	for (j = 0; j < numlines/2; j++)
+	  *place++ = data[(j*2+1)*width8 + i + left/8];
+      }
+      else
+      {
+	memset (place, 0, numlines/2);
+	place += numlines/2;
+      }
+    }
+  }
+  else /* sweep_data->direction == left_to_right */
+  {
+    for (i = 0; i < p_width8+shift; i++)
+    {
+      if (i < p_width8)
+      {
+	for (j = 0; j < numlines/2; j++)
+	  *place++ = data[(j*2+1)*width8 + i + left/8];
+      }
+      else
+      {
+	memset (place, 0, numlines/2);
+	place += numlines/2;
+      }
+
+      if (i >= shift)
+      {
+	for (j = 0; j < numlines/2; j++)
+	  *place++ = data[j*2*width8 + i + left/8 - shift];
+      }
+      else
+      {
+	memset (place, 0, numlines/2);
+	place += numlines/2;
+      }
+    }
+  }
+
+  /* done with data */
+  free(data);
+
+  /* place 0's in the last 12 columns */
+  memset (place, 0, numlines/2 * shift);
+  place += numlines/2 * shift;
+  maxplace = place;
+
+  /* create sweep data */
+  sweep_data->image_data = ppa;
+  sweep_data->data_size = maxplace-ppa;
+  sweep_data->in_color = False;
+
+  /*
+  horzpos = left*600/prn->DPI + (sweep_data->direction==left_to_right ? 0*600/prn->DPI : 0);
+  */
+  horzpos = left * 600/prn->DPI;
+
+  hp2 = horzpos + ( p_width8 + 2*shift )*8 * 600/prn->DPI;
+  
+ 
+  sweep_data->left_margin = horzpos;
+  sweep_data->right_margin = hp2 + prn->marg_diff;
+
+  
+  for (i = 0; i < 2; i++)
+  {
+    nozzles[i].DPI = prn->DPI;
+        
+    nozzles[i].pins_used_d2 = numlines/2;
+    nozzles[i].unused_pins_p1 = 301-numlines;
+    nozzles[i].first_pin = 1;
+    if (i == 0)
+    {
+      nozzles[i].left_margin = horzpos + prn->marg_diff;
+      nozzles[i].right_margin = hp2 + prn->marg_diff;
+      if(sweep_data->direction == right_to_left)
+       /* 0 */
+	nozzles[i].nozzle_delay=prn->right_to_left_delay[0];
+      else
+       /* 6 */
+	nozzles[i].nozzle_delay=prn->left_to_right_delay[0];
+    }
+    else
+    {
+      nozzles[i].left_margin = horzpos;
+      nozzles[i].right_margin = hp2;
+      if(sweep_data->direction == right_to_left)
+       /* 2 */
+	nozzles[i].nozzle_delay=prn->right_to_left_delay[1];
+      else
+       /* 0 */
+	nozzles[i].nozzle_delay=prn->left_to_right_delay[1];
+
+    }
+  }
+
+  sweep_data->nozzle_data_size = 2;
+  sweep_data->nozzle_data = malloc(sizeof(nozzles));
+  if(sweep_data->nozzle_data == NULL)
+    return 0;
+  memcpy(sweep_data->nozzle_data,nozzles,sizeof(nozzles));
+
+  return 2;
+}
+
+
diff --git a/converter/pbm/pbmtoppa/cutswath.h b/converter/pbm/pbmtoppa/cutswath.h
new file mode 100644
index 00000000..430558de
--- /dev/null
+++ b/converter/pbm/pbmtoppa/cutswath.h
@@ -0,0 +1,4 @@
+int 
+cut_pbm_swath(pbm_stat* pbm,ppa_stat* prn,int maxlines,
+              ppa_sweep_data* sweep_data);
+
diff --git a/converter/pbm/pbmtoppa/defaults.h b/converter/pbm/pbmtoppa/defaults.h
new file mode 100644
index 00000000..481b9585
--- /dev/null
+++ b/converter/pbm/pbmtoppa/defaults.h
@@ -0,0 +1,65 @@
+/* defaults.h
+ * Default printer values.  Edit these and recompile if so desired.
+ * [Note: a /etc/pbm2ppa.conf file will override these]
+ */
+#ifndef _DEFAULTS_H
+#define _DEFAULTS_H
+
+/* Refer to CALIBRATION file about these settings */
+
+#define HP1000_PRINTER        ( HP1000 )
+
+#define HP1000_MARG_DIFF      (  0x62 )
+#define HP1000_BUFSIZE        ( 100*1024 )
+
+#define HP1000_X_OFFSET       (   100 )
+#define HP1000_Y_OFFSET       (  -650 )
+
+#define HP1000_TOP_MARGIN     (   150 )
+#define HP1000_LEFT_MARGIN    (   150 )
+#define HP1000_RIGHT_MARGIN   (   150 )
+#define HP1000_BOTTOM_MARGIN  (   150 )
+
+
+#define HP720_PRINTER        ( HP720 )
+
+#define HP720_MARG_DIFF      (     2 )
+#define HP720_BUFSIZE        ( 200*1024 )
+
+#define HP720_X_OFFSET       (   169 )
+#define HP720_Y_OFFSET       (  -569 )
+
+#define HP720_TOP_MARGIN     (   150 )
+#define HP720_LEFT_MARGIN    (   150 )
+#define HP720_RIGHT_MARGIN   (   150 )
+#define HP720_BOTTOM_MARGIN  (   150 )
+
+
+#define HP820_PRINTER        ( HP820 )
+
+#define HP820_MARG_DIFF      (  0x62 )
+#define HP820_BUFSIZE        ( 100*1024 )
+
+#define HP820_X_OFFSET       (    75 )
+#define HP820_Y_OFFSET       (  -500 )
+
+#define HP820_TOP_MARGIN     (    80 )
+#define HP820_LEFT_MARGIN    (    80 )
+#define HP820_RIGHT_MARGIN   (    80 )
+#define HP820_BOTTOM_MARGIN  (   150 )
+
+
+
+#define DEFAULT_PRINTER        HP1000_PRINTER
+
+#define DEFAULT_X_OFFSET       HP1000_X_OFFSET
+#define DEFAULT_Y_OFFSET       HP1000_Y_OFFSET
+
+#define DEFAULT_TOP_MARGIN     HP1000_TOP_MARGIN
+#define DEFAULT_LEFT_MARGIN    HP1000_LEFT_MARGIN
+#define DEFAULT_RIGHT_MARGIN   HP1000_RIGHT_MARGIN
+#define DEFAULT_BOTTOM_MARGIN  HP1000_BOTTOM_MARGIN
+
+#define DEFAULT_DPI ( 600 )
+
+#endif
diff --git a/converter/pbm/pbmtoppa/pbm.c b/converter/pbm/pbmtoppa/pbm.c
new file mode 100644
index 00000000..5c9798f2
--- /dev/null
+++ b/converter/pbm/pbmtoppa/pbm.c
@@ -0,0 +1,135 @@
+/* pbm.c
+ * code for reading the header of an ASCII PBM file
+ * Copyright (c) 1998 Tim Norman.  See LICENSE for details
+ * 2-25-98
+ *
+ * Mar 18, 1998  Jim Peterson  <jspeter@birch.ee.vt.edu>
+ *
+ *     Restructured to encapsulate more of the PBM handling.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ppapbm.h"
+
+int make_pbm_stat(pbm_stat* pbm,FILE* fptr)
+{
+  char line[1024];
+
+  pbm->fptr=fptr;
+  pbm->version=none;
+  pbm->current_line=0;
+  pbm->unread = 0;
+
+  if (fgets (line, 1024, fptr) == NULL)
+    return 0;
+  line[strlen(line)-1] = 0;
+
+  if(!strcmp(line,"P1")) pbm->version=P1;
+  if(!strcmp(line,"P4")) pbm->version=P4;
+  if(pbm->version == none)
+  {
+    fprintf(stderr,"pbm_readheader(): unknown PBM magic '%s'\n",line);
+    return 0;
+  }
+
+  do
+    if (fgets (line, 1024, fptr) == NULL)
+      return 0;
+  while (line[0] == '#');
+
+  if (2 != sscanf (line, "%d %d", &pbm->width, &pbm->height))
+    return 0;
+
+  return 1;
+}
+
+static int getbytes(FILE *fptr,int width,unsigned char* data)
+{
+  unsigned char mask,acc,*place;
+  int num;
+
+  if(!width) return 0;
+  for(mask=0x80, acc=0, num=0, place=data; num<width; )
+  {
+    switch(getc(fptr))
+    {
+    case EOF:      
+      return 0;
+    case '1':
+      acc|=mask;
+      /* fall through */
+    case '0':
+      mask>>=1;
+      num++;
+      if(!mask) /* if(num%8 == 0) */
+      {
+	*place++ = acc;
+	acc=0;
+	mask=0x80;
+      }
+    }
+  }
+  if(width%8)
+    *place=acc;
+  return 1;
+}
+
+/* Reads a single line into data which must be at least (pbm->width+7)/8
+   bytes of storage */
+int pbm_readline(pbm_stat* pbm,unsigned char* data)
+{
+  int tmp,tmp2;
+
+  if(pbm->current_line >= pbm->height) return 0;
+
+  if (pbm->unread)
+    {
+      memcpy (data, pbm->revdata, (pbm->width+7)/8);
+      pbm->current_line++;
+      pbm->unread = 0;
+      free (pbm->revdata);
+      return 1;
+    }
+
+  switch(pbm->version)
+  {
+  case P1:
+    if(getbytes(pbm->fptr,pbm->width,data))
+    {
+      pbm->current_line++;
+      return 1;
+    }
+    return 0;
+
+  case P4:
+    tmp=(pbm->width+7)/8;
+    tmp2=fread(data,1,tmp,pbm->fptr);
+    if(tmp2 == tmp)
+    {
+      pbm->current_line++;
+      return 1;
+    }
+    fprintf(stderr,"pbm_readline(): error reading line data (%d)\n",tmp2);
+    return 0;
+
+  default:
+    fprintf(stderr,"pbm_readline(): unknown PBM version\n");
+    return 0;
+  }
+}
+
+/* push a line back into the buffer; we read too much! */
+void pbm_unreadline (pbm_stat *pbm, void *data)
+{
+  /* can only store one line in the unread buffer */
+  if (pbm->unread)
+    return;
+
+  pbm->unread = 1;
+  pbm->revdata = malloc ((pbm->width+7)/8);
+  memcpy (pbm->revdata, data, (pbm->width+7)/8);
+  pbm->current_line--;
+}
diff --git a/converter/pbm/pbmtoppa/pbmtoppa.c b/converter/pbm/pbmtoppa/pbmtoppa.c
new file mode 100644
index 00000000..85a98529
--- /dev/null
+++ b/converter/pbm/pbmtoppa/pbmtoppa.c
@@ -0,0 +1,449 @@
+/* pbmtoppa.c
+ * program to print a 600 dpi PBM file on the HP DJ820Cse or the HP720 series.
+ * Copyright (c) 1998 Tim Norman.  See LICENSE for details
+ * 2-24-98
+ */
+
+#define _BSD_SOURCE
+    /* This makes sure strcasecmp() is in string.h */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "pbm.h"
+#include "ppa.h"
+#include "ppapbm.h"
+#include "cutswath.h"
+
+#include "defaults.h"
+
+/* Paper sizes in 600ths of an inch. */
+
+/* US is 8.5 in by 11 in */
+
+#define USWIDTH  (5100)
+#define USHEIGHT (6600)
+
+/* A4 is 210 mm by 297 mm == 8.27 in by 11.69 in */
+
+#define A4WIDTH  (4960)
+#define A4HEIGHT (7016)
+
+int Width;      /* width and height in 600ths of an inch */
+int Height;
+int Pwidth;     /* width in bytes */
+
+#define MAX_LINES 300
+
+ppa_stat printer;
+
+static int 
+print_pbm(FILE * const in) {
+
+    char line[1024];
+    pbm_stat pbm;
+    int done_page, numpages = 0;
+    ppa_sweep_data sweeps[2];
+    int current_sweep, previous_sweep;
+
+    ppa_init_job(&printer);
+
+    while(make_pbm_stat(&pbm, in)) {
+        if (pbm.width != Width || pbm.height != Height) 
+            pm_error("print_pbm(): Input image is not the size "
+                    "of a page for Page %d.  "
+                    "The input is %dW x %dH, "
+                     "while a page is %dW x %dH pixels.\n"
+                    "Page size is controlled by options and the configuration "
+                    "file.",
+                     numpages+1, pbm.width, pbm.height, Width, Height);
+
+        ppa_init_page(&printer);
+        ppa_load_page(&printer);
+
+        sweeps[0].direction = right_to_left;
+        sweeps[0].next=&sweeps[1];
+        sweeps[1].direction = left_to_right;
+        sweeps[1].next=&sweeps[0];
+
+        current_sweep=0;
+        previous_sweep=-1;
+
+        done_page=0;
+        while(!done_page) {
+            int rc;
+            rc = cut_pbm_swath(&pbm, &printer, MAX_LINES,
+                               &sweeps[current_sweep]);
+            switch(rc) {
+            case 0:
+                pm_error("print_pbm(): cut_pbm_swath() failed.");
+                break;
+            case 1:
+                done_page=1;
+                break;
+            case 2:
+                if (previous_sweep >= 0) {
+                    ppa_print_sweep(&printer, &sweeps[previous_sweep]);
+                    free(sweeps[previous_sweep].image_data);
+                    free(sweeps[previous_sweep].nozzle_data);
+                }
+                previous_sweep=current_sweep;
+                current_sweep= current_sweep==0 ? 1 : 0;
+                break;
+            default:
+                pm_error("print_pbm(): unknown return code from "
+                         "cut_pbm_swath()");
+            }
+        }
+        if (previous_sweep >= 0) {
+            sweeps[previous_sweep].next=NULL;
+            ppa_print_sweep(&printer,&sweeps[previous_sweep]);
+        }
+
+        free(sweeps[0].image_data);
+        free(sweeps[0].nozzle_data);
+        free(sweeps[1].image_data);
+        free(sweeps[1].nozzle_data);
+
+        ppa_eject_page(&printer);
+
+        /* eat any remaining whitespace */
+        if(pbm.version==P1)
+            fgets (line, 1024, in);
+
+        ++numpages;
+    }
+
+    if (numpages == 0)
+        pm_error("No pages printed!");
+
+    ppa_end_print(&printer);
+
+    fclose (pbm.fptr);
+    fclose (printer.fptr);
+
+    return 0;
+}
+
+
+
+static void 
+set_printer_specific_defaults()
+{
+    switch(printer.version)
+    {
+    case HP720:
+        printer.marg_diff     = HP720_MARG_DIFF;
+        printer.bufsize       = HP720_BUFSIZE;
+
+        printer.x_offset      = HP720_X_OFFSET;
+        printer.y_offset      = HP720_Y_OFFSET;
+        printer.top_margin    = HP720_TOP_MARGIN;
+        printer.left_margin   = HP720_LEFT_MARGIN;
+        printer.right_margin  = HP720_RIGHT_MARGIN;
+        printer.bottom_margin = HP720_BOTTOM_MARGIN;
+        break;
+    case HP820:
+        printer.marg_diff     = HP820_MARG_DIFF;
+        printer.bufsize       = HP820_BUFSIZE;
+
+        printer.x_offset      = HP820_X_OFFSET;
+        printer.y_offset      = HP820_Y_OFFSET;
+        printer.top_margin    = HP820_TOP_MARGIN;
+        printer.left_margin   = HP820_LEFT_MARGIN;
+        printer.right_margin  = HP820_RIGHT_MARGIN;
+        printer.bottom_margin = HP820_BOTTOM_MARGIN;
+        break;
+    case HP1000:
+        printer.marg_diff     = HP1000_MARG_DIFF;
+        printer.bufsize       = HP1000_BUFSIZE;
+
+        printer.x_offset      = HP1000_X_OFFSET;
+        printer.y_offset      = HP1000_Y_OFFSET;
+        printer.top_margin    = HP1000_TOP_MARGIN;
+        printer.left_margin   = HP1000_LEFT_MARGIN;
+        printer.right_margin  = HP1000_RIGHT_MARGIN;
+        printer.bottom_margin = HP1000_BOTTOM_MARGIN;
+        break;
+    default:
+        pm_error("set_printer_defaults(): unknown printer version");
+    }
+}
+
+
+
+static void 
+show_usage(const char* const prog)
+{
+    printf("usage: %s [ options ] [ <infile> [ <outfile> ] ]\n\n",prog);
+    printf("  Prints a pbm- or pbmraw-format <infile> to HP720/820/1000-format <outfile>.\n\n");
+    printf("    -v <version>    printer version (720, 820, or 1000)\n");
+    printf("    -x <xoff>       vertical offset adjustment in 1\"/600\n");
+    printf("    -y <yoff>       horizontal offset adjustment in 1\"/600\n");
+    printf("    -t <topmarg>    top margin in 1\"/600    (default: 150 = 0.25\")\n");
+    printf("    -l <leftmarg>   left margin in 1\"/600   (default: 150 = 0.25\")\n");
+    printf("    -r <rightmarg>  right margin in 1\"/600  (default: 150 = 0.25\")\n");
+    printf("    -b <botmarg>    bottom margin in 1\"/600 (default: 150 = 0.25\")\n");
+    printf("    -s <paper>      paper size (us, a4, default: us)\n");
+    printf("    -f <cfgfile>    read <cfgfile> as parameters\n\n");
+    printf("  The -x and -y options accumulate.  The -v option resets the horizontal and\n");
+    printf("  vertical adjustments to an internal default.  <infile> and <outfile> default\n");
+    printf("  to stdin and stdout.  '-' is a synonym for stdin and stdout.\n\n");
+    printf("  Configuration files specified with the '-f' parameter have the following\n  format:\n\n");
+    printf("    # Comment\n");
+    printf("    <key1> <value1>\n");
+    printf("    <key2> <value2>\n");
+    printf("    [etc.]\n\n");
+    printf("  Valid keys are 'version', 'xoffset', 'yoffset', 'topmargin', 'leftmargin',\n");
+    printf("  'rightmargin', 'bottommargin', 'papersize', or any non-null truncated\n");
+    printf("  version of these words.  Valid values are the same as with the corresponding\n");
+    printf("  command-line parameters.  Parameters in the configuration file act as though\n");
+    printf("  the corresponding parameters were substituted, in order, for the '-f'\n");
+    printf("  parameter which specified the file.\n\n");
+    printf("  The file /etc/pbmtoppa.conf, if it exists, is processed as a configuration\n");
+    printf("  file before any command-line parameters are processed.\n\n");
+}
+
+
+
+static void 
+parm_version(char* arg)
+{
+    if(!strcasecmp(arg,"hp720") || !strcmp(arg,"720"))
+        printer.version=HP720;
+    else if(!strcasecmp(arg,"hp820") || !strcmp(arg,"820"))
+        printer.version=HP820;
+    else if(!strcasecmp(arg,"hp1000") || !strcmp(arg,"1000"))
+        printer.version=HP1000;
+    else
+        pm_error("parm_version(): unknown printer version '%s'",arg);
+    set_printer_specific_defaults();
+}
+
+
+
+static void 
+parm_iversion(int arg)
+{
+    switch(arg)
+    {
+    case 720:
+        printer.version=HP720;
+        break;
+    case 820:
+        printer.version=HP820;
+        break;
+    case 1000:
+        printer.version=HP1000;
+        break;
+    default:
+        pm_error("parm_iversion(): unknown printer version '%d'", arg);
+    }
+    set_printer_specific_defaults();
+}
+
+
+
+static void 
+dump_config()
+{
+    printf("version:  ");
+    switch(printer.version)
+    {
+    case HP710:  printf("HP710\n");  break;
+    case HP720:  printf("HP720\n");  break;
+    case HP820:  printf("HP820\n");  break;
+    case HP1000: printf("HP1000\n"); break;
+    }
+    printf("x-offset: %d\ny-offset: %d\nmargins:\n top:    %d\n"
+           " left:   %d\n right:  %d\n bottom: %d\n",printer.x_offset,
+           printer.y_offset,printer.top_margin,printer.left_margin,
+           printer.right_margin,printer.bottom_margin);
+    exit(0);
+}
+
+
+
+static void 
+read_config_file(const char* const fname)
+{
+    FILE* cfgfile=fopen(fname,"r");
+    char line[1024],key[14],buf[10];
+    int len,value,lineno=1;
+
+    if(!cfgfile)
+        pm_error("read_config_file(): couldn't open file '%s'", fname);
+
+    while(fgets(line,1024,cfgfile))
+    {
+        if(strchr(line,'#'))
+            *strchr(line,'#')=0;
+        switch(sscanf(line,"%13s%9s",key,buf))
+        {
+        case 2:
+            value=atoi(buf);
+            len=strlen(key);
+            if(!strncmp(key,"version",len))
+                parm_iversion(value);
+            else if(!strncmp(key,"xoffset",len))
+                printer.x_offset=value;
+            else if(!strncmp(key,"yoffset",len))
+                printer.y_offset=value;
+            else if(!strncmp(key,"topmargin",len))
+                printer.top_margin=value;
+            else if(!strncmp(key,"leftmargin",len))
+                printer.left_margin=value;
+            else if(!strncmp(key,"rightmargin",len))
+                printer.right_margin=value;
+            else if(!strncmp(key,"bottommargin",len))
+                printer.bottom_margin=value;
+            else if(!strncmp(key,"papersize",len))
+            {
+                if(!strcmp(buf,"us"))
+                {
+                    Width = USWIDTH;
+                    Height = USHEIGHT;
+                }
+                else if(!strcmp(buf,"a4"))
+                {
+                    Width = A4WIDTH;
+                    Height = A4HEIGHT;
+                }
+                else
+                    pm_error("read_config_file(): unknown paper size %s", buf);
+            }
+            else if(!strcmp(key,"dump"))
+                dump_config();
+            else 
+                pm_error("read_config_file(): unrecognized parameter '%s' "
+                         "(line %d)", key, lineno);
+        case EOF:
+        case 0: 
+            break;
+        default:
+            pm_error("read_config_file(): error parsing config file "
+                     "(line %d)", lineno);
+        }
+        lineno++;
+    }
+
+    if(feof(cfgfile))
+    {
+        fclose(cfgfile);
+        return;
+    }
+
+    pm_error("read_config_file(): error parsing config file");
+}
+
+
+
+const char* const defaultcfgfile="/etc/pbmtoppa.conf";
+
+
+
+int 
+main(int argc, char *argv[]) {
+
+    int argn;
+    int got_in=0, got_out=0, do_continue=1;
+    FILE *in=stdin, *out=stdout;
+    struct stat tmpstat;
+
+    pbm_init(&argc, argv);
+
+    printer.version       = DEFAULT_PRINTER;
+    printer.x_offset      = DEFAULT_X_OFFSET;
+    printer.y_offset      = DEFAULT_Y_OFFSET;
+    printer.top_margin    = DEFAULT_TOP_MARGIN;
+    printer.left_margin   = DEFAULT_LEFT_MARGIN;
+    printer.right_margin  = DEFAULT_RIGHT_MARGIN;
+    printer.bottom_margin = DEFAULT_BOTTOM_MARGIN;
+    printer.DPI           = DEFAULT_DPI;
+    Width = USWIDTH;
+    Height = USHEIGHT;
+    set_printer_specific_defaults();
+
+    if(!stat(defaultcfgfile,&tmpstat))
+        read_config_file(defaultcfgfile);
+
+    for(argn=1; argn<argc; argn++)
+    {
+        if(!strcmp(argv[argn],"-h"))
+        {
+            show_usage(*argv);
+            return 0;
+        }
+        else if(!strcmp(argv[argn],"-d"))
+            dump_config();
+        else if(argn+1<argc)
+        {
+            do_continue=1;
+            if(!strcmp(argv[argn],"-v"))
+                parm_version(argv[++argn]);
+            else if(!strcmp(argv[argn],"-x"))
+                printer.x_offset+=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-y"))
+                printer.y_offset+=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-t"))
+                printer.top_margin=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-l"))
+                printer.left_margin=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-r"))
+                printer.right_margin=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-b"))
+                printer.bottom_margin=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-d"))
+                printer.DPI=atoi(argv[++argn]);
+            else if(!strcmp(argv[argn],"-s"))
+            {
+                argn++;
+                if(!strcmp(argv[argn],"us"))
+                {
+                    Width = USWIDTH;
+                    Height = USHEIGHT;
+                }
+                else if(!strcmp(argv[argn],"a4"))
+                {
+                    Width = A4WIDTH;
+                    Height = A4HEIGHT;
+                }
+                else
+                    pm_error("unknown paper size %s",argv[argn]);
+            }
+            else if(!strcmp(argv[argn],"-f"))
+                read_config_file(argv[++argn]);
+            else do_continue=0;
+            if(do_continue) continue;
+        }
+
+        if(!got_in)
+        {
+            if (strcmp (argv[argn], "-") == 0)
+                in = stdin;
+            else if ((in = fopen (argv[argn], "rb")) == NULL)
+                pm_error("main(): couldn't open file '%s'", 
+                         argv[argn]);
+            got_in=1;
+        }
+        else if(!got_out)
+        {
+            if (strcmp (argv[argn], "-") == 0)
+                out = stdout;
+            else if ((out = fopen (argv[argn], "wb")) == NULL)
+                pm_error("main(): couldn't open file '%s'", 
+                         argv[argn]);
+            got_out=1;
+        }
+        else
+            pm_error("main(): unrecognized parameter '%s'", argv[argn]);
+    }
+
+    Pwidth=(Width+7)/8;
+    printer.fptr=out;
+
+    return print_pbm (in);
+}
+
diff --git a/converter/pbm/pbmtoppa/pbmtoppa.conf.hp1000 b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp1000
new file mode 100644
index 00000000..a3ba3260
--- /dev/null
+++ b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp1000
@@ -0,0 +1,18 @@
+# Sample configuration file for the HP720
+#
+# This file will be automatically read upon startup if it's placed in
+# /etc/pbm2ppa.conf
+#
+
+version  1000
+
+papersize	us
+
+xoff     100 # \ Adjust these for your printer.
+yoff    -650 # / (see CALIBRATE)
+
+# 1/4 inch margins all around (at 600 DPI)
+top      150
+bottom   150
+left     150
+right    150
diff --git a/converter/pbm/pbmtoppa/pbmtoppa.conf.hp720 b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp720
new file mode 100644
index 00000000..b8975564
--- /dev/null
+++ b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp720
@@ -0,0 +1,18 @@
+# Sample configuration file for the HP720
+#
+# This file will be automatically read upon startup if it's placed in
+# /etc/pbm2ppa.conf
+#
+
+version  720
+
+papersize	us
+
+xoff     169 # \ Adjust these for your printer.
+yoff    -569 # / (see CALIBRATE)
+
+# 1/4 inch margins all around (at 600 DPI)
+top      150
+bottom   150
+left     150
+right    150
diff --git a/converter/pbm/pbmtoppa/pbmtoppa.conf.hp820 b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp820
new file mode 100644
index 00000000..55a8cb7d
--- /dev/null
+++ b/converter/pbm/pbmtoppa/pbmtoppa.conf.hp820
@@ -0,0 +1,18 @@
+# Sample configuration file for the HP820
+#
+# This file will be automatically read upon startup if it's placed in
+# /etc/pbm2ppa.conf
+#
+
+version  820
+
+papersize	us
+
+xoff      75 # \ Adjust these for your printer.
+yoff    -500 # / (see CALIBRATE)
+
+# 1/4 inch margins all around (at 600 DPI)
+top       80
+bottom   150
+left      80
+right     80
diff --git a/converter/pbm/pbmtoppa/ppa.c b/converter/pbm/pbmtoppa/ppa.c
new file mode 100644
index 00000000..8363d927
--- /dev/null
+++ b/converter/pbm/pbmtoppa/ppa.c
@@ -0,0 +1,526 @@
+/* ppa.c
+ * functions to handle PPA communications
+ * Copyright (c) 1998 Tim Norman.  See LICENSE for details.
+ * 2-25-98
+ *
+ * Mar 3, 1998  Jim Peterson  <jspeter@birch.ee.vt.edu>
+ *
+ *     Restructured to accommodate both the HP820/1000, and HP720 series.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pm_config.h"
+  /* pm_config.h is necessary for __inline__ for those compilers that don't
+     define __inline__ themselves
+     */
+#include "ppa.h"
+
+/*
+  VLink packet structure:
+
+    Bytes  Description
+    --------------------------------------------
+      1    Packet-start marker (always '$')
+      1    Channel (0: image data, 1: commands/responses(*), 2: autostatus(*), 128: pacing(*))
+      2    Data length (N)
+      N    [remaining data (e.g., SCP or SCP2 packet when Channel=1)]
+
+  (*): responses, autostatus, and pacing are communicated from the printer to
+       the computer, and may be safely ignored.
+*/
+static void 
+vlink_put(FILE *fptr, int channel, int length, void *data)
+{
+  fputc ('$', fptr);
+  fputc (channel, fptr);
+  fputc (length>>8, fptr);     fputc (length&0xFF, fptr);
+  fwrite (data, length, 1, fptr);
+}
+
+/*
+  SCP packet structure:
+
+    Bytes  Description
+    --------------------------------------------
+      2    Command specifier
+      2    Command reference number
+      1    Priority
+      1    padding? (always zero)
+      2    Data length (N)
+      N    [remaining data]
+
+    ComSpec  ComRef     Command
+    -------------------------------
+       35       1     Initialize1
+      101       2     Initialize2
+       21       1     Initialize3
+       19       1     Handle Media
+       18       1     Print Sweep
+*/
+static void 
+scp_put(FILE *fptr, int comspec, int comref, int priority,
+	     int length, void *data)
+{
+  /* encapsulate the vlink_put call in here, to avoid a memcpy */
+  fputc ('$', fptr);
+  fputc (1, fptr);
+  fputc ((length+8)>>8, fptr);     fputc ((length+8)&0xFF, fptr);
+
+  fputc (comspec>>8, fptr);  fputc (comspec&0xFF, fptr);
+  fputc (comref>>8, fptr);   fputc (comref&0xFF, fptr);
+  fputc (priority, fptr);
+  fputc (0, fptr);
+  fputc (length>>8, fptr);   fputc (length&0xFF, fptr);
+
+  fwrite (data, length, 1, fptr);
+}
+
+
+/*
+  SCP2 packet structure:
+
+    Bytes  Description
+    --------------------------------------------
+      2    Command specifier
+      2    Packet length (N)
+      1    Priority
+      1    padding? (always zero)
+      2    Command reference number
+      4    Channel 0 buffer increment
+      4    version number? (always 00 02 00 00)
+     N-16  [remaining data]
+
+    ComSpec  ComRef     Command
+    -------------------------------
+     0x186      1     Initialize1
+     0x18f      2     Initialize2
+     0x183      1     Initialize3
+     0x181      1     Handle Media
+     0x180      1     Print Sweep
+*/
+static void 
+scp2_put(FILE *fptr,unsigned short comspec,unsigned short pkt_len_s16,
+	      unsigned char priority,unsigned short comref,unsigned data_len,
+	      void *data)
+{
+  /* encapsulate the vlink_put call in here, to avoid a memcpy */
+  fputc ('$', fptr);
+  fputc (1, fptr);
+  fputc ((pkt_len_s16+16)>>8, fptr);  fputc ((pkt_len_s16+16), fptr);
+
+  fputc (comspec>>8, fptr);  fputc (comspec, fptr);
+  fputc ((pkt_len_s16+16)>>8, fptr);  fputc ((pkt_len_s16+16), fptr);
+  fputc (priority, fptr);
+  fputc (0, fptr);
+  fputc (comref>>8, fptr);
+  fputc (comref, fptr);
+  fputc (data_len>>24, fptr);   fputc (data_len>>16, fptr);
+  fputc (data_len>>8, fptr);    fputc (data_len, fptr);
+  fputc (0, fptr);
+  fputc (2, fptr);
+  fputc (0, fptr);
+  fputc (0, fptr);
+
+  fwrite (data, pkt_len_s16, 1, fptr);
+}
+
+
+/*
+  SCP3 packet structure:
+
+    Bytes  Description
+    --------------------------------------------
+      2    Command specifier
+      2    Packet length (N)
+      1    Priority
+      1    padding? (always zero)
+      2    Command reference number
+      4    Channel 0 buffer increment
+      4    version number? (always 01 04 00 00)
+     N-16  [remaining data]
+
+    ComSpec  ComRef     Command
+    -------------------------------
+     0x186      1     Initialize1
+     0x18C     16     Initialize Printer name
+     0x1A1      1     Initialize4?
+     0x18f      2     Initialize2
+     0x183      1     Initialize3
+     0x181      1     Handle Media
+     0x180      1     Print Sweep
+*/
+static void 
+scp3_put(FILE *fptr,unsigned short comspec,unsigned short pkt_len_s16,
+	      unsigned char priority,unsigned short comref,unsigned data_len,
+	      void *data)
+{
+  /* encapsulate the vlink_put call in here, to avoid a memcpy */
+  fputc ('$', fptr);
+  fputc (1, fptr);
+  fputc ((pkt_len_s16+16)>>8, fptr);  fputc ((pkt_len_s16+16), fptr);
+
+  fputc (comspec>>8, fptr);  fputc (comspec, fptr);
+  fputc ((pkt_len_s16+16)>>8, fptr);  fputc ((pkt_len_s16+16), fptr);
+  fputc (priority, fptr);
+  fputc (0, fptr);
+  fputc (comref>>8, fptr);
+  fputc (comref, fptr);
+  fputc (data_len>>24, fptr);   fputc (data_len>>16, fptr);
+  fputc (data_len>>8, fptr);    fputc (data_len, fptr);
+  fputc (1, fptr);
+  fputc (4, fptr);
+  fputc (0, fptr);
+  fputc (0, fptr);
+
+  fwrite (data, pkt_len_s16, 1, fptr);
+}
+
+
+void ppa_init_job(ppa_stat* prn)
+{
+  unsigned char init1[8] = { 0x00, 0x00, 0x01, 0xf4, 0x01, 0x00, 0x00, 0x00 };
+  unsigned char init2[4] = { 0xde, 0xad, 0xbe, 0xef };
+  unsigned char init3[8] = { 0xde, 0xad, 0xbe, 0xef, 0x02, 0x00, 0x00, 0x00 };
+  unsigned char init4[60] = "!!TAZ            \x81*HP DeskJet 1000C Prin (Copy 2)*FILE!!\x00\x00\x00"; /* plus 0 terminator */
+  unsigned char init5[4] = { 0x01, 0x01, 0x00, 0x00 };
+
+  switch(prn->version)
+  {
+  case HP820:
+    scp_put (prn->fptr, 35, 1, 7, sizeof(init1), init1);
+    vlink_put (prn->fptr, 0, sizeof(init2), init2);
+    scp_put (prn->fptr, 101, 2, 7, sizeof(init3), init3);
+    break;
+  case HP720:
+    scp2_put (prn->fptr, 0x0186, sizeof(init1), 7, 1, 0, init1);
+    vlink_put(prn->fptr, 0, sizeof(init2), init2);
+    scp2_put (prn->fptr, 0x018f, sizeof(init3), 7, 2, 4, init3);
+    break;
+  case HP1000:
+    scp3_put (prn->fptr, 0x0186, sizeof(init1), 7, 16, 0, init1);
+    scp3_put (prn->fptr, 0x018C, sizeof(init4), 7, 1, 0, init4);
+    scp3_put (prn->fptr, 0x01A1, sizeof(init5), 7, 1, 0, init5);
+    vlink_put (prn->fptr, 0, sizeof(init2), init2);
+    scp3_put (prn->fptr, 0x018f, sizeof(init3), 7, 2, 4, init3);
+    break;
+  default:
+    fprintf(stderr,"ppa_init_job(): unknown printer verson\n");
+  }
+}
+
+void ppa_end_print(ppa_stat* prn)
+{
+  unsigned char pageA[4] = { 0x05, 0x01, 0x03, 0x84 };
+
+  if (prn->version == HP1000)
+    scp3_put (prn->fptr, 0x0181, sizeof(pageA), 7, 2, 0, pageA);
+}
+
+void ppa_init_page(ppa_stat* prn)
+{
+  unsigned char pageA[16] = {0x28, 0x2d, 0x00, 0x41, 0x29, 0x2e, 0x00, 0x42,
+			     0x29, 0x2e, 0x00, 0x42, 0x29, 0x2e, 0x00, 0x42 };
+  unsigned char pageB[16] = {0x28, 0x2d, 0x00, 0x41, 0x2d, 0x32, 0x00, 0x46,
+			     0x2d, 0x32, 0x00, 0x46, 0x2d, 0x32, 0x00, 0x46 };
+
+  switch(prn->version)
+  {
+  case HP820:
+    scp_put (prn->fptr, 21, 1, 5, sizeof(pageA), pageA);
+    break;
+  case HP720:
+    scp2_put (prn->fptr, 0x0183, sizeof(pageB), 5, 1, 0, pageB);
+    break;
+  case HP1000:
+    scp3_put (prn->fptr, 0x0183, sizeof(pageA), 5, 1, 0, pageA);
+    break;
+  default:
+    fprintf(stderr,"ppa_init_page(): unknown printer verson\n");
+  }
+}
+
+void ppa_load_page(ppa_stat* prn)
+{
+  unsigned char loadA[4] = {0x01, 0x01, 0x09, 0x60 };
+  unsigned char loadB[4] = {0x01, 0x01, 0x12, 0xc0 };
+  unsigned char loadC[4] = {0x01, 0x01, 0x07, 0x08 };
+
+  switch(prn->version)
+  {
+  case HP820:
+    scp_put (prn->fptr, 19, 1, 7, sizeof(loadA), loadA);
+    break;
+  case HP720:
+    scp2_put (prn->fptr, 0x0181, sizeof(loadB), 7, 1, 0, loadB);
+    break;
+  case HP1000:
+    scp3_put (prn->fptr, 0x0181, sizeof(loadC), 7, 1, 0, loadC);
+    break;
+  default:
+    fprintf(stderr,"ppa_load_page(): unknown printer verson\n");
+  }
+}
+
+void ppa_eject_page(ppa_stat* prn)
+{
+  unsigned char loadA[4] = {0x02, 0x01, 0x09, 0x60 };
+  unsigned char loadB[4] = {0x02, 0x01, 0x12, 0xc0 };
+  unsigned char loadC[4] = {0x02, 0x01, 0x07, 0x08 };
+
+  switch(prn->version)
+  {
+  case HP820:
+    scp_put (prn->fptr, 19, 1, 7, sizeof(loadA), loadA);
+    break;
+  case HP720:
+    scp2_put (prn->fptr, 0x0181, sizeof(loadB), 7, 1, 0, loadB);
+    break;
+  case HP1000:
+    scp3_put (prn->fptr, 0x0181, sizeof(loadC), 7, 1, 0, loadC);
+    break;
+  default:
+    fprintf(stderr,"ppa_eject_page(): unknown printer verson\n");
+  }
+}
+
+
+
+static int 
+compress(unsigned char *in, int num_lines_d2, int final_len, 
+             unsigned char *iout)
+{
+  unsigned char* out = iout;
+  int I,len=num_lines_d2;
+  for(I=0; I<final_len; I+=num_lines_d2, in+=num_lines_d2)
+  {
+    int i = 0;
+    while (i < len) {
+      /* Find the size of duplicate values */
+      int dup_len = 0;
+      while ((i + dup_len < len)
+	     && (in[i + dup_len] == in[i])) {
+	dup_len++;
+      }
+      /* See if we have enough zeros to be worth compressing. */
+      /* I figure one is enough. */
+      if ((dup_len >= 1) && (in[i] == 0)) {
+	/* Output run of zeros. */
+	while (dup_len >= 128) {
+	  /* Max is 128 */
+	  *out++ = 0x00;
+	  i += 128;
+	  dup_len -= 128;
+	}
+	if (dup_len >= 1)
+	{
+	  *out++ = dup_len;
+	  i += dup_len;
+	}
+	/* See if we have enough non-zeros to be worth compressing. */
+	/* Here two should be enough. */
+      }
+      else if (dup_len >= 2)
+      {
+	/* Output run of duplicates. */
+	while (dup_len >= 64) {
+	  /* Max is 64 */
+	  *out++ = 0x80;
+	  *out++ = in[i];
+	  i += 64;
+	  dup_len -= 64;
+	}
+	if (dup_len >= 2)
+	{
+	  *out++ = dup_len + 0x80;
+	  *out++ = in[i];
+	  i += dup_len;
+	}
+      }
+      else
+      {
+	/* Look for two zeros, or three duplicates to end literal run. */
+	/* Note this is one more than the number to start a run. */
+	int lit_len = -1;
+	int add_more = 1;
+	while (add_more) {
+	  lit_len++;
+	  if (i + lit_len == len) add_more = 0;
+	  /* Always add more if we are near the very end. */
+	  if (i + lit_len < len - 3) {
+	    char a = in[i + lit_len + 0];
+	    char b = in[i + lit_len + 1];
+	    char c = in[i + lit_len + 2];
+	    /* See if there are enough zeros */
+	    if ((a == b) && (b == 0)) add_more = 0;
+	    /* See if there are enough duplicates */
+	    if ((a == b) && (b == c)) add_more = 0;
+	  }
+	}
+	/* Output run of literals. */
+	while (lit_len >= 64) {
+	  /* Max is 64 */
+	  int j;
+	  *out++ = 0xc0;
+	  for (j = i; j < i + 64; j++) {
+	    *out++ = in[j];
+	  }
+	  i += 64;
+	  lit_len -= 64;
+	} 
+	if (lit_len) {
+	  int j;
+	  *out++ = lit_len + 0xc0;
+	  for (j = i; j < i + lit_len; j++) {
+	    *out++ = in[j];
+	  }
+	  i += lit_len;
+	}
+      }
+    }
+  }
+  return out-iout;
+}
+
+static void __inline__ place_2bytes(int x,unsigned char* y)
+{ y[0]=x>>8; y[1]=x; }
+static void __inline__ place_4bytes(int x,unsigned char* y)
+{ place_2bytes(x>>16,y); place_2bytes(x,y+2); }
+
+#define do_compress_data (1)
+void ppa_print_sweep(ppa_stat* prn,ppa_sweep_data* data)
+{
+  unsigned char* pc, *tpc;
+  unsigned i,datasize=data->data_size;
+  unsigned char sweep_packet[144];
+  int sweep_packet_size;
+  unsigned short HP720constants[] = { 0x8ca0, 0x4650, 0x12c0 };
+  unsigned short HP820constants[] = { 0x4650, 0x1c20, 0x0960 };
+  unsigned short HP1000constants[] = { 0x4650, 0x2328, 0x0708 };
+  unsigned short* constants;
+  int nozzle_data_size;
+  int MF; /* Multiplicative Factor -- quick hack */
+
+  pc=data->image_data;
+
+  if(do_compress_data)
+  {
+    if(!(pc=malloc((datasize/64+1)*65)))
+    {
+      fprintf(stderr,"ppa_print_sweep(): could not malloc storage for compressed data\n");
+      exit(-1);
+    }
+    datasize=compress(data->image_data,data->nozzle_data->pins_used_d2,datasize,pc);
+  }
+
+  /* send image data 16k at a time */
+  for(i=0, tpc=pc; i<datasize; tpc+=16384, i+=16384)
+    vlink_put(prn->fptr, 0, datasize-i > 16384 ? 16384 : datasize-i, tpc);
+
+  /* memory leak fix courtesy of John McKown */
+  if (do_compress_data)
+    free (pc);
+
+  /* construct sweep packet */
+  switch(prn->version)
+  {
+  case HP820:
+    constants=HP820constants;
+    MF=1;
+    break;
+  case HP720:
+    constants=HP720constants;
+    MF=2;
+    break;
+  case HP1000:
+    constants=HP1000constants;
+    MF=1;
+    break;
+  default:
+    fprintf(stderr,"ppa_print_sweep(): unknown printer verson\n");
+    return;
+  }
+
+  sweep_packet[0]=0;
+  sweep_packet[1]= do_compress_data;
+  sweep_packet[2]= data->direction==right_to_left ? 1 : 2;
+  sweep_packet[3]= data->in_color ? 14 : 1;
+
+  place_4bytes(datasize,sweep_packet+4);
+
+  memset(sweep_packet+8,0,8);
+
+  place_4bytes(MF*(data->vertical_pos+prn->y_offset),sweep_packet+16);
+  place_2bytes(constants[0],sweep_packet+20);
+  place_2bytes(MF*(data->left_margin+prn->x_offset),sweep_packet+22);
+  place_2bytes(MF*(data->right_margin+prn->x_offset),sweep_packet+24);
+  place_2bytes(constants[1],sweep_packet+26);
+  place_2bytes(constants[2],sweep_packet+28);
+  place_2bytes(0x100,sweep_packet+30);
+
+  if(data->next)
+  {
+    sweep_packet[32]= data->next->direction==right_to_left ? 1 : 2;
+    sweep_packet[33]= data->next->in_color ? 14 : 1;
+    place_4bytes(MF*(data->next->vertical_pos+prn->y_offset),sweep_packet+34);
+    place_2bytes(MF*(data->next->left_margin+prn->x_offset),sweep_packet+38);
+    place_2bytes(MF*(data->next->right_margin+prn->x_offset),sweep_packet+40);
+    place_2bytes(constants[1],sweep_packet+42);
+    place_2bytes(constants[2],sweep_packet+44);
+  }
+  else
+    memset(sweep_packet+32,0,14);
+  sweep_packet[46]=8;
+
+  nozzle_data_size=data->nozzle_data_size;
+  if(nozzle_data_size>6)
+  {
+    fprintf(stderr,"ppa_print_sweep(): truncating nozzle data from %d rows to 6 rows\n",nozzle_data_size);
+    nozzle_data_size=6;
+  }
+  sweep_packet[47]=nozzle_data_size;
+
+  for(i=0; i<nozzle_data_size; ++i)
+  {
+    unsigned char * const pc = sweep_packet + 48 + i*16;
+
+    place_2bytes(data->nozzle_data[i].DPI,pc);
+    place_2bytes(data->nozzle_data[i].pins_used_d2,pc+2);
+    place_2bytes(data->nozzle_data[i].unused_pins_p1,pc+4);
+    place_2bytes(data->nozzle_data[i].first_pin,pc+6);
+    place_2bytes(data->nozzle_data[i].pins_used_d2,pc+8);
+    place_2bytes(MF*(data->nozzle_data[i].left_margin+prn->x_offset),pc+10);
+    place_2bytes(MF*(data->nozzle_data[i].right_margin+prn->x_offset),pc+12);
+    pc[14]=data->nozzle_data[i].nozzle_delay;
+    pc[15]=0;
+  }
+
+  sweep_packet_size = data->in_color ? 144 : 80;
+
+  /* send sweep packet */
+  switch(prn->version)
+  {
+  case HP820:
+    scp_put (prn->fptr, 18, 1, 7, sweep_packet_size, sweep_packet);
+    break;
+  case HP720:
+    scp2_put (prn->fptr, 0x0180, sweep_packet_size, 7, 1, datasize, sweep_packet);
+    break;
+  case HP1000:
+    scp3_put (prn->fptr, 0x0180, sweep_packet_size, 7, 1, datasize, sweep_packet);
+    break;
+  default:
+    fprintf(stderr,"ppa_print_sweep(): unknown printer version\n");
+    return;
+  }
+}
+
+
+void ppa_print_sweeps(ppa_stat* prn,ppa_sweep_data* data)
+{
+  ppa_sweep_data* current_sweep;
+  for(current_sweep=data; current_sweep; current_sweep=current_sweep->next)
+    ppa_print_sweep(prn,current_sweep);
+}
diff --git a/converter/pbm/pbmtoppa/ppa.h b/converter/pbm/pbmtoppa/ppa.h
new file mode 100644
index 00000000..1c7e6f18
--- /dev/null
+++ b/converter/pbm/pbmtoppa/ppa.h
@@ -0,0 +1,74 @@
+/* ppa.h
+ * Copyright (c) 1998 Tim Norman.  See LICENSE for details.
+ * 2-25-98
+ *
+ * Mar 3, 1998  Jim Peterson  <jspeter@birch.ee.vt.edu>
+ *
+ *     Restructured to accommodate both the HP820/1000, and HP720 series.
+ */
+#ifndef _PPA_H
+#define _PPA_H
+#include <stdio.h>
+
+typedef struct
+{
+  FILE* fptr;
+  enum { HP820, HP1000, HP720, HP710 } version;
+  /* 300 , 600 dpi */
+  int DPI;
+  /* nozzle delay */
+  int right_to_left_delay[2];
+  int left_to_right_delay[2];
+  /* direction of printing */
+  enum { RIGHT_ONLY, LEFT_ONLY, BOTH_DIR } direction;
+  int x_offset;
+  int y_offset;
+  int marg_diff;
+  int top_margin;
+  int left_margin;
+  int right_margin;
+  int bottom_margin;
+  int bufsize;
+} ppa_stat;
+
+typedef struct
+{ 
+  int DPI;
+  int right;
+  int left;
+} printer_delay;
+
+typedef struct
+{
+  unsigned short DPI;
+  unsigned short pins_used_d2;
+  unsigned short unused_pins_p1;
+  unsigned short first_pin;
+  unsigned short left_margin;
+  unsigned short right_margin;
+  unsigned char nozzle_delay;
+} ppa_nozzle_data;
+
+typedef struct ppa_sweep_data_s
+{
+  unsigned char* image_data;
+  unsigned data_size;
+  enum { False=0, True=1 } in_color;
+  enum { right_to_left, left_to_right } direction;
+  int vertical_pos;
+  unsigned short left_margin;
+  unsigned short right_margin;
+  unsigned char nozzle_data_size;
+  ppa_nozzle_data* nozzle_data;
+  struct ppa_sweep_data_s* next; /* NULL indicates last print sweep */
+} ppa_sweep_data;
+
+void ppa_init_job(ppa_stat*);
+void ppa_init_page(ppa_stat*);
+void ppa_load_page(ppa_stat*);
+void ppa_eject_page(ppa_stat*);
+void ppa_end_print(ppa_stat*);
+void ppa_print_sweep(ppa_stat*,ppa_sweep_data*);  /* prints one sweep */
+void ppa_print_sweeps(ppa_stat*,ppa_sweep_data*); /* prints a linked-list of sweeps */
+
+#endif
diff --git a/converter/pbm/pbmtoppa/ppapbm.h b/converter/pbm/pbmtoppa/ppapbm.h
new file mode 100644
index 00000000..1ffc093b
--- /dev/null
+++ b/converter/pbm/pbmtoppa/ppapbm.h
@@ -0,0 +1,29 @@
+/* pbm.h
+ * Copyright (c) 1998 Tim Norman.  See LICENSE for details
+ * 2-25-98
+ *
+ * Mar 18, 1998  Jim Peterson  <jspeter@birch.ee.vt.edu>
+ *
+ *     Restructured to encapsulate more of the PBM handling.
+ */
+#ifndef _PBM_H
+#define _PBM_H
+
+#include <stdio.h>
+
+typedef struct
+{
+  FILE* fptr;
+  enum { none, P1, P4 } version;
+  int width, height;
+  int current_line;
+  void *revdata;
+  int unread;
+} pbm_stat;
+
+int make_pbm_stat(pbm_stat*,FILE*);
+int pbm_readline(pbm_stat*,unsigned char*); 
+  /* reads a single line into char* */
+void pbm_unreadline(pbm_stat*,void*); /* pushes a single line back */
+
+#endif