/*
* pbmtoibm23xx -- print pbm file on IBM 23XX printers
* Copyright (C) 2004 Jorrit Fahlke <jorrit@jorrit.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 or later as published by the Free Software Foundation.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
/*
* This prgram is primarily based on the description of Brothers PPDS
* emulation (see
* http://www.brother.de/download/send_file.cfm?file_name=guide_ibmpro.pdf).
* However, there are some differences. Their document states that
* ESC J does linefeed in terms of 1/216" -- my printer clearly does
* it in terms of 1/240". Also, the quick and the slow mode for
* double density printing really makes a difference on my printer,
* the result of printing tiger.ps in quick double density mode was
* worse than printing it in single density mode.
*
* If anyone Knows of any better documentation of the language used by
* the IBM 23XX or PPDS in general, please send a mail to
* Jö Fahlke <jorrit@jorrit.de>.
*
* All the graphics modes of the printer differ only in the resolution
* in x they provide (and how quick they do their job). They print a
* line of 8 pixels height and variable widths. The bitlines within
* the line are 1/60" apart, so that is the resolution you can
* normally achieve in y. But the printer is able to do line feeds in
* terms of 1/240", so the trick to print in higher resolutions is to
* print in several interleaved passes, and do a line feed of 1/240"
* or 1/120" inbetween.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pm_c_util.h"
#include "pbm.h"
#include "shhopt.h"
#include "mallocvar.h"
struct cmdlineInfo {
unsigned char graph_mode;
unsigned int passes;
unsigned int nFiles;
const char ** inputFile;
};
bool sent_xon; /* We have send x-on to enable the printer already */
static void
parseCommandLine(int argc, char ** const argv,
struct cmdlineInfo * const cmdlineP) {
optStruct3 opt;
optEntry option_def[100];
unsigned int option_def_index = 0;
unsigned int xresSpec, yresSpec;
unsigned int xres, yres;
unsigned int slowMode;
OPTENT3(0, "xres", OPT_UINT, &xres, &xresSpec, 0);
OPTENT3(0, "yres", OPT_UINT, &yres, &yresSpec, 0);
OPTENT3(0, "slow", OPT_FLAG, NULL, &slowMode, 0);
opt.opt_table = option_def;
opt.short_allowed = 0;
opt.allowNegNum = 0;
pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
/* Uses and sets argc, argv, and some of *cmdlineP and others. */
if (!xresSpec)
pm_error("You must specify the -xres option");
if (!yresSpec)
pm_error("You must specify the -yres option");
switch (xres) {
case 60: cmdlineP->graph_mode = 'K'; break;
case 120: cmdlineP->graph_mode = slowMode ? 'L' : 'Y'; break;
case 240: cmdlineP->graph_mode = 'Z'; break;
default:
pm_error("Please specify 60, 120, or 240 for -xres");
}
if (yres != 60 && yres != 120 && yres != 240)
pm_error("Please specify 60, 120, or 240 for -yres");
cmdlineP->passes = yres / 60;
cmdlineP->nFiles = MAX(argc-1, 1);
MALLOCARRAY_NOFAIL(cmdlineP->inputFile, cmdlineP->nFiles);
if (argc-1 < 1)
cmdlineP->inputFile[0] = "-";
else {
unsigned int i;
for (i = 0; i < argc-1; ++i)
cmdlineP->inputFile[i] = argv[i+1];
}
}
/* Read all pbm images from a filehandle and print them */
static void
process_handle(FILE * const fh,
unsigned char const graph_mode,
unsigned int const passes) {
int eof;
while(pbm_nextimage(fh, &eof), eof == 0) {
/* pbm header dats */
int cols, rows, format;
/* iteration variables */
unsigned int x, y;
unsigned int bitline; /* pixel line within a sigle printing line */
unsigned int pass;
/* here we build the to-be-printed data */
unsigned char *output; /* for reading one row from the file */
bit *row;
/* Enable printer in case it is disabled, do it only once */
if(!sent_xon) {
putchar(0x11);
sent_xon = TRUE;
}
pbm_readpbminit(fh, &cols, &rows, &format);
output = malloc(sizeof(*output) * cols * passes);
if(output == NULL)
pm_error("Out of memory");
row = pbm_allocrow(cols);
for(y = 0; y < rows; y += 8 * passes) {
memset(output, 0, sizeof(*output) * cols * passes);
for(bitline = 0; bitline < 8; ++bitline)
for(pass = 0; pass < passes; ++pass)
/* don't read beyond the end of the image if
height is not a multiple of passes
*/
if(y + bitline * passes + pass < rows) {
pbm_readpbmrow(fh, row, cols, format);
for(x = 0; x < cols; ++x)
if(row[x] == PBM_BLACK)
output[cols * pass + x] |= 1 << (7 - bitline);
}
for(pass = 0; pass < passes; ++pass){
/* write graphics data */
putchar(0x1b); putchar(graph_mode);
putchar(cols & 0xff); putchar((cols >> 8) & 0xff);
fwrite(output + pass * cols, sizeof(*output), cols, stdout);
/* Carriage return */
putchar('\r');
/* move one pixel down */
putchar(0x1b); putchar('J'); putchar(4 / passes);
}
/* move one line - passes pixel down */
putchar(0x1b); putchar('J'); putchar(24 - 4);
}
putchar(0x0c); /* Form-feed */
pbm_freerow(row);
free(output);
}
}
int
main(int argc,char **argv) {
struct cmdlineInfo cmdline;
unsigned int i;
pbm_init(&argc, argv);
parseCommandLine(argc, argv, &cmdline);
sent_xon = FALSE;
for (i = 0; i < cmdline.nFiles; ++i) {
FILE *ifP;
pm_message("opening '%s'", cmdline.inputFile[i]);
ifP = pm_openr(cmdline.inputFile[i]);
process_handle(ifP, cmdline.graph_mode, cmdline.passes);
pm_close(ifP);
}
free(cmdline.inputFile);
return 0;
}