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