HP printer filter

From: K. Russell <russell_at_ais.alumdev.oberlin.edu>
Date: Mon, 19 Feb 2001 19:04:28 -0500 (EST)

Our Tru64 site has for some years used the following input print filter
to pre-format print jobs for (any and all) HP LaserJet printers...

Essentially, the print filter parses a chunk of the file to be
printed, decides what format will work best (portrait, landscape,
regular, condensed or extra small font), and then encapsulates
the input file in HP PCL commands which give the appropriate format
(and which isolate the print job from any innappropriate default
settings present on the printer).

The filter program is also responsive to -w page width requests, for
instance to force a file with very wide lines to print in regular
portrait format (in which case the wide lines will wrap).
Pine or other email programs can be pre-configured to use -w80 if
desired, to provide a consistent "normal portrait" look when users
print email containing run-on paragraphs (which the filter would
otherwise interpret as "wide" and thus set to landscape).

More documentation is included in the body of the program.

Our relatively unsophisticated users have found this makes it easier
for them to print out routine reports, etc, from deep within an RDBMS;
for instance, wide output will automatically be printed as landscape,
narrow as portrait, wide + very tall as portrait in a compressed
font, and so on.

The filter will not screw up files previously formatted for an
HP printer, for instance, word processing jobs submitted to the
printer from within Corel's WordPerfect.

Since my program is based on an earlier print filter
found posted on the OSF managers list (date: 1995),
I thought I might as well post it back to the forum
to see if anyone else can make use of it.

The file, "hplaserif.c", is included below in the body of this
message. Once compiled, the executable may be used by placing it
in the ":if" entry of an HP printer in /etc/printcap.
Set the printcap entry up with ":pw=0:" if you wish to allow
the default "guessing" behavior to take place, or set pw to a
specific width if you have found one format you like and do not
wish to diverge from it.
(hplaserif may also be used as a pipe, independent of printcap and lpd:
standard input to the program is a file to be printed, and
standard output is the same file with PCL- and PJL- formatting.)

Any suggestions or complaints? Please direct them to

Katherine Russell
russell_at_ais.oberlin.edu

NOTE: hplaserif ought to work with operating systems besides
Digital-Tru64 unix as well; nothing in the program is Digital Unix-
specific other than the assumption that a "-w option" will be
inherited properly from the lpr command, but a "-l option" will not.
Unfortunately, I have found that DU user -l options seem to be
thrown out at some point before being provided to the print filter,
so an earlier attempt to have the program respond to printer page
length requests has been commented out. Perhaps it can be resuscitated
under another OS.

/*** BEGIN C PROGRAM ***/
/*******************************************************/
/* */
/* PROGRAM: hplaserif.c */
/* AUTHOR: K.B.W. Russell */
/* REVISED: 1/30/98,8/30/2000 */
/* */
/* BASED ON: hplazer4.c */
/* * Found in Oct 95 archives of listserv */
/* alpha-osf-managers_at_ornl.gov. */
/* AUTHOR: Alex M. George */
/* DATE: December, 21, 1993 */
/* "Designed by Alex George to work with landscape */
/* script on November, 23, 1993." */
/* */
/* About hplaserif.c: */
/* */
/* This program filters text for output to the */
/* HPLaserJet printers. It examines the length of */
/* lines in the first 10,000 char of the doc sent to */
/* it, and decides what printing format to use, */
/* based on the longest line it sees. */
/* */
/* If it encounters the HP PJL "UEL" job delimiter */
/* anywhere in this examined portion of the doc, */
/* it gives up and doesn't try any formatting. */
/* Presence of the UEL indicates that this is */
/* a pre-formatted print job. */
/* */
/* In all other cases, page width gives: */
/* - 96 characters and under = portrait */
/* - 97-110 characters = portrait 14 cpi */
/* - 97-132 characters with page length > 46 lines = */
/* portrait with compressed ("tiny") font. */
/* Vertical spacing is compressed as well. */
/* - 111-127 characters = landscape */
/* - 128-150 characters = landscape 14 cpi */
/* - over 150 characters = landscape, with tiny font */
/* and compressed vert. spacing */
/* */
/* You can use lpr's "-w" option to override this */
/* automatic behavior, if desired. */
/* */
/* Line width which you pass should correspond to */
/* the behavior which you want. For instance, */
/* - Pass -w80 for a regular size font, portait format */
/* - Pass -w110 for portrait 14cpi */
/* - Pass -w127 for landscape */
/* - etc, */
/* with the one exception: */
/* - Passing -w132 constitutes a "magic" request for */
/* the unusual format, portrait with compressed */
/* (tiny) font, otherwise obtained by the combination */
/* of 97-132 characters in width and over 46 lines in */
/* length. Good for packing lots of info to a page. */
/* */
/* ADDITIONAL NOTES about text formatting: */
/* */
/* Default font used is Courier. */
/* Line wrapping is enabled. */
/* <CR> is added before each <LF> . */
/* Plus, entire print job is "armored" in a */
/* HP PJL request to use PCL to interpret */
/* it... also, the originating username */
/* will display in the printer's status */
/* window for a brief period of time, */
/* as the job is being sent. KR 2000 */
/*******************************************************/

