#!/bin/sh
# This is a shell archive (shar 3.32)
# made 03/08/1994 10:01 UTC by bin@greenie
# Source directory /u/softadm/pbmdot.enh
#
# existing files WILL be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   5401 -rw-r--r-- pbmtodot.1
#  10835 -rw-r--r-- pbmtodot.c
#    226 -rw-r--r-- Makefile
#
if touch 2>&1 | fgrep 'amc' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= pbmtodot.1 ==============
echo "x - extracting pbmtodot.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > pbmtodot.1 &&
X.TH pbmtodot 1 "31 May 1992"
X.IX pbmtodot
X.SH NAME
Xpbmtodot - convert a portable bitmap into dot-matrix printer commands
X.SH SYNOPSIS
X.B pbmtodot
X.RB [ -8 | -8x3 | -24
X.RB | -24x2 | -48 ]
X.RI [ pbmfile ]
X.RI [ outputfile ]
X.SH DESCRIPTION
XReads a portable bitmap as input.
XProduces a file of dot-matrix printer commands as output,
Xone or more bytes per column.
X.IX "Dot-matrix printer commands"
X.PP
XThe MSDOS version defaults to LPT1 as the output, rather than stdout.
X.PP
XNote that there is no dottopbm tool - this transformation is one way.
X.SH OPTIONS
X.PP
XThe default printer is a 24-pin Epson,
XNEC or compatible, at 180dpi resolution.
XThe program is designed so that most printers that take their data in
Xvertical stripes can be used,
Xand a few are built-in.
XMultiple interleaved passes can be used.
X.PP
XThe flags are as follows:
X.TS
Xcenter;
Xl l.
X-8	T{
Xfor 8-pin graphics, supported by most 9-pin printers.
XGives 72V by 60H resolution on an Epson MX or later.
XT}
X-8x3	T{
Xset three-pass printing on a 9-pin printer, giving 216V by 240H on Epsons.
XT}
X-24	T{
XReasserts the default 180dpi resolution on 24-pin printers.
XT}
X-24x2	Gives 360 dpi on NEC 24-pin printers, using two passes.
X-48	T{
XGives 360 dpi on a Canon BJ-10e, in its BJ-130e emulation.
XSet DIP switch 10 on (mode 2 graphics).
XT}
X.TE
X
X.SH ENVIRONMENT
XIf the environment variable PBMTODOT is set,
Xand no flags are given,
Xit will be used as a source of a generalised control string.
X
XThe string is like Termcap, but simplified.
XEach parameter name is one letter.
XString parameter names are followed by a delimiter
Xwhich must not occur in the string,
Xeven after it is parsed.
XNumerical parameters may be followed by "=" or ":".
X
X.TS
Xcenter;
Xl l.
X<str>	::= <item> <whitespace> <str> | <item>
X<item>	T{
X::= <parmname> <delimiter> <string> <delimiter> |
X<shortname> <punct> <number>
XT}
X<parmname>	::=  c | d | e | f | l | m | s | u | x
X<shortname>	::= b | i | p
X<punct>	::= = | : | <null>
X<delimiter>	::= any single character except \\\\0
X.TE
X
X.TS
Xcenter;
Xc s, l l.
XParameters: These default to null or 1 unless stated.
Xl	Start line (usually contains %c)
Xe	End line (should not do a linefeed: defaults to \\\\r)
Xf	Line feed (end of line: defaults to \\\\n)
Xm	Line feed (between multiple passes)
Xs	Start Print (initialise printer)
Xx	Exit print (reset printer to normal, maybe do a pagefeed)
Xb	Number of bytes transmitted for each column per pass
Xi	Interleave (number of passes with tiny line feed between each)
Xp	number of pins per pass (normally 8*b: defaults to 8)
Xd *	Non-zero if lsb is top row of dots
Xu *	Non-zero if first byte is at the bottom (fill Upwards)
Xc	Comment (parameter is ignored)
X.TE
X* = not implemented.
X
XThe program economises on the number of columns printed. The true number
Xof columns is available to the
X.I l
Xand
X.I e
Xstrings, but the others will see the maximum number of columns.
XIf a printhead pass would have no printing at all,
Xthe start and end
X.RI ( l
Xand
X.IR e )
Xstrings are omitted altogether;
Xin this case there will be a succession of
X.I f
Xand
X.I m
Xstrings. Hence
X.I f
Xand
X.I m
Xshould
Xonly do vertical motion, and the
X.I l
Xand
X.I e
Xhorizontal.
X
XThe actual print data will be transmitted between the
X.I l
Xand
X.I e
Xcontrols.
XCurrently the order of presentation is always top byte first, and each byte
Xhas the top dot in the msb.
XImplementing the "d" control would be trivial; the
X.I u
Xcontrol would take a bit more thought.
XNeither is needed for any printer I know of.
X
XEscape sequences
X
X.TS
Xcenter tab(^);
Xl l.
X%c^T{
XNumber of columns as two binary bytes, little-endian
X(This is the only variable that printers want that I know)
XIf you need more of the same, hack "putcode". And tell me.
XT}
X%%^Print a "%"
X\\\\\\\\^print a "\\\\"
X\\\\r^Carriage Return
X\\\\n^Line feed
X\\\\e^ESC
X\\\\123^Octal character (1 to 3 digits of octal)
X.TE
X.SH EXAMPLES
XThe default adaptation is
Xl:\\e*\\47%c: f:\\eJ\\30: b=3 p=24
Xc:180 dpi on NEC and Epson 24-print printers:
X
XThe following is the string used for 24x2.
XIt is a bit tricky, since the NEC doesn't have an explicit n/360 feed.
XYou have to set the linefeed to 1/360 and use that, then reset afterwards.
X
Xs:\\34\\63\\1: x:\\e2: l:\\e*\\50%c: m:\\n: f:\\n\\eJ\\27: b=3 i=2 p=24
Xc:360 dpi on NEC 24-print printers:
X
XYou don't have to have p = 8 * b. The following also gives 180 dpi, but
Xonly uses the top 17 pins of a 24-pin printer:
X
Xl:\\e*\\47%c: f:\\eJ\\21: p:17 b:3
X
XThis duplicates the effect of pbmto10x in high-resolution mode:
X
Xs:\\e3\\0: l:\\eL%c: m:\\eJ\\1: f:\\eJ\\17: e:\\n: i=2
X
X.SH "SEE ALSO"
Xpbm(5)
X.SH BUGS
XThe values for b, p and i are not sanity-checked.
XSetting any of them to zero is not recommended.
X.PP
XThe use of octal in escape sequences is an interesting historical relic.
X.PP
XThe MSDOS version only treats the default output (LPT1) specially.
XRedirecting to another printer will fall into a DOS bug, which deletes
X\\032 characters. File output is OK.
XDon't even THINK about using stdin under DOS.
X.SH AUTHOR
XCopyright (C) Ian Phillipps (ian@unipalm.co.uk)
X.\" Permission to use, copy, modify, and distribute this software and its
X.\" documentation for any purpose and without fee is hereby granted, provided
X.\" that the above copyright notice appear in all copies and that both that
X.\" copyright notice and this permission notice appear in supporting
X.\" documentation.  This software is provided "as is" without express or
X.\" implied warranty.
SHAR_EOF
$TOUCH -am 0602103792 pbmtodot.1 &&
chmod 0644 pbmtodot.1 ||
echo "restore of pbmtodot.1 failed"
set `wc -c pbmtodot.1`;Wc_c=$1
if test "$Wc_c" != "5401"; then
	echo original size 5401, current size $Wc_c
