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