#include <stdio.h>
#include <string.h>
#ifndef lint
static char vcid[] = "$Id: hplaserif.c,v 1.20 2001/02/19 23:16:17 root Exp root $";
#endif /* lint */

#define MAXBUF 10000
#define LANDSCAPE 47
#define PORTRAIT 80

/* Routine to parse argument characters into an integer value */
int int_arg(char * readit){
  int ttl=0; /* running total */
  while (readit[0] > 47 && readit[0] < 58)
    {
      ttl = 10*ttl + readit[0] - 48;
      readit++;
    }
  return ttl;
}

/* routine to look at args: for width and username */
void parse_args( int argc, char ** argv, int * width, int * lines,
                char * usnam)
{
  int arg, request, tmp;
  for (arg=1; arg< argc; arg++)
    {
      if (argv[arg][0] == '-')
        {
          switch (argv[arg][1])
            {
            case 'w' :
              /* user passed a "width"- requests a page layout */
              request = int_arg(& (argv[arg][2]));
              if (request > 0) {
                *width = request;
                /* assume wide print requests should be landscape,
                 * unless the user has used the magic width 132,
                 * which is a request for compressed portrait:
                 */
                if (*width==132) *lines=PORTRAIT;
                else *lines = LANDSCAPE;
              }
              break;
            case 'n' :
              /* username will be next! get arg+1 to display on printer */
              if (arg+1 < argc)
                {
                  arg++;
                  for (tmp=0;tmp < L_cuserid && argv[arg][tmp]; tmp++)
                    {
                      usnam[tmp] = argv[arg][tmp];
                    }
                  usnam[tmp] = '\0'; /* make sure string is null-terminated */
                }
              break;
              /*
               * "-l" does not seem to work on Digital Unix:
               * no matter what -l arg the user types,
               * lpr or lpd does not relay it to the
               * print filters: a malignant, system "-l"
               * is ALWAYS PASSED instead
               */
              /* case 'l' :;
               * k = ReadArg(& (argv[arg][2]));
               * if (k > 0) {*lines =k;}
               * break;
               */
            default:;
              break;
    } } }
}

/* strings for PJL: */
char * pjl_head = "\033%-12345X",
* pjl_d1 = "_at_PJL RDYMSG DISPLAY = \042", *pjl_d2 = "\042\n",
* pjl_mid = "_at_PJL ENTER LANGUAGE = PCL\n",
* pjl_tail = "\n\033%-12345X_at_PJL RDYMSG DISPLAY = \042\042\n\033%-12345X\n";
int do_fmt=1;

/* search for HP PJL region in print text: */
int test_pjl ( char next )
{
  static char * test_start_pjl= "\0";
  static int in_pjl=0;

  if (!test_start_pjl[0]) test_start_pjl=pjl_head;

  if (in_pjl || next)
    {
      if (test_start_pjl[0]==next)
        {
          in_pjl=1;
          if (!test_start_pjl[1]) { do_fmt=0; } /* found entire UEL */
          else test_start_pjl++; /* move along string */
        }
      else
        { in_pjl=0; test_start_pjl=pjl_head; } /* reset comparison */
    }
  return (!do_fmt);
}

/* find "representative" line width by looking at first 10,000 characters: */
int analyze (char * buffer, int * width, int * lines)
{
  char c;
  int i=0, j=0, k=0;
  
  while ((i < MAXBUF) && ((c=getchar()) != EOF))
    {
      buffer[i++] = c; /* store character in buffer */
      if (test_pjl(c)) return i; /* found PJL UEL: don't bother */
      if ( (c == '\n') || (c == '\r')) /* end of a line */
        {
          j += (c == '\n'); /* add one to line-per-page count */
          if ( k > *width ) *width=k; /* found new "longest line": */
          k = 0; /* reset line length counter */
        }
      else if (c == '\f')
        {
          if ( j > *lines ) *lines=j; /* record page length */
          j = 0;
        }
      else k++; /* count character in line length */
    }
  if ( j > *lines ) *lines=j; /* pay attention to unterminated page */
 
  return i; /* number of char in buffer */
}

