1 /*
2 * Generate PPM files from printer output
3 *
4 * Copyright 2000-2001 Eric Sharkey <sharkey@superk.physics.sunysb.edu>
5 * Andy Thaller <thaller@ph.tum.de>
6 * Robert Krawitz <rlk@alum.mit.edu>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <gutenprint/util.h>
26 #include<stdio.h>
27 #include<stdlib.h>
28 #ifdef HAVE_LIMITS_H
29 #include<limits.h>
30 #endif
31 #include<string.h>
32
33 #ifdef __GNUC__
34 #define inline __inline__
35 #endif
36
37 typedef enum {
38 QT_NONE,
39 QT_QUAD,
40 QT_MIS
41 } quadtone_t;
42
43 /*
44 * Printer state variable.
45 */
46 typedef struct {
47 unsigned char unidirectional;
48 unsigned char printer_weave;
49 int page_management_units; /* dpi */
50 int relative_horizontal_units; /* dpi */
51 int absolute_horizontal_units; /* dpi, assumed to be >= relative */
52 int relative_vertical_units; /* dpi */
53 int absolute_vertical_units; /* dpi, assumed to be >= relative */
54 int horizontal_spacing; /* Horizontal dot spacing */
55 int top_margin; /* dots */
56 int bottom_margin; /* dots */
57 int page_height; /* dots */
58 int dotsize;
59 int bpp; /* bits per pixel */
60 int current_color;
61 int xposition; /* dots */
62 int yposition; /* dots */
63 int monomode;
64 int nozzle_separation;
65 int nozzles;
66 int extraskip;
67 int got_graphics;
68 int left_edge;
69 int right_edge;
70 int top_edge;
71 int bottom_edge;
72 quadtone_t quadtone;
73 } pstate_t;
74
75 /* We'd need about a gigabyte of ram to hold a ppm file of an 8.5 x 11
76 * 1440 x 720 dpi page. That's more than I have in my laptop, so, let's
77 * play some games to reduce memory. Allocate each scan line separately,
78 * and don't require that the allocated height be full page width. This
79 * way, if we only want to print a 2x2 image, we only need to allocate the
80 * ram that we need. We'll build up the printed image in ram at low
81 * color depth, KCMYcm color basis, and then write out the RGB ppm file
82 * as output. This way we never need to have the full data in RAM at any
83 * time. 2 bits per color of KCMYcm is half the size of 8 bits per color
84 * of RGB.
85 *
86 * We would like to be able to print in bands, so that we don't have to
87 * read the entire page into memory in order to print it. Unfortunately,
88 * we may not know what the left and right margins are until we've read the
89 * entire file. If we can read it in two passes we could do it; use one
90 * pass to scan the file looking at the margins, and another pass to
91 * actually read in the data. This optimization may be worthwhile.
92 */
93
94 #define MAX_INKS 20
95 typedef struct {
96 unsigned char *line[MAX_INKS];
97 int startx[MAX_INKS];
98 int stopx[MAX_INKS];
99 } line_type;
100
101 typedef unsigned char ppmpixel[3];
102
103 unsigned char *buf;
104 unsigned valid_bufsize;
105 unsigned char minibuf[256];
106 unsigned bufsize;
107 unsigned save_bufsize;
108 unsigned char ch;
109 unsigned short sh;
110 int eject = 0;
111 int global_counter = 0;
112 int global_count = 0;
113 unsigned color_mask = 0xffffffff;
114
115 pstate_t pstate;
116 int unweave;
117
118 line_type **page=NULL;
119
120 /* Color Codes:
121 color Epson1 Epson2 Sequential
122 Black 0 0 0/16
123 Magenta 1 1 1/17
124 Cyan 2 2 2/18
125 Yellow 4 4 3/19
126 L.Mag. 17 257 4
127 L.Cyan 18 258 5
128 L.Black 16 256 6
129 D.Yellow 36 516 7
130 Red 7 N/A 8
131 Blue 8 N/A 9
132 P.Black 64 N/A 0
133 Gloss 9 N/A 10
134 LL.Black 48 768 11
135 Orange 10 N/A 12
136 */
137
138 /* convert either Epson1 or Epson2 color encoding into a sequential encoding */
139 static int
seqcolor(int c)140 seqcolor(int c)
141 {
142 switch (c)
143 {
144 case 0:
145 return 0;
146 case 1:
147 return 1;
148 case 2:
149 return 2;
150 case 4:
151 return 3;
152 case 17:
153 case 257:
154 return 4;
155 case 18:
156 case 258:
157 return 5;
158 case 16:
159 case 256:
160 return 6;
161 case 36:
162 case 516:
163 return 7;
164 case 7:
165 return 8;
166 case 8:
167 return 9;
168 case 9:
169 return 10;
170 case 48:
171 case 768:
172 return 11;
173 case 10:
174 return 12;
175 case 64:
176 return 16;
177 case 65:
178 return 17;
179 case 66:
180 return 18;
181 case 68:
182 return 19;
183 default:
184 return 0;
185 }
186 }
187
188 extern void merge_line(line_type *p, unsigned char *l, int startl, int stopl,
189 int color);
190 extern void expand_line (unsigned char *src, unsigned char *dst, int height,
191 int skip, int left_ignore);
192 extern void write_output (FILE *fp_w, int dontwrite, int allblack);
193 extern void find_white (unsigned char *buff,int npix, int *left, int *right);
194 extern int update_page (unsigned char *buff, int buffsize, int m, int n,
195 int color, int density);
196 extern void parse_escp2 (FILE *fp_r);
197 extern void reverse_bit_order (unsigned char *buff, int n);
198 extern int rle_decode (unsigned char *inbuf, int n, int max);
199 extern void parse_canon (FILE *fp_r);
200
201 unsigned get_mask_1[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
202 unsigned get_mask_2[] = { 6, 4, 2, 0 };
203 unsigned get_mask_4[] = { 4, 0 };
204
205 static inline int
get_bits(unsigned char * p,int idx)206 get_bits(unsigned char *p, int idx)
207 {
208 /*
209 * p is a pointer to a bit stream, ordered MSb first. Extract the
210 * indexth bpp bit width field and return that value. Ignore byte
211 * boundaries.
212 */
213 int value, b;
214 unsigned addr;
215 switch (pstate.bpp)
216 {
217 case 1:
218 return (p[idx >> 3] >> (7 - (idx & 7))) & 1;
219 case 2:
220 b = get_mask_2[idx & 3];
221 return (p[idx >> 2] >> b) & 3;
222 case 4:
223 b = get_mask_4[idx & 1];
224 return (p[idx >> 1] >> b) & 0xf;
225 case 8:
226 return p[idx];
227 default:
228 addr = (idx * pstate.bpp);
229 value = 0;
230 for (b = 0; b < pstate.bpp; b++)
231 {
232 value += value;
233 value |= (p[(addr + b) >> 3] >> (7 - ((addr + b) & 7))) & 1;
234 }
235 return(value);
236 }
237 }
238
239 static unsigned clr_mask_1[] = { 0xfe, 0xfd, 0xfb, 0xf7,
240 0xef, 0xdf, 0xbf, 0x7f };
241 static unsigned clr_mask_2[] = { 0xfc, 0, 0xf3, 0, 0xcf, 0, 0x3f, 0 };
242 static unsigned clr_mask_4[] = { 0xf0, 0, 0, 0, 0xf, 0, 0, 0 };
243
244 static inline void
set_bits(unsigned char * p,int idx,int value)245 set_bits(unsigned char *p,int idx,int value)
246 {
247
248 /*
249 * p is a pointer to a bit stream, ordered MSb first. Set the
250 * indexth bpp bit width field to value value. Ignore byte
251 * boundaries.
252 */
253
254 int b;
255 switch (pstate.bpp)
256 {
257 case 1:
258 b = (7 - (idx & 7));
259 p[idx >> 3] &= clr_mask_1[b];
260 p[idx >> 3] |= value << b;
261 break;
262 case 2:
263 b = get_mask_2[idx & 3];
264 p[idx >> 2] &= clr_mask_2[b];
265 p[idx >> 2] |= value << b;
266 break;
267 case 4:
268 b = get_mask_4[idx & 1];
269 p[idx >> 1] &= clr_mask_4[b];
270 p[idx >> 1] |= value << b;
271 break;
272 case 8:
273 p[idx] = value;
274 break;
275 default:
276 for (b = pstate.bpp - 1; b >= 0; b--)
277 {
278 if (value & 1)
279 p[(idx * pstate.bpp + b) / 8] |=
280 1 << (7 - ((idx * pstate.bpp + b) % 8));
281 else
282 p[(idx * pstate.bpp + b) / 8] &=
283 ~(1 << (7 - ((idx * pstate.bpp + b) % 8)));
284 value/=2;
285 }
286 }
287 }
288
289 static float ink_colors[MAX_INKS][4] =
290 /* C(R) M(G) Y(B) K(W) */
291 {{ 0, 0, 0, 1 }, /* 0 K */
292 { 1, .1, 1, 1 }, /* 1 M */
293 { .1, 1, 1, 1 }, /* 2 C */
294 { 1, 1, .1, 1 }, /* 3 Y */
295 { 1, .7, 1, 1 }, /* 4 m */
296 { .7, 1, 1, 1 }, /* 5 c */
297 { .7, .7, .7, 1 }, /* 6 k */
298 { .7, .7, 0, 1 }, /* 7 dY */
299 { 1, 0, 0, 1 }, /* 8 R */
300 { 0, 0, 1, 1 }, /* 8 B */
301 { 1, 1, 1, 1 }, /* 10 Gloss */
302 { .8, .8, .8, 1 }, /* 11 llk */
303 { .9, .3, 0, 1 }, /* 12 Orange */
304 { 0, 0, 0, 1 }, /* 13 K */
305 { 0, 0, 0, 1 }, /* 14 K */
306 { 0, 0, 0, 1 }, /* 15 K */
307 { 0, 0, 0, 1 }, /* 16 K */
308 { 1, .1, 1, 1 }, /* 17 M */
309 { .1, 1, 1, 1 }, /* 18 C */
310 { 1, 1, .1, 1 }, /* 19 Y */
311 };
312
313 static float quadtone_inks[] = { 0.0, .5, .25, .75, .9, .8 };
314
315 static float mis_quadtone_inks[] = { 0.0, .25, .75, .5, .55, .85 };
316
317 static float bpp_shift[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
318
319 static inline void
mix_ink(ppmpixel p,int color,unsigned int amount,float * ink,quadtone_t quadtone)320 mix_ink(ppmpixel p, int color, unsigned int amount, float *ink, quadtone_t quadtone)
321 {
322 /* this is pretty crude */
323
324 if (((1 << color) & color_mask) && amount)
325 {
326 int i;
327 float size;
328
329 size = (float) amount / bpp_shift[pstate.bpp];
330 switch (quadtone)
331 {
332 case QT_QUAD:
333 for (i = 0; i < 3; i++)
334 p[i] *= (1 - size) + size * quadtone_inks[color];
335 break;
336 case QT_MIS:
337 for (i = 0; i < 3; i++)
338 p[i] *= (1 - size) + size * mis_quadtone_inks[color];
339 break;
340 default:
341 for (i = 0; i < 3; i++)
342 p[i] *= (1 - size) + size * ink[i];
343 }
344 }
345 }
346
347 void
merge_line(line_type * p,unsigned char * l,int startl,int stopl,int color)348 merge_line(line_type *p, unsigned char *l, int startl, int stopl, int color)
349 {
350
351 int i;
352 int temp, shift, height, lvalue, pvalue, oldstop;
353 int width, owidth;
354 unsigned char *tempp;
355 int reversed = 0;
356 int need_realloc = 0;
357
358 /*
359 * If we have a pixel to the left of anything previously printed,
360 * we need to expand our margins to the left. This is a bit tricky...
361 */
362 if (startl < p->startx[color])
363 {
364 temp = p->startx[color];
365 p->startx[color] = startl;
366 startl = temp;
367
368 temp = p->stopx[color];
369 p->stopx[color] = stopl;
370 stopl = temp;
371
372 tempp = p->line[color];
373 p->line[color] = l;
374 l = tempp;
375 reversed = 1;
376 }
377 shift = startl - p->startx[color];
378 height = stopl - startl + 1;
379
380 oldstop = p->stopx[color];
381 if (stopl > p->stopx[color])
382 {
383 p->stopx[color] = stopl;
384 need_realloc = 1;
385 }
386 if (need_realloc || reversed)
387 {
388 width = ((p->stopx[color] - p->startx[color] + 1) * pstate.bpp + 7) / 8;
389 owidth = ((oldstop - p->startx[color] + 1) * pstate.bpp + 7) / 8;
390 p->line[color] = stp_realloc(p->line[color], width);
391 memset((p->line[color] + owidth), 0, (width - owidth));
392 }
393 /*
394 * Can we do an empty line optimization?
395 */
396 for (i = 0; i < height; i++)
397 {
398 lvalue = get_bits(l, i);
399 if (lvalue)
400 {
401 pvalue = get_bits(p->line[color], i + shift);
402 pvalue += lvalue;
403 if (pvalue > (1 << pstate.bpp) - 1)
404 pvalue = (1 << pstate.bpp) - 1;
405 set_bits(p->line[color], i + shift, pvalue);
406 }
407 }
408 stp_free(l);
409 }
410
411 void
expand_line(unsigned char * src,unsigned char * dst,int height,int skip,int left_ignore)412 expand_line (unsigned char *src, unsigned char *dst, int height, int skip,
413 int left_ignore)
414 {
415
416 /*
417 * src is a pointer to a bit stream which is composed of fields of height
418 * bpp starting with the most significant bit of the first byte and
419 * proceeding from there with no regard to byte boundaries. For the
420 * existing Epson printers, bpp is 1 or 2, which means fields will never
421 * cross byte boundaries. However, if bpp were 3, this would undoubtedly
422 * happen. This routine will make no assumptions about bpp, and handle each
423 * bit individually. It's slow, but, it's the only way that will work in
424 * the general case of arbitrary bpp.
425 *
426 * We want to copy each field from the src to the dst, spacing the fields
427 * out every skip fields. We should ignore the first left_ignore fields
428 * pointed to by src, though.
429 */
430
431 int i;
432
433 if ((skip == 1) && !(left_ignore * pstate.bpp % 8))
434 {
435 /* the trivial case, this should be faster */
436 memcpy(dst, src + left_ignore * pstate.bpp / 8,
437 (height * pstate.bpp + 7) / 8);
438 }
439 else
440 {
441 for (i = 0; i < height; i++)
442 set_bits(dst, i * skip, get_bits(src, i + left_ignore));
443 }
444 }
445
446 int donothing;
447
448 void
write_output(FILE * fp_w,int dontwrite,int allblack)449 write_output(FILE *fp_w, int dontwrite, int allblack)
450 {
451 int c, l, p, left, right, first, last, width, height, i;
452 unsigned int amount;
453 ppmpixel *out_row;
454 int oversample = pstate.absolute_horizontal_units /
455 pstate.absolute_vertical_units;
456 if (oversample == 0)
457 oversample = 1;
458
459 fprintf(stderr, "Margins: top: %d bottom: top+%d\n", pstate.top_margin,
460 pstate.bottom_margin);
461
462 first = pstate.top_edge;
463 last = pstate.bottom_edge;
464 left = pstate.left_edge;
465 right = pstate.right_edge;
466 height = oversample * (last - first + 1);
467
468 fprintf(stderr, "Image from (%d,%d) (%.3fx%.3f) to (%d,%d) (%.3fx%.3f) size (%dx%d) (%.3fx%.3f)\n",
469 left, first - pstate.top_margin,
470 (left / (double) pstate.page_management_units),
471 (first / (double) pstate.page_management_units),
472 right, last - pstate.top_margin,
473 (right / (double) pstate.page_management_units),
474 (last / (double) pstate.page_management_units),
475 right - left + 1, last - first + 1,
476 (right - left + 1) / (double) pstate.page_management_units,
477 (last - first + 1) / (double) pstate.page_management_units);
478
479 width = right - left + 1;
480 if (width < 0)
481 width=0;
482
483 out_row = stp_malloc(sizeof(ppmpixel) * width);
484 fprintf(stderr, "Writing output...\n");
485
486 if (dontwrite)
487 return;
488 /* write out the PPM header */
489 fprintf(fp_w, "P6\n");
490 fprintf(fp_w, "%d %d\n", width, height);
491 fprintf(fp_w, "255\n");
492 for (l = first; l <= last; l++)
493 {
494 line_type *lt = page[l];
495 memset(out_row, ~0, (sizeof(ppmpixel) * width));
496 if (lt)
497 {
498 for (c = 0; c < MAX_INKS; c++)
499 {
500 int inknum = allblack ? 0 : c;
501 float *ink = ink_colors[inknum];
502 if (lt->line[c])
503 {
504 for (p = lt->startx[c]; p <= lt->stopx[c]; p++)
505 {
506 amount = get_bits(lt->line[c], p - lt->startx[c]);
507 mix_ink(out_row[p - left], c, amount, ink,
508 pstate.quadtone);
509 }
510 }
511 }
512 }
513 for (i = 0; i < oversample; i++)
514 fwrite(out_row, sizeof(ppmpixel), width, fp_w);
515 }
516 stp_free(out_row);
517 }
518
519 void
find_white(unsigned char * buff,int npix,int * left,int * right)520 find_white(unsigned char *buff,int npix, int *left, int *right)
521 {
522
523 /*
524 * If a line has white borders on either side, count the number of
525 * pixels and fill that info into left and right.
526 */
527
528 int i, j, max;
529 int words, bytes, bits, extra;
530
531 *left = *right = 0;
532 bits = npix * pstate.bpp;
533 bytes = bits / 8;
534 extra = bits % 8;
535 words = bytes / sizeof(int);
536
537 /*
538 * First, find the leftmost pixel. We first identify the word
539 * containing the byte, then the byte, and finally the pixel within
540 * the byte. It does seem like this is unnecessarily complex, perhaps?
541 */
542 max = words;
543 for (i = 0; (i < max) && (((int *)buff)[i] == 0); i++)
544 ;
545 max = (i < words) ? (i + 1) * sizeof(int) : bytes;
546
547 i *= sizeof(int); /* Convert from ints to bytes */
548 for (; (i < max) && (buff[i] == 0); i++)
549 ;
550 max = (i < bytes) ? 8 : extra;
551 for (j = 0; (j < max) && !(buff[i] & (1 << (7 - j))); j++)
552 ;
553 *left = (i * 8 + j) / pstate.bpp;
554 *right = 0;
555
556 /* if left is everything, then right is nothing */
557 if (*left == npix)
558 return;
559
560 /* right side, this is a little trickier */
561 for (i = 0; (i < extra) && !(buff[bytes] & (1 << (i + 8 - extra))); i++)
562 ;
563 if (i < extra)
564 {
565 *right = i / pstate.bpp;
566 return;
567 }
568 *right = extra; /*temporarily store right in bits to avoid rounding error*/
569
570 for (i = 0; (i < bytes % sizeof(int)) && !(buff[bytes - 1 - i]); i++)
571 ;
572 if (i < bytes % sizeof(int))
573 {
574 for (j = 0; (j < 8) && !(buff[bytes - 1 - i] & (1 << j)); j++)
575 ;
576 *right = (*right + i * 8 + j) / pstate.bpp;
577 return;
578 }
579 *right += i * 8;
580
581 for (i = 0; (i < words) && !(((int *)buff)[words - 1 - i]); i++)
582 ;
583
584 if (i < words)
585 {
586 *right += i * sizeof(int) * 8;
587 for (j = 0;
588 (j < sizeof(int)) && !(buff[(words - i) * sizeof(int) - 1 - j]);
589 j++)
590 ;
591 if (j < sizeof(int))
592 {
593 *right += j * 8;
594 max = (words - i) * sizeof(int) - 1 - j;
595 for (j = 0; (j < 8) && !(buff[max] & (1 << j)); j++)
596 ;
597 if (j < 8)
598 {
599 *right = (*right + j) / pstate.bpp;
600 return;
601 }
602 }
603 }
604 fprintf(stderr, "Warning: Reality failure. The impossible happened.\n");
605 }
606
607 int
update_page(unsigned char * buff,int buffsize,int m,int n,int color,int density)608 update_page(unsigned char *buff, /* I - pixel data */
609 int buffsize, /* I - size of buff in bytes */
610 int m, /* I - height of area in pixels */
611 int n, /* I - width of area in pixels */
612 int color, /* I - color of pixel data */
613 int density /* I - horizontal density in dpi */
614 )
615 {
616 int y, skip, oldstart, oldstop, mi = 0;
617 int left_white, right_white, width;
618 unsigned char *oldline;
619 int sep;
620
621 if ((n == 0) || (m == 0))
622 return(0); /* shouldn't happen */
623
624 skip = pstate.relative_horizontal_units / density;
625 skip *= pstate.extraskip;
626
627 if (skip == 0)
628 {
629 fprintf(stderr, "Warning! Attempting to print at %d DPI but units are "
630 "set to %d DPI.\n", density, pstate.relative_horizontal_units);
631 return(0);
632 }
633
634 if (!page)
635 {
636 fprintf(stderr,
637 "Warning! Attempting to print before setting up page!\n");
638 /*
639 * Let's hope that we've at least initialized the printer with
640 * with an ESC @ and allocate the default page. Otherwise, we'll
641 * have unpredictable results. But, that's a pretty acurate statement
642 * for a real printer, too!
643 */
644 page = (line_type **)
645 stp_zalloc((pstate.bottom_margin - pstate.top_margin) *
646 sizeof(line_type *));
647 }
648 if (pstate.printer_weave)
649 sep = 1;
650 else
651 sep = pstate.nozzle_separation;
652 for (y=pstate.yposition; y < pstate.yposition + m * sep; y += sep, mi++)
653 {
654 if (y >= pstate.bottom_margin - pstate.top_margin)
655 {
656 fprintf(stderr,
657 "Warning: Unprinter out of unpaper (limit %d, pos %d).\n",
658 pstate.bottom_margin, y);
659 return(1);
660 }
661 find_white(buff + mi * ((n * pstate.bpp + 7) / 8), n,
662 &left_white, &right_white);
663 if (left_white == n)
664 continue; /* ignore blank lines */
665 if (!(page[y]))
666 {
667 page[y] = (line_type *) stp_zalloc(sizeof(line_type));
668 if (y < pstate.top_edge)
669 pstate.top_edge = y;
670 if (y > pstate.bottom_edge)
671 pstate.bottom_edge = y;
672 }
673 if ((left_white * pstate.bpp < 8) && (skip == 1))
674 {
675 left_white=0; /* if it's just a few bits, don't bother cropping */
676 } /* unless we need to expand the line anyway */
677 if (page[y]->line[color])
678 {
679 oldline = page[y]->line[color];
680 oldstart = page[y]->startx[color];
681 oldstop = page[y]->stopx[color];
682 }
683 else
684 {
685 oldline = NULL;
686 oldstart = -1;
687 oldstop = -1;
688 }
689 page[y]->startx[color] = pstate.xposition + left_white * skip;
690 page[y]->stopx[color] =pstate.xposition + ((n - 1 - right_white) * skip);
691 if (page[y]->startx[color] < pstate.left_edge)
692 pstate.left_edge = page[y]->startx[color];
693 if (page[y]->stopx[color] > pstate.right_edge)
694 pstate.right_edge = page[y]->stopx[color];
695 width = page[y]->stopx[color] - page[y]->startx[color];
696 page[y]->line[color] =
697 stp_zalloc(((width * skip + 1) * pstate.bpp + 7) / 8);
698 expand_line(buff + mi * ((n * pstate.bpp + 7) / 8), page[y]->line[color],
699 width+1, skip, left_white);
700 if (oldline)
701 merge_line(page[y], oldline, oldstart, oldstop, color);
702 }
703 if (n)
704 pstate.xposition += (n - 1) * skip + 1;
705 return(0);
706 }
707
708 #define get1(error) \
709 do \
710 { \
711 if (!(global_count = fread(&ch, 1, 1, fp_r))) \
712 { \
713 fprintf(stderr, "%s at %d (%x), read %d", \
714 error, global_counter, global_counter, global_count); \
715 eject = 1; \
716 continue; \
717 } \
718 else \
719 global_counter += global_count; \
720 } while (0)
721
722 #define get2(error) \
723 do \
724 { \
725 if (!(global_count = fread(minibuf, 1, 2, fp_r))) \
726 { \
727 fprintf(stderr, "%s at %d (%x), read %d", \
728 error, global_counter, global_counter, global_count); \
729 eject = 1; \
730 continue; \
731 } \
732 else \
733 { \
734 global_counter += global_count; \
735 sh = minibuf[0] + minibuf[1] * 256; \
736 } \
737 } while (0)
738
739 #define getn(n,error) \
740 do \
741 { \
742 if (!(global_count = fread(buf, 1, n, fp_r))) \
743 { \
744 fprintf(stderr, "%s at %d (%x), read %d", \
745 error, global_counter, global_counter, global_count); \
746 eject = 1; \
747 continue; \
748 } \
749 else \
750 global_counter += global_count; \
751 } while (0)
752
753 #define getnoff(n,offset,error) \
754 do \
755 { \
756 if (!(global_count = fread(buf + offset, 1, n, fp_r))) \
757 { \
758 fprintf(stderr, "%s at %d (%x), read %d", \
759 error, global_counter, global_counter, global_count); \
760 eject = 1; \
761 continue; \
762 } \
763 else \
764 global_counter += global_count; \
765 } while (0)
766
767 static void
parse_escp2_data(FILE * fp_r)768 parse_escp2_data(FILE *fp_r)
769 {
770 int i, m = 0, n = 0, c = 0;
771 int currentcolor = 0;
772 int density = 0;
773 int bandsize;
774 switch (ch)
775 {
776 case 'i':
777 get1("Error reading color.\n");
778 currentcolor = seqcolor(ch);
779 get1("Error reading compression mode!\n");
780 c = ch;
781 get1("Error reading bpp!\n");
782 if (ch != pstate.bpp)
783 {
784 fprintf(stderr, "Warning! Color depth altered by ESC i.\n");
785 pstate.bpp=ch;
786 }
787 if (pstate.bpp > 2)
788 fprintf(stderr, "Warning! Excessively deep color detected.\n");
789 if (pstate.bpp == 0)
790 fprintf(stderr, "Warning! Zero bit pixel depth detected.\n");
791 get2("Error reading number of horizontal dots!\n");
792 n = (unsigned) sh * 8 / pstate.bpp;
793 get2("Error reading number of vertical dots!\n");
794 m = (unsigned) sh;
795 density = pstate.horizontal_spacing;
796 break;
797 case '.':
798 get1("Error reading compression mode!\n");
799 c=ch;
800 if (c > 2)
801 {
802 fprintf(stderr,"Warning! Unknown compression mode.\n");
803 break;
804 }
805 get1("Error reading vertical density!\n");
806 /* What should we do with the vertical density here??? */
807 get1("Error reading horizontal density!\n");
808 density=3600/ch;
809 get1("Error reading number of vertical dots!\n");
810 m=ch;
811 get2("Error reading number of horizontal dots!\n");
812 n=sh;
813 currentcolor=pstate.current_color;
814 break;
815 }
816 bandsize = m * ((n * pstate.bpp + 7) / 8);
817 if (valid_bufsize < bandsize)
818 {
819 buf = stp_realloc(buf, bandsize);
820 valid_bufsize = bandsize;
821 }
822 switch (c)
823 {
824 case 0: /* uncompressed */
825 bufsize = bandsize;
826 getn(bufsize,"Error reading raster data!\n");
827 update_page(buf, bufsize, m, n, currentcolor, density);
828 break;
829 case 1: /* run length encoding */
830 i = 0;
831 while (!eject && (i < bandsize))
832 {
833 get1("Error reading global_counter!\n");
834 if (ch < 128)
835 {
836 bufsize = ch + 1;
837 getnoff(bufsize, i, "Error reading RLE raster data!\n");
838 }
839 else
840 {
841 bufsize = 257 - (unsigned int) ch;
842 get1("Error reading compressed RLE raster data!\n");
843 memset(buf + i, ch, bufsize);
844 }
845 i += bufsize;
846 }
847 if (i != bandsize)
848 {
849 fprintf(stderr, "Error decoding RLE data.\n");
850 fprintf(stderr, "Total bufsize %d, expected %d\n",
851 i, bandsize);
852 eject = 1;
853 }
854 else
855 update_page(buf, i, m, n, currentcolor, density);
856 break;
857 case 2: /* TIFF compression */
858 fprintf(stderr, "TIFF mode not yet supported!\n");
859 /* FIXME: write TIFF stuff */
860 break;
861 default: /* unknown */
862 fprintf(stderr, "Unknown compression mode %d.\n", c);
863 break;
864 }
865 }
866
867 static void
parse_escp2_extended(FILE * fp_r)868 parse_escp2_extended(FILE *fp_r)
869 {
870 int unit_base;
871 int i;
872
873 get1("Corrupt file. Incomplete extended command.\n");
874 if (eject)
875 return;
876 get2("Corrupt file. Error reading buffer size.\n");
877 bufsize = sh;
878 getn(bufsize, "Corrupt file. Error reading command payload.\n");
879 /* fprintf(stderr,"Command %X bufsize %d.\n",ch,bufsize); */
880 switch (ch)
881 {
882 case 'R':
883 if (bufsize == 8 && memcmp(buf, "\0REMOTE1", 8) == 0)
884 {
885 int rc1 = 0, rc2 = 0;
886 /* Remote mode 1 */
887 do
888 {
889 get1("Corrupt file. Error in remote mode.\n");
890 rc1 = ch;
891 get1("Corrupt file. Error reading remote mode command.\n");
892 rc2 = ch;
893 get2("Corrupt file. Error reading remote mode command size.\n");
894 bufsize = sh;
895 if (bufsize)
896 getn(bufsize, "Corrupt file. Error reading remote mode command parameters.\n");
897 if (rc1 == 0x1b && rc2 == 0) /* ignore quietly */
898 ;
899 else
900 fprintf(stderr,
901 "Remote mode command `%c%c' ignored.\n",
902 rc1,rc2);
903 }
904 while (!eject && !(rc1 == 0x1b && rc2 == 0));
905 }
906 else
907 {
908 /*
909 fprintf(stderr,"Warning! Commands in unrecognised remote mode %s ignored.\n", buf);
910 */
911 do
912 {
913 while((!eject) && (ch!=0x1b))
914 get1("Error in remote mode.\n");
915 get1("Error reading remote mode terminator\n");
916 }
917 while ((!eject) && (ch != 0));
918 }
919 break;
920 case 'G': /* select graphics mode */
921 /* FIXME: this is supposed to have more side effects */
922 pstate.printer_weave = 0;
923 pstate.dotsize = 0;
924 pstate.bpp = 1;
925 break;
926 case 'U': /* set page units */
927 switch (bufsize)
928 {
929 case 1:
930 pstate.page_management_units =
931 pstate.absolute_horizontal_units =
932 pstate.relative_horizontal_units =
933 pstate.relative_vertical_units =
934 pstate.horizontal_spacing =
935 pstate.absolute_vertical_units = 3600 / buf[0];
936 if (pstate.page_management_units < 720)
937 pstate.extraskip = 1;
938 fprintf(stderr, "Setting units to 1/%d\n",
939 pstate.absolute_horizontal_units);
940 break;
941 case 5:
942 unit_base = buf[4] * 256 + buf[3];
943 pstate.extraskip=1;
944 pstate.page_management_units= unit_base / buf[0];
945 pstate.relative_vertical_units =
946 pstate.absolute_vertical_units = unit_base/buf[1];
947 pstate.relative_horizontal_units =
948 pstate.horizontal_spacing =
949 pstate.absolute_horizontal_units = unit_base / buf[2];
950 fprintf(stderr, "Setting page management units to 1/%d\n",
951 pstate.page_management_units);
952 fprintf(stderr, "Setting vertical units to 1/%d\n",
953 pstate.relative_vertical_units);
954 fprintf(stderr, "Setting horizontal units to 1/%d\n",
955 pstate.relative_horizontal_units);
956 break;
957 }
958 break;
959 case 'i': /* set printer weave mode */
960 if (bufsize != 1)
961 fprintf(stderr,"Malformed printer weave setting command.\n");
962 else
963 pstate.printer_weave = buf[0] % 0x30;
964 break;
965 case 'e': /* set dot size */
966 if ((bufsize != 2) || (buf[0] != 0))
967 fprintf(stderr,"Malformed dotsize setting command.\n");
968 else if (pstate.got_graphics)
969 fprintf(stderr,"Changing dotsize while printing not supported.\n");
970 else
971 {
972 pstate.dotsize = buf[1];
973 if (pstate.dotsize > 0x10)
974 pstate.bpp = 2;
975 else
976 pstate.bpp = 1;
977 }
978 fprintf(stderr, "Setting dot size to 0x%x (bits %d)\n",
979 pstate.dotsize, pstate.bpp);
980 break;
981 case 'c': /* set page format */
982 if (page)
983 {
984 fprintf(stderr,"Setting the page format in the middle of printing a page is not supported.\n");
985 break;
986 }
987 switch (bufsize)
988 {
989 case 4:
990 pstate.top_margin = buf[1] * 256 + buf[0];
991 pstate.bottom_margin = buf[3] * 256 + buf[2];
992 break;
993 case 8:
994 pstate.top_margin = (buf[3] << 24) +
995 (buf[2] << 16) + (buf[1] << 8) + buf[0];
996 pstate.bottom_margin = (buf[7] << 24) +
997 (buf[6] << 16) + (buf[5] << 8) + buf[4];
998 break;
999 default:
1000 fprintf(stderr,"Malformed page format. Ignored.\n");
1001 }
1002 pstate.yposition = 0;
1003 if (pstate.top_margin + pstate.bottom_margin > pstate.page_height)
1004 pstate.page_height = pstate.top_margin + pstate.bottom_margin;
1005 fprintf(stderr, "Setting top margin to %d (%.3f)\n",
1006 pstate.top_margin,
1007 (double) pstate.top_margin / pstate.page_management_units);
1008 fprintf(stderr, "Setting bottom margin to %d (%.3f)\n",
1009 pstate.bottom_margin,
1010 (double) pstate.bottom_margin / pstate.page_management_units);
1011 page = (line_type **)
1012 stp_zalloc((pstate.bottom_margin - pstate.top_margin) *
1013 sizeof(line_type *));
1014 break;
1015 case 'V': /* set absolute vertical position */
1016 i = 0;
1017 switch (bufsize)
1018 {
1019 case 4:
1020 i = (buf[2] << 16) + (buf[3]<<24);
1021 /* FALLTHROUGH */
1022 case 2:
1023 i += (buf[0]) + (256 * buf[1]);
1024 if (pstate.top_margin + i * (pstate.relative_vertical_units /
1025 pstate.absolute_vertical_units) >=
1026 pstate.yposition)
1027 pstate.yposition = i * (pstate.relative_vertical_units /
1028 pstate.absolute_vertical_units) +
1029 pstate.top_margin;
1030 else
1031 fprintf(stderr, "Warning: Setting Y position in negative direction ignored\n");
1032 break;
1033 default:
1034 fprintf(stderr, "Malformed absolute vertical position set.\n");
1035 }
1036 if (pstate.yposition > pstate.bottom_margin - pstate.top_margin)
1037 {
1038 fprintf(stderr,
1039 "Warning! Printer head moved past bottom margin. Dumping output and exiting.\n");
1040 eject = 1;
1041 }
1042 break;
1043 case 'v': /* set relative vertical position */
1044 i = 0;
1045 switch (bufsize)
1046 {
1047 case 4:
1048 i = (buf[2] << 16) + (buf[3] << 24);
1049 /* FALLTHROUGH */
1050 case 2:
1051 i += (buf[0]) + (256 * buf[1]);
1052 if (unweave)
1053 i = pstate.nozzles;
1054 pstate.yposition+=i;
1055 break;
1056 default:
1057 fprintf(stderr,"Malformed relative vertical position set.\n");
1058 }
1059 if (pstate.yposition > pstate.bottom_margin - pstate.top_margin)
1060 {
1061 fprintf(stderr,"Warning! Printer head moved past bottom margin. Dumping output and exiting.\n");
1062 eject = 1;
1063 }
1064 break;
1065 case 'K':
1066 if (bufsize!=2)
1067 fprintf(stderr,"Malformed monochrome/color mode selection.\n");
1068 else if (buf[0])
1069 fprintf(stderr,"Non-zero first byte in monochrome selection command. Ignored.\n");
1070 else if (buf[0] > 0x02)
1071 fprintf(stderr,"Unknown color mode 0x%X.\n",buf[1]);
1072 else
1073 pstate.monomode = buf[1];
1074
1075 break;
1076 case 's': /* Set print speed */
1077 case 'm': /* Set paper type */
1078 break;
1079 case 'S': /* set paper dimensions */
1080 switch (bufsize)
1081 {
1082 case 4:
1083 i = (buf[1] << 16) + buf[0];
1084 fprintf(stderr, "Setting paper width to %d (%.3f)\n", i,
1085 (double) i / pstate.page_management_units);
1086 i = (buf[3] << 16) + buf[2];
1087 fprintf(stderr, "Setting paper height to %d (%.3f)\n", i,
1088 (double) i / pstate.page_management_units);
1089 break;
1090 case 8:
1091 i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
1092 fprintf(stderr, "Setting paper width to %d (%.3f)\n", i,
1093 (double) i / pstate.page_management_units);
1094 i = (buf[7] << 24) + (buf[6] << 16) + (buf[5] << 8) + buf[4];
1095 fprintf(stderr, "Setting paper height to %d (%.3f)\n", i,
1096 (double) i / pstate.page_management_units);
1097 break;
1098 default:
1099 fprintf(stderr, "Invalid set paper dimensions command.\n");
1100 }
1101 break;
1102 case 'D':
1103 if (bufsize != 4)
1104 fprintf(stderr, "Malformed set resolution request.\n");
1105 else
1106 {
1107 int res_base = (256 * buf[1]) + buf[0];
1108 pstate.nozzle_separation =
1109 pstate.absolute_vertical_units / (res_base / buf[2]);
1110 pstate.horizontal_spacing = res_base / buf[3];
1111 fprintf(stderr, "Setting nozzle separation to %d\n",
1112 pstate.nozzle_separation);
1113 fprintf(stderr, "Setting vertical spacing to 1/%d\n",
1114 res_base / buf[2]);
1115 fprintf(stderr, "Setting horizontal spacing to 1/%d\n",
1116 pstate.horizontal_spacing);
1117 }
1118 break;
1119 case 'r': /* select color */
1120 if (bufsize!=2)
1121 fprintf(stderr,"Malformed color selection request.\n");
1122 else
1123 {
1124 sh = 256 * buf[0] + buf[1];
1125 if ((buf[1] > 4) || (buf[1] == 3) || (buf[0] > 1) ||
1126 (buf[0] && (buf[1]==0)))
1127 fprintf(stderr,"Invalid color 0x%X.\n",sh);
1128 else
1129 pstate.current_color = seqcolor(sh);
1130 }
1131 break;
1132 case '\\': /* set relative horizontal position */
1133 case '/':
1134 i = (buf[3] << 8) + buf[2];
1135 if (pstate.xposition + i < 0)
1136 {
1137 fprintf(stderr,"Warning! Attempt to move to -X region ignored.\n");
1138 fprintf(stderr," Command: ESC ( %c %X %X %X %X Original "
1139 "position: %d\n",
1140 ch, buf[0], buf[1], buf[2], buf[3], pstate.xposition);
1141 }
1142 else /* FIXME: Where is the right margin??? */
1143 pstate.xposition+=i;
1144 break;
1145 case '$': /* set absolute horizontal position */
1146 i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
1147 pstate.xposition = i * (pstate.relative_horizontal_units /
1148 pstate.absolute_horizontal_units);
1149 break;
1150 case 'C': /* set page height */
1151 switch (bufsize)
1152 {
1153 case 2:
1154 i = (buf[1] << 8) | buf[0];
1155 fprintf(stderr, "Setting page height to %d (%.3f)\n", i,
1156 (double) i / pstate.page_management_units);
1157 break;
1158 case 4:
1159 i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
1160 fprintf(stderr, "Setting page height to %d (%.3f)\n", i,
1161 (double) i / pstate.page_management_units);
1162 break;
1163 default:
1164 fprintf(stderr, "Invalid set page height command.\n");
1165 }
1166 break;
1167 default:
1168 fprintf(stderr,"Warning: Unknown command ESC ( 0x%X at 0x%08X.\n",
1169 ch, global_counter - 5 - bufsize);
1170 }
1171 }
1172
1173 static void
parse_escp2_command(FILE * fp_r)1174 parse_escp2_command(FILE *fp_r)
1175 {
1176 get1("Corrupt file. No command found.\n");
1177 switch (ch)
1178 {
1179 case 1: /* Magic EJL stuff to get USB port working */
1180 fprintf(stderr,"Ignoring EJL commands.\n");
1181 do
1182 {
1183 get1("Error reading EJL commands.\n");
1184 }
1185 while (!eject && ch != 0x1b);
1186 if (eject)
1187 break;
1188 get1("Expect esc-NULL to close EJL command.\n");
1189 if (ch != 0x40)
1190 fprintf(stderr, "Expect esc-NULL to close EJL command.\n");
1191 break;
1192 case '@': /* initialize printer */
1193 if (page)
1194 eject = 1;
1195 else
1196 {
1197 pstate.unidirectional = 0;
1198 pstate.printer_weave = 0;
1199 pstate.dotsize = 0;
1200 pstate.bpp = 1;
1201 pstate.page_management_units = 360;
1202 pstate.relative_horizontal_units = 180;
1203 pstate.absolute_horizontal_units = 60;
1204 pstate.relative_vertical_units = 360;
1205 pstate.absolute_vertical_units = 360;
1206 pstate.top_margin = 120;
1207 pstate.bottom_margin =
1208 pstate.page_height = 22 * 360; /* 22 inches is default ??? */
1209 pstate.monomode = 0;
1210 pstate.left_edge = INT_MAX;
1211 pstate.right_edge = 0;
1212 pstate.top_edge = INT_MAX;
1213 pstate.bottom_edge = 0;
1214 }
1215 break;
1216 case 'U': /* turn unidirectional mode on/off */
1217 get1("Error reading unidirectionality.\n");
1218 if ((ch <= 2) || ((ch >= 0x30) && (ch <= 0x32)))
1219 pstate.unidirectional=ch;
1220 break;
1221 case 'i': /* transfer raster image */
1222 case '.':
1223 pstate.got_graphics = 1;
1224 parse_escp2_data(fp_r);
1225 break;
1226 case '\\': /* set relative horizontal position */
1227 get2("Error reading relative horizontal position.\n");
1228 if (pstate.xposition + (signed short)sh < 0)
1229 {
1230 fprintf(stderr, "Warning! Move off left of region ignored.\n");
1231 fprintf(stderr, " Command: ESC %c %X %X "
1232 "Original Position: %d\n",
1233 ch, minibuf[0], minibuf[1], pstate.xposition);
1234 }
1235 else /* FIXME: Where is the right margin??? */
1236 pstate.xposition += (signed short)sh;
1237 break;
1238 case '$': /* set absolute horizontal position */
1239 get2("Error reading absolute horizontal position.\n");
1240 pstate.xposition = sh * (pstate.relative_horizontal_units /
1241 pstate.absolute_horizontal_units);
1242 break;
1243 case 0x0: /* Exit remote mode */
1244 get2("Error exiting remote mode.\n");
1245 break;
1246 case 0x6: /* flush buffers */
1247 /* Woosh. Consider them flushed. */
1248 break;
1249 case 0x19: /* control paper loading */
1250 get1("Error reading paper control byte.\n");
1251 /* paper? */
1252 break;
1253 case 'r': /* select printing color */
1254 get1("Error reading color.\n");
1255 if ((ch <= 4) && (ch != 3))
1256 pstate.current_color = seqcolor(ch);
1257 else
1258 fprintf(stderr, "Invalid color %d.\n", ch);
1259 break;
1260 case '(': /* commands with a payload */
1261 parse_escp2_extended(fp_r);
1262 break;
1263 default:
1264 fprintf(stderr,"Warning: Unknown command ESC 0x%X at 0x%08X.\n",ch,global_counter-2);
1265 }
1266 }
1267
1268 void
parse_escp2(FILE * fp_r)1269 parse_escp2(FILE *fp_r)
1270 {
1271 global_counter = 0;
1272
1273 while ((!eject) && (fread(&ch, 1, 1, fp_r)))
1274 {
1275 global_counter++;
1276 switch (ch)
1277 {
1278 case 0xd: /* carriage return */
1279 pstate.xposition = 0;
1280 break;
1281 case 0xc: /* form feed */
1282 eject = 1;
1283 break;
1284 case 0x0:
1285 break;
1286 case 0x1b: /* Command! */
1287 parse_escp2_command(fp_r);
1288 break;
1289 default:
1290 fprintf(stderr,
1291 "Corrupt file? No ESC found. Found: %02X at 0x%08X\n",
1292 ch, global_counter-1);
1293 break;
1294 }
1295 }
1296 }
1297
1298
1299 /* 'reverse_bit_order'
1300 *
1301 * reverse the bit order in an array of bytes - does not reverse byte order!
1302 */
1303 void
reverse_bit_order(unsigned char * buff,int n)1304 reverse_bit_order(unsigned char *buff, int n)
1305 {
1306 int i;
1307 unsigned char a;
1308 if (!n) return; /* nothing to do */
1309
1310 for (i= 0; i<n; i++) {
1311 a= buff[i];
1312 buff[i]=
1313 (a & 0x01) << 7 |
1314 (a & 0x02) << 5 |
1315 (a & 0x04) << 3 |
1316 (a & 0x08) << 1 |
1317 (a & 0x10) >> 1 |
1318 (a & 0x20) >> 3 |
1319 (a & 0x40) >> 5 |
1320 (a & 0x80) >> 7;
1321 }
1322 }
1323
1324 /* 'rle_decode'
1325 *
1326 * run-length-decodes a given buffer of height "n"
1327 * and stores the result in the same buffer
1328 * not exceeding a size of "max" bytes.
1329 */
1330 int
rle_decode(unsigned char * inbuf,int n,int max)1331 rle_decode(unsigned char *inbuf, int n, int max)
1332 {
1333 unsigned char outbuf[1440*3];
1334 signed char *ib= (signed char *)inbuf;
1335 signed char cnt;
1336 int num;
1337 int i= 0, j;
1338 int o= 0;
1339
1340 #ifdef DEBUG_RLE
1341 fprintf(stderr,"input: %d\n",n);
1342 #endif
1343 if (n<=0) return 0;
1344 if (max>1440*3) max= 1440*3; /* FIXME: this can be done much better! */
1345
1346 while (i<n && o<max) {
1347 cnt= ib[i];
1348 if (cnt<0) {
1349 /* cnt identical bytes */
1350 /* fprintf(stderr,"rle 0x%02x = %4d = %4d\n",cnt&0xff,cnt,1-cnt); */
1351 num= 1-cnt;
1352 /* fprintf (stderr,"+%6d ",num); */
1353 for (j=0; j<num && o+j<max; j++) outbuf[o+j]= inbuf[i+1];
1354 o+= num;
1355 i+= 2;
1356 } else {
1357 /* cnt individual bytes */
1358 /* fprintf(stderr,"raw 0x%02x = %4d = %4d\n",cnt&0xff,cnt,cnt + 1); */
1359 num= cnt+1;
1360 /* fprintf (stderr,"*%6d ",num); */
1361 for (j=0; j<num && o+j<max; j++) outbuf[o+j]= inbuf[i+j+1];
1362 o+= num;
1363 i+= num+1;
1364 }
1365 }
1366 if (o>=max) {
1367 fprintf(stderr,"Warning: rle decompression exceeds output buffer.\n");
1368 return 0;
1369 }
1370 /* copy decompressed data to inbuf: */
1371 memset(inbuf,0,max-1);
1372 memcpy(inbuf,outbuf,o);
1373 #ifdef DEBUG_RLE
1374 fprintf(stderr,"output: %d\n",o);
1375 #endif
1376 return o;
1377 }
1378
1379 void
parse_canon(FILE * fp_r)1380 parse_canon(FILE *fp_r)
1381 {
1382
1383 int m=0;
1384 int currentcolor,currentbpp,density,l_eject;
1385 int cmdcounter;
1386 int delay_c=0, delay_m=0, delay_y=0, delay_C=0,
1387 delay_M=0, delay_Y=0, delay_K=0, currentdelay=0;
1388
1389 global_counter=0;
1390
1391 page= 0;
1392 l_eject=pstate.got_graphics=currentbpp=currentcolor=density=0;
1393 while ((!l_eject)&&(fread(&ch,1,1,fp_r))){
1394 global_counter++;
1395 if (ch==0xd) { /* carriage return */
1396 pstate.xposition=0;
1397 #ifdef DEBUG_CANON
1398 fprintf(stderr,"< ");
1399 #endif
1400 continue;
1401 }
1402 if (ch==0xc) { /* form feed */
1403 l_eject=1;
1404 continue;
1405 }
1406 if (ch=='B') {
1407 fgets((char *)buf,sizeof(buf),fp_r);
1408 global_counter+= strlen((char *)buf);
1409 if (!strncmp((char *)buf,"JLSTART",7)) {
1410 while (strncmp((char *)buf,"BJLEND",6)) {
1411 fgets((char *)buf,sizeof(buf),fp_r);
1412 global_counter+= strlen((char *)buf);
1413 fprintf(stderr,"got BJL-plaintext-command %s",buf);
1414 }
1415 } else {
1416 fprintf(stderr,"Error: expected BJLSTART but got B%s",buf);
1417 }
1418 global_counter= ftell(fp_r);
1419 continue;
1420 }
1421 if (ch!=0x1b) {
1422 fprintf(stderr,"Corrupt file? No ESC found. Found: %02X at 0x%08X\n",
1423 ch,global_counter-1);
1424 continue;
1425 }
1426 get1("Corrupt file. No command found.\n");
1427 /* fprintf(stderr,"Got a %X.\n",ch); */
1428 switch (ch) {
1429 case '[': /* 0x5b initialize printer */
1430 get1("Error reading CEM-code.\n");
1431 cmdcounter= global_counter;
1432 get2("Error reading CEM-data size.\n");
1433 getn(sh,"Error reading CEM-data.\n");
1434
1435 if (ch=='K') /* 0x4b */ {
1436 if (sh!=2 || buf[0]!=0x00 ) {
1437 fprintf(stderr,"Error initializing printer with ESC [ K\n");
1438 l_eject=1;
1439 continue;
1440 }
1441 if (page) {
1442 l_eject=1;
1443 continue;
1444 } else {
1445 pstate.unidirectional=0;
1446 pstate.printer_weave=0;
1447 pstate.dotsize=0;
1448 pstate.bpp=1;
1449 pstate.page_management_units=360;
1450 pstate.relative_horizontal_units=180;
1451 pstate.absolute_horizontal_units=60;
1452 pstate.relative_vertical_units=360;
1453 pstate.absolute_vertical_units=360;
1454 pstate.top_margin=120;
1455 pstate.bottom_margin=
1456 pstate.page_height=22*360; /* 22 inches is default ??? */
1457 pstate.monomode=0;
1458 pstate.xposition= 0;
1459 pstate.yposition= 0;
1460 pstate.left_edge = INT_MAX;
1461 pstate.right_edge = 0;
1462 pstate.top_edge = INT_MAX;
1463 pstate.bottom_edge = 0;
1464 fprintf(stderr,"canon: init printer\n");
1465 }
1466 } else {
1467 fprintf(stderr,"Warning: Unknown command ESC %c 0x%X at 0x%08X.\n",
1468 0x5b,ch,global_counter);
1469 }
1470 break;
1471
1472 case '@': /* 0x40 */
1473 l_eject=1;
1474 break;
1475
1476 case '(': /* 0x28 */
1477 get1("Corrupt file. Incomplete extended command.\n");
1478 cmdcounter= global_counter;
1479 get2("Corrupt file. Error reading buffer size.\n");
1480 bufsize=sh;
1481 getn(bufsize,"Corrupt file. Error reading data buffer.\n");
1482
1483 switch(ch) {
1484 /* Color Codes:
1485 color Epson1 Epson2 Sequential
1486 Black 0 0 0 K
1487 Magenta 1 1 1 M
1488 Cyan 2 2 2 C
1489 Yellow 4 4 3 Y
1490 L.Mag. 17 257 4 m
1491 L.Cyan 18 258 5 c
1492 L.Yellow NA NA 6 y
1493 */
1494 case 'A': /* 0x41 - transfer graphics data */
1495 switch (*buf) {
1496 case 'K': currentcolor= 0; currentdelay= delay_K; break;
1497 case 'M': currentcolor= 1; currentdelay= delay_M; break;
1498 case 'C': currentcolor= 2; currentdelay= delay_C; break;
1499 case 'Y': currentcolor= 3; currentdelay= delay_Y; break;
1500 case 'm': currentcolor= 4; currentdelay= delay_m; break;
1501 case 'c': currentcolor= 5; currentdelay= delay_c; break;
1502 case 'y': currentcolor= 6; currentdelay= delay_y; break;
1503 default:
1504 fprintf(stderr,"Error: unsupported color type 0x%02x.\n",*buf);
1505 /* exit(-1); */
1506 }
1507 pstate.current_color= currentcolor;
1508 m= rle_decode(buf+1,bufsize-1,sizeof(buf)-1);
1509 /* reverse_bit_order(buf+1,m); */
1510 pstate.yposition+= currentdelay;
1511 if (m) update_page(buf+1,m,1,(m*8)/pstate.bpp,currentcolor,
1512 pstate.absolute_horizontal_units);
1513 pstate.yposition-= currentdelay;
1514 #ifdef DEBUG_CANON
1515 fprintf(stderr,"%c:%d>%d ",*buf,sh-1,m);
1516 #endif
1517 break;
1518 case 'a': /* 0x61 - turn something on/off */
1519 break;
1520 case 'b': /* 0x62 - turn something else on/off */
1521 break;
1522 case 'c': /* 0x63 - some information about the print job */
1523 break;
1524 case 'd': /* 0x64 - set resolution */
1525 if (page) {
1526 fprintf(stderr,"Setting the page format in the middle of printing "
1527 "a page is not supported.\n");
1528 exit(-1);
1529 }
1530 pstate.relative_vertical_units=
1531 pstate.absolute_vertical_units=
1532 buf[1]+256*buf[0];
1533 pstate.relative_horizontal_units=
1534 pstate.absolute_horizontal_units=
1535 buf[3]+256*buf[2];
1536 pstate.bottom_margin= pstate.relative_vertical_units* 22;
1537 /* FIXME: replace with real page height */
1538 fprintf(stderr,"canon: res is %d x %d dpi\n",
1539 pstate.relative_horizontal_units,
1540 pstate.relative_vertical_units);
1541
1542 page= (line_type **) stp_zalloc(pstate.bottom_margin *
1543 sizeof(line_type *));
1544 break;
1545 case 'e': /* 0x65 - vertical head movement */
1546 pstate.yposition+= (buf[1]+256*buf[0]);
1547 #ifdef DEBUG_CANON
1548 fprintf(stderr,"\n");
1549 #endif
1550 break;
1551 case 'l': /* 0x6c - some more information about the print job*/
1552 break;
1553 case 'm': /* 0x6d - used printheads and other things */
1554 break;
1555 case 'p': /* 0x70 - set printable area */
1556 break;
1557 case 'q': /* 0x71 - turn yet something else on/off */
1558 break;
1559 case 't': /* 0x74 - contains bpp and line delaying*/
1560 pstate.bpp= buf[0];
1561 fprintf(stderr,"canon: using %d bpp\n",pstate.bpp);
1562 if (buf[1]&0x04) {
1563 delay_y= 0;
1564 delay_m= 0;
1565 delay_c= 0;
1566 delay_Y= 0;
1567 delay_M= delay_Y+112;
1568 delay_C= delay_M+112;
1569 delay_K= delay_C+112;
1570 fprintf(stderr,"canon: using line delay code\n");
1571 }
1572 break;
1573
1574 default:
1575 fprintf(stderr,"Warning: Unknown command ESC ( 0x%X at 0x%08X.\n",
1576 ch,global_counter);
1577 }
1578 break;
1579
1580 default:
1581 fprintf(stderr,"Warning: Unknown command ESC 0x%X at 0x%08X.\n",
1582 ch,global_counter-2);
1583 }
1584 }
1585 }
1586
1587 int
main(int argc,char * argv[])1588 main(int argc,char *argv[])
1589 {
1590
1591 int arg;
1592 char *s;
1593 char *UNPRINT;
1594 FILE *fp_r, *fp_w;
1595 int force_extraskip = -1;
1596 int no_output = 0;
1597 int all_black = 0;
1598
1599 unweave = 0;
1600 pstate.nozzle_separation = 6;
1601 fp_r = fp_w = NULL;
1602 for (arg = 1; arg < argc; arg++)
1603 {
1604 if (argv[arg][0] == '-')
1605 {
1606 switch (argv[arg][1])
1607 {
1608 case 0:
1609 if (fp_r)
1610 fp_w = stdout;
1611 else
1612 fp_r = stdin;
1613 break;
1614 case 'h':
1615 fprintf(stderr, "Usage: %s [-m mask] [-n nozzle_sep] [-s extra] [-b] [-q] [-Q] [-M] [-u] [in [out]]\n", argv[0]);
1616 fprintf(stderr, " -m mask Color mask to unprint\n");
1617 fprintf(stderr, " -n nozzle_sep Nozzle separation in vertical units for old printers\n");
1618 fprintf(stderr, " -s extra Extra feed requirement for old printers (typically 1)\n");
1619 fprintf(stderr, " -b Unprint everything in black\n");
1620 fprintf(stderr, " -q Don't produce output\n");
1621 fprintf(stderr, " -Q Assume quadtone inks\n");
1622 fprintf(stderr, " -M Assume MIS quadtone inks\n");
1623 fprintf(stderr, " -u Unweave\n");
1624 return 1;
1625 case 'm':
1626 if (argv[arg][2])
1627 {
1628 s = argv[arg] + 2;
1629 }
1630 else
1631 {
1632 if (argc <= arg + 1)
1633 {
1634 fprintf(stderr, "Missing color mask\n");
1635 exit(-1);
1636 }
1637 else
1638 {
1639 s = argv[++arg];
1640 }
1641 }
1642 if (!sscanf(s, "%x", &color_mask))
1643 {
1644 fprintf(stderr,"Error parsing mask\n");
1645 exit(-1);
1646 }
1647 break;
1648 case 'n':
1649 if (argv[arg][2])
1650 {
1651 s = argv[arg] + 2;
1652 }
1653 else
1654 {
1655 if (argc <= arg + 1)
1656 {
1657 fprintf(stderr, "Missing nozzle separation\n");
1658 exit(-1);
1659 }
1660 else
1661 {
1662 s = argv[++arg];
1663 }
1664 }
1665 if (!sscanf(s, "%d", &pstate.nozzle_separation))
1666 {
1667 fprintf(stderr,"Error parsing nozzle separation\n");
1668 exit(-1);
1669 }
1670 break;
1671 case 's':
1672 if (argv[arg][2])
1673 {
1674 s = argv[arg] + 2;
1675 }
1676 else
1677 {
1678 if (argc <= arg + 1)
1679 {
1680 fprintf(stderr,"Missing extra skip\n");
1681 exit(-1);
1682 }
1683 else
1684 {
1685 s = argv[++arg];
1686 }
1687 }
1688 if (!sscanf(s, "%d", &force_extraskip))
1689 {
1690 fprintf(stderr, "Error parsing extra skip\n");
1691 exit(-1);
1692 }
1693 break;
1694 case 'b':
1695 all_black = 1;
1696 break;
1697 case 'q':
1698 no_output = 1;
1699 break;
1700 case 'Q':
1701 pstate.quadtone = QT_QUAD;
1702 break;
1703 case 'M':
1704 pstate.quadtone = QT_MIS;
1705 break;
1706 case 'u':
1707 unweave = 1;
1708 break;
1709 }
1710 }
1711 else
1712 {
1713 if (fp_r)
1714 {
1715 if (!(fp_w = fopen(argv[arg],"w")))
1716 {
1717 perror("Error opening output file");
1718 exit(-1);
1719 }
1720 }
1721 else
1722 {
1723 if (!(fp_r = fopen(argv[arg],"r")))
1724 {
1725 perror("Error opening input file");
1726 exit(-1);
1727 }
1728 }
1729 }
1730 }
1731 if (!fp_r)
1732 fp_r = stdin;
1733 if (!fp_w)
1734 fp_w = stdout;
1735
1736 if (unweave) {
1737 pstate.nozzle_separation = 1;
1738 }
1739 pstate.nozzles = 96;
1740 buf = stp_malloc(256 * 256);
1741 valid_bufsize = 256 * 256;
1742
1743 UNPRINT = getenv("UNPRINT");
1744 if ((UNPRINT)&&(!strcmp(UNPRINT,"canon")))
1745 {
1746 if (force_extraskip > 0)
1747 pstate.extraskip = force_extraskip;
1748 else
1749 pstate.extraskip = 1;
1750 parse_canon(fp_r);
1751 }
1752 else
1753 {
1754 if (force_extraskip > 0)
1755 pstate.extraskip = force_extraskip;
1756 else
1757 pstate.extraskip = 2;
1758 parse_escp2(fp_r);
1759 }
1760 fprintf(stderr,"Done reading.\n");
1761 write_output(fp_w, no_output, all_black);
1762 fclose(fp_w);
1763 fprintf(stderr,"Image dump complete.\n");
1764
1765 return(0);
1766 }
1767