1 /*
2 * pbmtoibm23xx -- print pbm file on IBM 23XX printers
3 * Copyright (C) 2004 Jorrit Fahlke <jorrit@jorrit.de>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version
7 * 2 or later as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17 * USA
18 */
19
20 /*
21 * This program is primarily based on the description of Brothers PPDS
22 * emulation (see
23 * http://www.brother.de/download/send_file.cfm?file_name=guide_ibmpro.pdf).
24 * However, there are some differences. Their document states that
25 * ESC J does linefeed in terms of 1/216" -- my printer clearly does
26 * it in terms of 1/240". Also, the quick and the slow mode for
27 * double density printing really makes a difference on my printer,
28 * the result of printing tiger.ps in quick double density mode was
29 * worse than printing it in single density mode.
30 *
31 * If anyone Knows of any better documentation of the language used by
32 * the IBM 23XX or PPDS in general, please send a mail to
33 * Jö Fahlke <jorrit@jorrit.de>.
34 *
35 * All the graphics modes of the printer differ only in the resolution
36 * in x they provide (and how quick they do their job). They print a
37 * line of 8 pixels height and variable widths. The bitlines within
38 * the line are 1/60" apart, so that is the resolution you can
39 * normally achieve in y. But the printer is able to do line feeds in
40 * terms of 1/240", so the trick to print in higher resolutions is to
41 * print in several interleaved passes, and do a line feed of 1/240"
42 * or 1/120" in between.
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include "pm_c_util.h"
50 #include "pbm.h"
51 #include "shhopt.h"
52 #include "mallocvar.h"
53
54 struct cmdlineInfo {
55 unsigned char graph_mode;
56 unsigned int passes;
57 unsigned int nFiles;
58 const char ** inputFile;
59 };
60
61
62 bool sent_xon; /* We have send x-on to enable the printer already */
63
64
65
66
67 static void
parseCommandLine(int argc,char ** const argv,struct cmdlineInfo * const cmdlineP)68 parseCommandLine(int argc, char ** const argv,
69 struct cmdlineInfo * const cmdlineP) {
70
71 optStruct3 opt;
72 optEntry option_def[100];
73
74 unsigned int option_def_index = 0;
75 unsigned int xresSpec, yresSpec;
76 unsigned int xres, yres;
77 unsigned int slowMode;
78
79 OPTENT3(0, "xres", OPT_UINT, &xres, &xresSpec, 0);
80 OPTENT3(0, "yres", OPT_UINT, &yres, &yresSpec, 0);
81 OPTENT3(0, "slow", OPT_FLAG, NULL, &slowMode, 0);
82
83 opt.opt_table = option_def;
84 opt.short_allowed = 0;
85 opt.allowNegNum = 0;
86
87 pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
88 /* Uses and sets argc, argv, and some of *cmdlineP and others. */
89
90 if (!xresSpec)
91 pm_error("You must specify the -xres option");
92 if (!yresSpec)
93 pm_error("You must specify the -yres option");
94
95 switch (xres) {
96 case 60: cmdlineP->graph_mode = 'K'; break;
97 case 120: cmdlineP->graph_mode = slowMode ? 'L' : 'Y'; break;
98 case 240: cmdlineP->graph_mode = 'Z'; break;
99 default:
100 pm_error("Please specify 60, 120, or 240 for -xres");
101 }
102
103 if (yres != 60 && yres != 120 && yres != 240)
104 pm_error("Please specify 60, 120, or 240 for -yres");
105
106 cmdlineP->passes = yres / 60;
107
108 cmdlineP->nFiles = MAX(argc-1, 1);
109 MALLOCARRAY_NOFAIL(cmdlineP->inputFile, cmdlineP->nFiles);
110
111 if (argc-1 < 1)
112 cmdlineP->inputFile[0] = "-";
113 else {
114 unsigned int i;
115 for (i = 0; i < argc-1; ++i)
116 cmdlineP->inputFile[i] = argv[i+1];
117 }
118 }
119
120
121
122 /* Read all pbm images from a filehandle and print them */
123 static void
process_handle(FILE * const fh,unsigned char const graph_mode,unsigned int const passes)124 process_handle(FILE * const fh,
125 unsigned char const graph_mode,
126 unsigned int const passes) {
127 int eof;
128
129 while(pbm_nextimage(fh, &eof), eof == 0) {
130 /* pbm header dats */
131 int cols, rows, format;
132 /* iteration variables */
133 unsigned int x, y;
134 unsigned int bitline; /* pixel line within a single printing line */
135 unsigned int pass;
136 /* here we build the to-be-printed data */
137 unsigned char *output; /* for reading one row from the file */
138 bit *row;
139
140 /* Enable printer in case it is disabled, do it only once */
141 if(!sent_xon) {
142 putchar(0x11);
143 sent_xon = TRUE;
144 }
145
146 pbm_readpbminit(fh, &cols, &rows, &format);
147
148 output = malloc(sizeof(*output) * cols * passes);
149 if(output == NULL)
150 pm_error("Out of memory");
151 row = pbm_allocrow(cols);
152
153 for(y = 0; y < rows; y += 8 * passes) {
154 memset(output, 0, sizeof(*output) * cols * passes);
155 for(bitline = 0; bitline < 8; ++bitline)
156 for(pass = 0; pass < passes; ++pass)
157 /* don't read beyond the end of the image if
158 height is not a multiple of passes
159 */
160 if(y + bitline * passes + pass < rows) {
161 pbm_readpbmrow(fh, row, cols, format);
162 for(x = 0; x < cols; ++x)
163 if(row[x] == PBM_BLACK)
164 output[cols * pass + x] |= 1 << (7 - bitline);
165 }
166 for(pass = 0; pass < passes; ++pass){
167 /* write graphics data */
168 putchar(0x1b); putchar(graph_mode);
169 putchar(cols & 0xff); putchar((cols >> 8) & 0xff);
170 fwrite(output + pass * cols, sizeof(*output), cols, stdout);
171
172 /* Carriage return */
173 putchar('\r');
174
175 /* move one pixel down */
176 putchar(0x1b); putchar('J'); putchar(4 / passes);
177 }
178
179 /* move one line - passes pixel down */
180 putchar(0x1b); putchar('J'); putchar(24 - 4);
181 }
182 putchar(0x0c); /* Form-feed */
183
184 pbm_freerow(row);
185 free(output);
186 }
187 }
188
189
190
191 int
main(int argc,char ** argv)192 main(int argc,char **argv) {
193
194 struct cmdlineInfo cmdline;
195 unsigned int i;
196
197 pbm_init(&argc, argv);
198
199 parseCommandLine(argc, argv, &cmdline);
200
201 sent_xon = FALSE;
202
203 for (i = 0; i < cmdline.nFiles; ++i) {
204 FILE *ifP;
205 pm_message("opening '%s'", cmdline.inputFile[i]);
206 ifP = pm_openr(cmdline.inputFile[i]);
207 process_handle(ifP, cmdline.graph_mode, cmdline.passes);
208 pm_close(ifP);
209 }
210
211 free(cmdline.inputFile);
212
213 return 0;
214 }
215