void main ( int argc, char *argv [] )
{
   int c, j=0, k=0, width=0, lines=0,
     was_cr=0,
     buf_ct=0;
   char buffer[MAXBUF]; /* used to hold text being examined */
   char usnam[L_cuserid+1]; /* defined in stdio. username length estimate */

/*
 * The following section reads the 1st MAXBUF chars of the printjob into
 * buffer, to find the longest line so far.
 * This info will be used for font selection.
 * Note: this information will be overridden if the user specifies
 * a preferred width/ length of their own, using -w or -l flags
 */
/*
 * EXCEPT THAT: at the current time, a user's "-l" is not conveyed
 * properly to the input filter program... so the user is powerless to
 * specify a "-l" length (and parse_args no longer tries to set it)
 */

buf_ct=analyze (buffer, &width, &lines);

/* Now look at user arguments. User can specify desired width if desired.
 * /etc/printcap should be set up with pw#0, so any non-zero "-w" option
 * is *known* to originate with the user.
 * This width will take precedence over the value
 * "discovered" by the page parsing code above:
 */

if (do_fmt)
  {
    strcpy(usnam,"unix"); /* set a default "user name" */

    /* Find any width, length, user args passed to the print filter: */
    parse_args( argc, argv, &width, &lines, usnam );
    
    /* Place user name into standard out: for effect
     * Looks very impressive on printers which support this feature.
     * Displays username in printer "window" as the job is printing */
    printf("%s",pjl_head);
    printf("%s%s%s",pjl_d1,usnam,pjl_d2);
    printf("%s",pjl_mid);
    
    if (width <= 96) { /* portrait 12pts */
      printf ("\033\046\154\060\117"); /* portrait */
      printf ("\033\046\153\064\123"); /* pitch mode elite 12cpi */
      printf ("\033\050\163\064\060\071\071\124"); /* courier font */
      printf ("\033\046\154\066\104"); /* normal line spacing */
    }
    
    else if (width <= 110) { /* portrait 14cpi */
      printf ("\033\046\154\060\117"); /* portrait */
      printf ("\033\046\153\064\123"); /* pitch mode elite 12cpi */
      printf ("\033\050\163\061\064\110"); /* pitch scale 14cpi */
      printf ("\033\050\163\064\060\071\071\124"); /* courier font */
      printf ("\033\046\154\066\104"); /* normal line spacing */
    }
    
    else if ((width <= 132) && (lines > LANDSCAPE)) {
      /* compressed type portrait */
      printf ("\033\046\154\060\117"); /* portrait */
      printf ("\033\046\153\062\123"); /* pitch mode condensed 16.5-16.7 */
      printf ("\033\050\163\064\060\071\071\124"); /* courier font */
      printf ("\033\050\163\017"); /* 15 cpi-remove \110 */
      printf ("\033\046\154\070\104"); /* condensed line spacing */
    }
    
    else if (width <= 127) { /* landscape 12pts */
      printf ("\033\046\154\061\117"); /* landscape */
      printf ("\033\046\1411\120"); /* rotate 90 degrees */
      printf ("\033\046\153\064\123"); /* pitch mode elite 12cpi */
      printf ("\033\050\163\064\060\071\071\124"); /* courier font */
      printf ("\033\046\154\066\104"); /* normal line spacing */
    }
    
    else if (width <= 150) { /* landscape 14 cpi */
      printf ("\033\046\154\061\117"); /* landscape */
      printf ("\033\046\1411\120"); /* rotate 90 degrees */
      printf ("\033\046\153\064\123"); /* pitch mode elite 12cpi */
      printf ("\033\050\163\061\064\110"); /* pitch scale 14cpi */
      printf ("\033\050\163\064\060\071\071\124"); /* courier font */
      printf ("\033\046\154\066\104"); /* normal line spacing */
    }
    
    else { /* landscape compressed */
      printf ("\033\046\153\062\123"); /* pitch mode condensed 16.5-16.7 */
      printf ("\033\046\154\061\117"); /* landscape */
      printf ("\033\046\1411\120"); /* rotate 90 degrees */
      printf ("\033\050\163\017"); /* 15 cpi-remove \110 */
      printf ("\033\046\154\070\104"); /* condensed line spacing */
    }
    
    /* enable end-of-line wrapping in case pp. after page 1 are wider: */
    printf ("\033\046\163\060\103");
  }
   
/* put the buffer contents onto output: */
for (k = 0; k < (buf_ct-1); k++)
{
  if ( do_fmt && buffer[k] == '\n' && ( k>0 ? (buffer[k-1] != '\r') : 1))
    printf("\r"); /* add <CR> to every <LF> not already preceded with <CR> */
  printf ("%c", buffer[k]);
}

/* note any final <CR> printed: */
if (buffer[buf_ct-2] == '\r') was_cr=0;
else was_cr=1;

/* loop through remaining data. */
/* start with c, the last character in the buffer */
c=buffer[buf_ct-1];
while (c != EOF)
  {
    if (c == '\f')
      {
        if ((c=getchar()) != EOF) printf ("\f");
      }
    else
      {
        /* handle <CR> insertion */
        if (do_fmt && !was_cr && c == '\n') printf("\r");
        if (c == '\r') was_cr=1;
        else was_cr=0;

        putchar (c); /* pass through to stdout */
        c = getchar();
      }
  }

/* Reset printer back into normal mode. */

if (do_fmt)
  {
    /* printf ("\033\046\154\060\117"); * portrait *
     * printf ("\033\046\154\066\104"); * normal line spacing *
     * printf ("\033\046\153\064\123"); * pitch mode elite 12cpi *
     * printf ("\033\050\163\012"); * 12 cpi *
     * printf ("\033\050\163\064\060\071\071\124"); * courier font *
     */
    printf ("%s",pjl_tail);
  }
}
/*** END C PROGRAM ***/
Received on Tue Feb 20 2001 - 00:05:51 NZDT

This archive was generated by hypermail 2.4.0 : Wed Nov 08 2023 - 11:53:41 NZDT