fi
# ============= pbmtodot.c ==============
echo "x - extracting pbmtodot.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > pbmtodot.c &&
X/* pbmtodot.c - read a portable bitmap and produce dot-matrix printer graphics
X**
X** Copyright (C) 1992 by Ian Phillipps (ian@unipalm.co.uk)
X**
X** Permission to use, copy, modify, and distribute this software and its
X** documentation for any purpose and without fee is hereby granted, provided
X** that the above copyright notice appear in all copies and that both that
X** copyright notice and this permission notice appear in supporting
X** documentation.  This software is provided "as is" without express or
X** implied warranty.
X*/
X
X#include <stdio.h>
X#ifdef __TURBOC__
X#include <stdlib.h>
X#endif
X#include "pbm.h"
X
X/*
XThis is like Termcap, but simplified. Each parameter name is one letter.
XString parameter names are followed by a delimiter which
Xmust not occur in the string.
XNumerical parameters may be followed by "=" or ":".
X
X<str>	::= <item> <whitespace> <str> | <item>
X<item>	::= <parmname> <delimiter> <string> <delimiter> | <shortname> <number>
X<parmname> ::=  c | d | e | f | l | m | s | u | x
X<shortname> ::= b | i | p
X
XThese default to null or 1 unless stated.
Xl	Start line (usually contains %c)
Xe	End line (should not do a linefeed: defaults to \r)
Xf	Line feed (end of line: defaults to \n)
Xm	Line feed (between multiple passes)
Xs	Start Print (initialise printer)
Xx	Exit print (reset printer to normal, maybe do a pagefeed)
Xb	Number of bytes transmitted per pass
Xi	Interleave (number of passes with tiny line feed between each)
Xp	number of pins per pass (normally 8*by: defaults to 8)
Xd *	Non-zero if lsb is top row of dots
Xu *	Non-zero if first byte is at the bottom (fill Upwards)
X	* = not implemented.
Xc	Comment (parameter is ignored)
X
XEscape sequences
X
X%c	Number of columns as two binary bytes, little-endian
X	(This is the only variable that printers want that I know)
X	If you need more of the same, hack "putcode". And tell me.
X%%	Print a "%"
X
X	The "\" escapes are provided for the benefit of PBMTODOT
X	variable setters. If you want an escape in a compiled-in string,
X	you must use \\e, to ensure that the runtime sees the "\".
X	If you need to print a literal "\", you need four of them. Sorry.
X
X\\	print a "\"
X\r	Carriage Return
X\n	Line feed
X\e	Escape - NB This must be represented as \\e within a C string
X\123	Octal number
X	NB - the string must NOT contain a literal \0 when scanned, so if
X	it is compiled-in to the program, a binary zero must be shown as
X	\\0. Once readparm has been at the string, an embedded \0 is fine.
X
X*/
X
X/* defcon is the default control string used if no parameters or environment
X   variables are specified */
X
Xchar defcon[] = "l:\\e*\\047%c: f:\\eJ\030: b=3 p=24\
Xc:Gives 180 dpi resolution on NEC and Epson 24-print printers:";
X
X/* Pairs of command-line parms and strings they produce. Because of the
X   way pm_getparms operates, make sure that a string is not followed by
X   one which is a leading substring of itself (e.g. -24x2 must come
X   before -24) */
X
Xchar *modes[][2] =
X{
X    {	"-24x2",
X	/* 360 dpi for a typical 24-pin printer (NEC 2200): two passes
X	   sets line spacing to 1/6" on exit */
X	"s:\034\063\001: x:\\e2: l:\\e*\050%c: m:\n: \
X	f:\n\\eJ\027: b=3 i=2 p=24\
X	c:Gives 360 dpi resolution on NEC 24-print printers:"
X    },
X    {	"-24",
X	defcon
X    },
X    {   "-360x180",
X        "l:\\e*\\050%c: f:\\eJ\030: b=3 p=24\
X         c:Gives 360x180 dpi on NEC / Epson 24-pin printers:"
X    },
X    {	"-48",
X	/* 360 dpi resolution on a Canon bubblejet (known to work on BJ-10e) */
X	/* Sorry, but we need to transmit a "\" character: hence \\\\ ! */
X	"s:\\e[\\\\\4\\0\\0\\0h\1: l:\34CB\4\4%c: \
X	f:\\eJ\60: p=48 b=6"
X    },
X    {	"-8x3",
X	/* Epson 9-pin, three passes: gives 240 x 216 resolution */
X	"l:\\eZ%c: f:\\eJ\25: m:\\eJ\1: i=3"
X    },
X    { 	"-8",
X	/* Epson 9-pin (only 8 used) - bog-standard single density 60x72 resolution */
X	"s:\\eA\010: l:\\eK%c:"
X    },
X    { (char*)0, (char*)0 } /* Keep this at the end! */
X};
X
Xstatic char *st_start_line;
Xstatic char *st_end_line;
Xstatic char *linefeed;
Xstatic char *tinyfeed;
Xstatic char *st_start_print;
Xstatic char *st_end_print;
Xstatic short bytes;
Xstatic short passes; /* i */
Xstatic short pins;
Xstatic FILE *ofp;
Xstatic int cols;
Xstatic int cols_x_passes;
X
X#ifdef __MSDOS__
X/* Would you believe that MSDOS (version 5) won't send a ^Z to a printer
X   via a filehandle?  No, nor did I until I wrote this program.
X */
X#include <bios.h>
X#include <conio.h>
X#define PR_ERROR	0x29	/* Error bits in printer status */
X#define PRINTER 	0	/* LPT1 */
X/* send characters to LPT1 via the BIOS. I dare say that Dos call 5 would do
X   the job as well, but you don't get a chance to print diagnostics */
Xint printc( int c )
X{
X	if ( ofp != stdout ) return putc( c, ofp );
X	while( biosprint( 2, 0, PRINTER ) & PR_ERROR )
X	{
X		fprintf( stderr, "Printer error: correct then press any key\n");
X		getch();
X	}
X	while( biosprint( 0, c, PRINTER ) & PR_ERROR )
X	{
X		fprintf( stderr, "Printer error: correct then press any key\n");
X		getch();
X	}
X	return c;
X
X}
X#else /* you have a sensible operating system */
X#define printc( c ) putc( (c), ofp )
X#endif
X
X
X/* Readparm reads a control string, and may destroy it in the process */
Xvoid readparm( string )
Xchar *string;
X{
X    /* initialise variables */
X    st_start_line = "::";
X    st_end_line = ":\r:";
X    linefeed = ":\n:";
X    tinyfeed = "::";
X    st_start_print = "::";
X    st_end_print = "::";
X    bytes = 1;
X    passes = 1;
X    pins = 8;
X    /* read the string */
X    while( *string )
X    {
X	char c = tolower( *string );
X	short *ashort;
X	char *dest, delim;
X
X	string++;
X
X	switch ( c )
X	{
X	case '\0':
X	    return;
X
X	case ' ': case '\t': case '\r': case '\n':
X	    break;
X
X	/* numerical parameters */
X	case 'b': ashort = &bytes; goto decode_short;
X	case 'i': ashort = &passes; goto decode_short;
X	case 'p': ashort = &pins;
X	decode_short:
X	    while( *string == ':' || *string == '=' )
X		string++;
X	    *ashort = 0;
X	    while( isdigit( *string ) )
X		*ashort = *ashort * 10 + *string++ - '0';
X	    break;
X
X	case 'e': st_end_line = string;	    	goto decode_string;
X	case 'f': linefeed = string;		goto decode_string;
X	case 'l': st_start_line = string;	goto decode_string;
X	case 'm': tinyfeed = string;		goto decode_string;
X	case 's': st_start_print = string;	goto decode_string;
X	case 'x': st_end_print = string;
X
X	case 'c': /* no action needed for a comment */
X	decode_string:
X	    /* Decode the string in situ */
X	    delim = *string++;
X	    dest = string;
X	    /* The code to overwrite the new copy of string relies
X	       on the interpreted string being no longer than the
X	       original */
X	    for( ; ( *dest = c = *string++ ) != delim; dest++ )
X	    {
X		if (!c )
X		    pm_error( "Delimiter '%c' missing from PBMTODOT string",
X					delim );
X		if ( c == '\\' ) switch ( *string )
X		{
X		case 'r':
X		    *dest = '\r'; string++; break;
X
X		case 'n':
X		    *dest = '\n'; string++; break;
X
X		case 'e':
X		    *dest = '\033'; string++; break;
X
X		default:
X		    *dest = *string++; break;
X
X		case '0': case '1': case '2': case '3':
X		case '4': case '5': case '6': case '7':
X		    *dest = *string++ - '0';
X		    if ( '0' <= *string && *string <= '7' )
X		    {
X			*dest = (*dest << 3) + *string++ - '0';
X			if ( '0' <= *string && *string <= '7' )
X			    *dest = (*dest << 3) + *string++ - '0';
X		    }
X		}
X	    }
X	    break;
X
X	case 'd': /* not implemented */
X	case 'u': /* *not implemented */
X	default:
X	    pm_error( "unknown char %c in format", c );
X	}
X    }
X}
X
X/* Write a single control string to the printer or output */
Xvoid putcode( format )
X    char *format;
X{
X    char delim;
X	char c;
X    for( delim = *format++; ( c = *format ) != delim; format++ )
X    {
X	if ( c == '%' )
X	{
X	    switch ( *++format )
X	    {
X	    case 'c':
X		printc( cols & 255 );
X		printc( cols >> 8 );
X		break;
X	    default:
X		printc( *format );
X	    }
X	}
X	else if ( printc( c ) == EOF )
X		pm_error( "Output error" );
X	}
X}
X
X/* Output array contains passes in pass-major order, so print out everything
X   in the order it's stored */
X
Xvoid writepasses( startline )
X	char *startline;
X{
X    int pass, col, byte;
X    char *outbyte;
X    for( pass = 0; ;  )
X    {
X	char *outcol;
X	int maxcols = cols;		/* save value of columns */
X	char *lastblank = outbyte = startline;	/* Last position to test for blank */
X	int lastcol;
X
X	cols = 0;
X	/* Although this order of doing things looks slower, it probably isnt*/
X	for( byte = 0; byte < bytes; byte++ )
X	{
X	    lastcol = maxcols-1;
X	    while ( outbyte[ lastcol ] == 0 && lastcol > cols ) lastcol--;
X
X	    cols = lastcol+1;
X
X	    outbyte += maxcols;
X	}
X
X	outcol = startline;
X	putcode ( st_start_line );
X	for( col = 0; col < cols; col++ )
X	    for( outbyte = outcol++, byte = 0; byte < bytes; byte++ )
X		printc( *outbyte ), outbyte += maxcols;
X	putcode ( st_end_line );
X	cols = maxcols;
X	if ( ++pass >= passes ) break;
X	putcode( tinyfeed );
X	startline += maxcols * bytes;
X    }
X    putcode( linefeed );
X
X}
X
Xvoid main( argc, argv )
X    int argc;
X    char* argv[];
X{
X    FILE* ifp;
X    bit *inrow, *inrowend;
X    char* outarray;
X
X    char *control;				/* Control string address */
X
X    int rows, format;
X
X    pbm_init( &argc, argv );
X
X    argc--; argv++;
X
X    control = getenv( "PBMTODOT" );
X    if ( ! control ) control = defcon;
X
X    if ( **argv == '-' )
X    {
X	int m = 0;
X	for ( m = 0; *modes[m][0]; m++ )
X	    if( pm_keymatch( *argv, modes[m][0], strlen( modes[m][0] ) ) )
X	    {
X		control = modes[m][1];
X		argv++; argc--;
X		break;
X	    }
X    }
X
X    if ( argc > 2 || **argv == '-' )
X	pm_usage( "[-8 -8x3 -24 -24x2 -48] [infile] [outfile]" );
X
X    ifp = pm_openr( argc >= 1 ? argv[0] : "-" );
X    readparm( control );
X    ofp = argc >= 2 ? pm_openw( argv[1] ) : stdout;
X
X    pbm_readpbminit(ifp, &cols, &rows, &format);
X    cols_x_passes = cols * passes;
X
X    /* allocate space for output */
X
X    if( !( outarray = malloc( cols_x_passes * bytes ) ) )
X	pm_error( "Out of memory" );
X
X    inrow = pbm_allocrow(cols);
X    inrowend = inrow + cols;
X
X    /* Read in the file */
X    putcode( st_start_print );
X    /* here we have three loops: (inner) passes, pins and (outer) bytes */
X    while( rows > 0 )
X    {
X	unsigned char mask = 0x80;
X	char *startpass = outarray;
X	int r;
X
X	memset( outarray, 0, cols_x_passes * bytes );
X	for( r = 0; r < pins; r++ )
X	{
X	    int p;
X	    char *startcol = startpass;
X	    for ( p = 0; p < passes; p++, startcol += cols * bytes )
X	    {
X		char *o = startcol;
X		bit *in = inrow;
X		pbm_readpbmrow(ifp, inrow, cols, format);
X		for( ; in < inrowend; o++, in++ )
X		    if( *in == PBM_BLACK )
X			*o |= mask;
X		/* breakout here ensures that the last few lines get printed */
X		if ( --rows <= 0 )
X		    goto endwriteloop; /* don't panic: just a double "break" */
X	    }
X	    if ( !( mask >>= 1 ) )
X	    {
X		mask = 0x80;
X		startpass += cols;
X	    }
X	}
X    endwriteloop:
X	writepasses( outarray );
X    }
X    putcode( st_end_print );
X
X    pm_close( ifp );
X
X    exit( 0 );
X    }
SHAR_EOF
$TOUCH -am 0226202393 pbmtodot.c &&
chmod 0644 pbmtodot.c ||
echo "restore of pbmtodot.c failed"
set `wc -c pbmtodot.c`;Wc_c=$1
if test "$Wc_c" != "10835"; then
	echo original size 10835, current size $Wc_c
fi
# ============= Makefile ==============
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# where you keep your pbmplus sources
XPBM=../pbmplus10dec91
X
Xpbmtodot: pbmtodot.c
X	gcc -O2 -g -fwritable-strings -I$(PBM) -I$(PBM)/pbm -o pbmtodot pbmtodot.c $(PBM)/pbm/libpbm.a
X
Xinstall: pbmtodot
X	cp pbmtodot /usr/local/bin/
SHAR_EOF
$TOUCH -am 1019181493 Makefile &&
chmod 0644 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "226"; then
	echo original size 226, current size $Wc_c
fi
exit 0
