/* * pbmtoibm23xx -- print pbm file on IBM 23XX printers * Copyright (C) 2004 Jorrit Fahlke * * 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 program 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 . * * 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" in between. */ #include #include #include #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 single 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; }