|
Packit |
78deda |
/* pbmtoeps.c - read a PBM image and produce Epson graphics
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Copyright (C) 1990 by John Tiller (tiller@galois.msfc.nasa.gov)
|
|
Packit |
78deda |
** and Jef Poskanzer.
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Permission to use, copy, modify, and distribute this software and its
|
|
Packit |
78deda |
** documentation for any purpose and without fee is hereby granted, provided
|
|
Packit |
78deda |
** that the above copyright notice appear in all copies and that both that
|
|
Packit |
78deda |
** copyright notice and this permission notice appear in supporting
|
|
Packit |
78deda |
** documentation. This software is provided "as is" without express or
|
|
Packit |
78deda |
** implied warranty.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
|
|
Packit |
78deda |
#define _BSD_SOURCE /* Make sure strcaseeq() is in nstring.h */
|
|
Packit |
78deda |
#include <stdio.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "nstring.h"
|
|
Packit |
78deda |
#include "shhopt.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pbm.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static char const esc = 033;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
enum epsonProtocol {ESCP9, ESCP};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
enum adjacence {ADJACENT_ANY, ADJACENT_YES, ADJACENT_NO};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct CmdlineInfo {
|
|
Packit |
78deda |
/* All the information the user supplied in the command line,
|
|
Packit |
78deda |
in a form easy for the program to use.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
const char * inputFileName; /* '-' if stdin */
|
|
Packit |
78deda |
unsigned int dpi; /* zero means "any" */
|
|
Packit |
78deda |
enum adjacence adjacence;
|
|
Packit |
78deda |
enum epsonProtocol protocol;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseCommandLine(int argc,
|
|
Packit |
78deda |
const char ** argv,
|
|
Packit |
78deda |
struct CmdlineInfo * cmdlineP ) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Parse program command line described in Unix standard form by argc
|
|
Packit |
78deda |
and argv. Return the information in the options as *cmdlineP.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
If command line is internally inconsistent (invalid options, etc.),
|
|
Packit |
78deda |
issue error message to stderr and abort program.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
Note that the strings we return are stored in the storage that
|
|
Packit |
78deda |
was passed to us as the argv array. We also trash *argv.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
optEntry *option_def;
|
|
Packit |
78deda |
/* Instructions to pm_optParseOptions3 on how to parse our options.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
optStruct3 opt;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int option_def_index;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
char * protocol;
|
|
Packit |
78deda |
unsigned int adjacentSpec, nonadjacentSpec;
|
|
Packit |
78deda |
unsigned int dpiSpec, protocolSpec;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(option_def, 100);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
option_def_index = 0; /* incremented by OPTENT3 */
|
|
Packit |
78deda |
OPTENT3(0, "protocol", OPT_STRING, &protocol,
|
|
Packit |
78deda |
&protocolSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "dpi", OPT_UINT, &cmdlineP->dpi,
|
|
Packit |
78deda |
&dpiSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "adjacent", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&adjacentSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "nonadjacent", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&nonadjacentSpec, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
opt.opt_table = option_def;
|
|
Packit |
78deda |
opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
|
|
Packit |
78deda |
opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0);
|
|
Packit |
78deda |
/* Uses and sets argc, argv, and some of *cmdlineP and others. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!dpiSpec)
|
|
Packit |
78deda |
cmdlineP->dpi = 0;
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
if (cmdlineP->dpi == 0)
|
|
Packit |
78deda |
pm_error("-dpi must be positive");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (!protocolSpec)
|
|
Packit |
78deda |
cmdlineP->protocol = ESCP9;
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
if (strcaseeq(protocol, "escp9"))
|
|
Packit |
78deda |
cmdlineP->protocol = ESCP9;
|
|
Packit |
78deda |
else if (strcaseeq(protocol, "escp"))
|
|
Packit |
78deda |
cmdlineP->protocol = ESCP;
|
|
Packit |
78deda |
else if (strcaseeq(protocol, "escp2"))
|
|
Packit |
78deda |
pm_error("This program cannot do ESC/P2. Try Pbmtoescp2.");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
pm_error("Unrecognized value '%s' for -protocol. "
|
|
Packit |
78deda |
"Only recognized values are 'escp9' and 'escp'",
|
|
Packit |
78deda |
protocol);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (adjacentSpec && nonadjacentSpec)
|
|
Packit |
78deda |
pm_error("You can't specify both -adjacent and -nonadjacent");
|
|
Packit |
78deda |
else if (adjacentSpec)
|
|
Packit |
78deda |
cmdlineP->adjacence = ADJACENT_YES;
|
|
Packit |
78deda |
else if (nonadjacentSpec)
|
|
Packit |
78deda |
cmdlineP->adjacence = ADJACENT_NO;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->adjacence = ADJACENT_ANY;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 < 1)
|
|
Packit |
78deda |
cmdlineP->inputFileName = "-";
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
cmdlineP->inputFileName = argv[1];
|
|
Packit |
78deda |
if (argc-1 > 1)
|
|
Packit |
78deda |
pm_error("Too many arguments (%d). The only non-option argument "
|
|
Packit |
78deda |
"is the file name", argc-1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
free(option_def);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static unsigned int
|
|
Packit |
78deda |
lineWidth(const bit ** const stripeBits,
|
|
Packit |
78deda |
unsigned int const cols,
|
|
Packit |
78deda |
unsigned int const stripeRows) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Return the column number just past the rightmost column of the stripe
|
|
Packit |
78deda |
stripeBits[] that contains at least some black.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
The stripe is 'cols' wide by 'stripeRows' high.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
unsigned int col;
|
|
Packit |
78deda |
unsigned int endSoFar;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
endSoFar = 0;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (col = 0; col < cols; ++ col) {
|
|
Packit |
78deda |
unsigned int stripeRow; /* row number within stripe */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (stripeRow = 0; stripeRow < stripeRows; ++stripeRow) {
|
|
Packit |
78deda |
if (stripeBits[stripeRow][col] == PBM_BLACK)
|
|
Packit |
78deda |
endSoFar = col+1;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
return endSoFar;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
printStripe(const bit ** const stripeBits,
|
|
Packit |
78deda |
unsigned int const cols,
|
|
Packit |
78deda |
unsigned int const stripeRows,
|
|
Packit |
78deda |
char const m) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Print one stripe (a group of rows printed with one pass of the print
|
|
Packit |
78deda |
head. The stripe is cols columns wide by stripeRows high.
|
|
Packit |
78deda |
stripeBits[row][col] is the pixel value for Row row, Column col within
|
|
Packit |
78deda |
the stripe.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'm' is the "m" parameter for the Select Bit Image command. It controls
|
|
Packit |
78deda |
such things as the horizontal density.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
unsigned int col;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Print header of Select Bit Image command */
|
|
Packit |
78deda |
printf("%c%c%c%c%c", esc, '*', m, cols % 256, cols / 256);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Print the data part of the Select Bit Image command */
|
|
Packit |
78deda |
for (col = 0; col < cols; ++col) {
|
|
Packit |
78deda |
unsigned int stripeRow;
|
|
Packit |
78deda |
int val;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
val = 0;
|
|
Packit |
78deda |
for (stripeRow = 0; stripeRow < stripeRows; ++stripeRow)
|
|
Packit |
78deda |
if (stripeBits[stripeRow][col] == PBM_BLACK)
|
|
Packit |
78deda |
val |= (1 << (8-1-stripeRow));
|
|
Packit |
78deda |
putchar(val);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
computeM(enum epsonProtocol const protocol,
|
|
Packit |
78deda |
unsigned int const dpi,
|
|
Packit |
78deda |
enum adjacence const adjacence,
|
|
Packit |
78deda |
char * const mP) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Compute the "m" parameter for the Select Bit Image command.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
switch (dpi) {
|
|
Packit |
78deda |
case 0:
|
|
Packit |
78deda |
/* Special value meaning "any dpi you feel is appropriate" */
|
|
Packit |
78deda |
if (adjacence == ADJACENT_NO)
|
|
Packit |
78deda |
*mP = 2;
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
switch (protocol) {
|
|
Packit |
78deda |
case ESCP9: *mP = 5; break;
|
|
Packit |
78deda |
case ESCP: *mP = 6; break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 60:
|
|
Packit |
78deda |
if (adjacence == ADJACENT_NO)
|
|
Packit |
78deda |
pm_error("You can't print at %u dpi "
|
|
Packit |
78deda |
"with adjacent dot printing", dpi);
|
|
Packit |
78deda |
*mP = 0;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 120:
|
|
Packit |
78deda |
*mP = adjacence == ADJACENT_NO ? 2 : 1;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 240:
|
|
Packit |
78deda |
if (adjacence == ADJACENT_YES)
|
|
Packit |
78deda |
pm_error("You can't print at %u dpi "
|
|
Packit |
78deda |
"without adjacent dot printing", dpi);
|
|
Packit |
78deda |
*mP = 3;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 80:
|
|
Packit |
78deda |
if (adjacence == ADJACENT_NO)
|
|
Packit |
78deda |
pm_error("You can't print at %u dpi "
|
|
Packit |
78deda |
"with adjacent dot printing", dpi);
|
|
Packit |
78deda |
*mP = 4;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 72:
|
|
Packit |
78deda |
if (protocol != ESCP9)
|
|
Packit |
78deda |
pm_error("%u dpi is possible only with the ESC/P 9-pin protocol",
|
|
Packit |
78deda |
dpi);
|
|
Packit |
78deda |
if (adjacence == ADJACENT_NO)
|
|
Packit |
78deda |
pm_error("You can't print at %u dpi "
|
|
Packit |
78deda |
"with adjacent dot printing", dpi);
|
|
Packit |
78deda |
*mP = 5;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 90:
|
|
Packit |
78deda |
if (adjacence == ADJACENT_NO)
|
|
Packit |
78deda |
pm_error("You can't print at %u dpi "
|
|
Packit |
78deda |
"with adjacent dot printing", dpi);
|
|
Packit |
78deda |
*mP = 6;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case 144:
|
|
Packit |
78deda |
if (protocol != ESCP9)
|
|
Packit |
78deda |
pm_error("%u dpi is possible only with the ESC/P 9-pin protocol",
|
|
Packit |
78deda |
dpi);
|
|
Packit |
78deda |
if (adjacence == ADJACENT_NO)
|
|
Packit |
78deda |
pm_error("You can't print at %u dpi "
|
|
Packit |
78deda |
"with adjacent dot printing", dpi);
|
|
Packit |
78deda |
*mP = 7;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
pm_error("Invalid DPI value: %u. This program knows only "
|
|
Packit |
78deda |
"60, 72, 80, 90, 120, 144, and 240.", dpi);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
convertToEpson(const bit ** const bits,
|
|
Packit |
78deda |
int const cols,
|
|
Packit |
78deda |
int const rows,
|
|
Packit |
78deda |
enum epsonProtocol const protocol,
|
|
Packit |
78deda |
unsigned int const dpi,
|
|
Packit |
78deda |
enum adjacence const adjacence) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int const rowsPerStripe = 8;
|
|
Packit |
78deda |
unsigned int const stripeCt = (rows + rowsPerStripe-1) / rowsPerStripe;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int stripe;
|
|
Packit |
78deda |
char m;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
computeM(protocol, dpi, adjacence, &m);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Change line spacing to 8/72 inches. */
|
|
Packit |
78deda |
printf("%c%c%c", esc, 'A', 8);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Write out the rows, one stripe at a time. A stripe is 8 rows --
|
|
Packit |
78deda |
the amount written in one pass of the print head. The bottommost
|
|
Packit |
78deda |
stripe can be fewer than 8 rows.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (stripe = 0; stripe < stripeCt; ++stripe) {
|
|
Packit |
78deda |
const bit ** const stripeBits = &bits[stripe*rowsPerStripe];
|
|
Packit |
78deda |
unsigned int const stripeRows =
|
|
Packit |
78deda |
MIN(rowsPerStripe, rows - stripe * rowsPerStripe);
|
|
Packit |
78deda |
/* Number of rows in this stripe (8 for all but bottom stripe) */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int const endcol = lineWidth(stripeBits, cols, stripeRows);
|
|
Packit |
78deda |
/* Column where right margin (contiguous white area at right
|
|
Packit |
78deda |
end of stripe) begins. Zero if entire stripe is white.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (endcol > 0)
|
|
Packit |
78deda |
printStripe(stripeBits, endcol, stripeRows, m);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
putchar('\n');
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
putchar('\f');
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Restore normal line spacing. */
|
|
Packit |
78deda |
printf("%c%c", esc, '@');
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc, const char ** argv) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct CmdlineInfo cmdline;
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
const bit** bits;
|
|
Packit |
78deda |
int rows, cols;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_proginit(&argc, argv);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseCommandLine(argc, argv, &cmdline);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifP = pm_openr(cmdline.inputFileName);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
bits = (const bit **)pbm_readpbm(ifP, &cols, &rows);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_close(ifP);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
convertToEpson(bits, cols, rows,
|
|
Packit |
78deda |
cmdline.protocol, cmdline.dpi, cmdline.adjacence);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pbm_freearray(bits, rows);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|