diff options
author | Roger Leigh <rleigh@debian.org> | 2008-10-26 16:10:50 +0000 |
---|---|---|
committer | Roger Leigh <rleigh@debian.org> | 2008-10-26 16:10:50 +0000 |
commit | eb5718390731a9746c556317e641320b671f2091 (patch) | |
tree | 762876b4adf298c1281142328e2ae87007330904 /test |
Imported Upstream version 4.2.0
Diffstat (limited to 'test')
-rw-r--r-- | test/.cvsignore | 12 | ||||
-rw-r--r-- | test/Makefile.am | 73 | ||||
-rw-r--r-- | test/bjc-unprint.c | 490 | ||||
-rw-r--r-- | test/cyan-sweep.tif | bin | 0 -> 16674 bytes | |||
-rw-r--r-- | test/escp2-weavetest.c | 408 | ||||
-rwxr-xr-x | test/parse-bjc | 145 | ||||
-rwxr-xr-x | test/parse-escp2 | 291 | ||||
-rw-r--r-- | test/pcl-unprint.c | 1641 | ||||
-rwxr-xr-x | test/run-weavetest | 43 | ||||
-rw-r--r-- | test/testdither.c | 740 | ||||
-rw-r--r-- | test/unprint.c | 1616 |
11 files changed, 5459 insertions, 0 deletions
diff --git a/test/.cvsignore b/test/.cvsignore new file mode 100644 index 0000000..7c679da --- /dev/null +++ b/test/.cvsignore @@ -0,0 +1,12 @@ +.deps +.libs +Makefile +Makefile.in +escp2-weavetest +printer_options +unprint +escp2-unprint +pcl-unprint +bjc-unprint +testdither +mixed-color-1bit.ppm diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..969f7d9 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,73 @@ +## $Id: Makefile.am,v 1.30 2001/11/10 14:42:43 rlk Exp $ +## Copyright (C) 2000 Roger Leigh +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## Process this file with automake to produce Makefile.in. + +AUTOMAKE_OPTIONS = 1.4 gnu + +@SET_MAKE@ + +MAINT_CHARSET = latin1 + + +## Variables + +AM_CFLAGS = $(GNUCFLAGS) +INCLUDES = @INCLUDES@ $(LIBGIMPPRINT_CFLAGS) -I$(top_srcdir)/src/main +LIBS = @LIBS@ ../lib/libprintut.la $(INTLLIBS) ../lib/libprintut.la + +TESTS = testdither run-weavetest + + +## Programs +TEST_BIN = testdither escp2-weavetest unprint pcl-unprint bjc-unprint + +noinst_PROGRAMS = @TEST_BIN@ +EXTRA_PROGRAMS = escp2-weavetest unprint pcl-unprint bjc-unprint testdither + +escp2_weavetest_SOURCES = escp2-weavetest.c + +escp2_weavetest.o: escp2_weavetest.c +escp2_weavetest_LDADD = $(LIBGIMPPRINT_LIBS) +escp2_weavetest_DEPENDENCIES = $(LIBGIMPPRINT_LIBS) + +unprint_SOURCES = unprint.c + +pcl_unprint_SOURCES = pcl-unprint.c + +bjc_unprint_SOURCES = bjc-unprint.c + +testdither_SOURCES = testdither.c +testdither_LDADD = $(LIBGIMPPRINT_LIBS) +testdither_DEPENDENCIES = $(LIBGIMPPRINT_LIBS) + +$(LIBGIMPPRINT_LIBS): + cd ../src/main ; \ + $(MAKE) + + +## Rules + +#run-weavetest: escp2-weavetest + + +## Clean + +CLEANFILES = $(EXTRA_PROGRAMS) mixed-color-1bit.ppm +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = cyan-sweep.tif parse-escp2 run-weavetest diff --git a/test/bjc-unprint.c b/test/bjc-unprint.c new file mode 100644 index 0000000..eb70301 --- /dev/null +++ b/test/bjc-unprint.c @@ -0,0 +1,490 @@ +/* $Id: bjc-unprint.c,v 1.6 2001/08/13 23:59:13 rlk Exp $ */ +/* + * Convert BJC-printjobs to xbm files, one for each color channel + * + * Copyright 2001 Andy Thaller <thaller@ph.tum.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../lib/libprintut.h" +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <malloc.h> + + +char *outfilename= 0; +char *efnlc= 0,*efnlm= 0,*efnc= 0,*efnm= 0,*efny= 0,*efnk= 0; + +int lc_cnt= 0,lm_cnt= 0,ly_cnt= 0,c_cnt= 0,m_cnt= 0,y_cnt= 0,k_cnt= 0; + +FILE *outfilelc= 0; +FILE *outfilelm= 0; +FILE *outfilely= 0; +FILE *outfilec= 0; +FILE *outfilem= 0; +FILE *outfiley= 0; +FILE *outfilek= 0; + +int xsize,ysize,pixcnt; + +typedef struct scanline_t_ { + int size; + int osize; + unsigned char *buf; + int xmin; + int xmax; + int width; + int y; + struct scanline_t_ *next; +} scanline_t; + +typedef struct bitimage_t_ { + unsigned char *buf; + int y0; + int width; + int height; + int xmin; + int xmax; +} bitimage_t; + +bitimage_t *bitimage_new (void); +int last_bit (unsigned char i); +int first_bit (unsigned char i); +void rle_info (const unsigned char *inbuf, int n, int *first, int *last, + int *width, int *length); +int rle_decode (unsigned char *inbuf, int n, unsigned char *outbuf, int max); +scanline_t* scanline_new (void); +scanline_t *scanline_store (scanline_t *line, int y, unsigned char *buf, + int size); +bitimage_t *scanlines2bitimage (scanline_t *slimg); +char conv (char i); +void save2xbm (const char *filename,char col, bitimage_t *img, + int xmin, int ymin, int xmax, int ymax); +int nextcmd (FILE *infile, unsigned char *inbuff, int *cnt); +int process(FILE *infile, scanline_t *sf[7], int *xmin_, int *xmax_, + int *ymin_, int *ymax_); + + +bitimage_t *bitimage_new(void) +{ + bitimage_t *tmp= (bitimage_t*) xmalloc (sizeof(bitimage_t)); + tmp->buf= 0; + tmp->y0= 0; + tmp->width= 0; + tmp->height= 0; + tmp->xmin= 0; + tmp->xmax= 0; + return tmp; +} + +int last_bit(unsigned char i) { + if (i & 0x1) return 0; + if (i & 0x2) return 1; + if (i & 0x4) return 2; + if (i & 0x8) return 3; + if (i & 0x10) return 4; + if (i & 0x20) return 5; + if (i & 0x40) return 6; + if (i & 0x80) return 7; + return 0; +} + +int first_bit(unsigned char i) { + if (i & 0x80) return 7; + if (i & 0x40) return 6; + if (i & 0x20) return 5; + if (i & 0x10) return 4; + if (i & 0x8) return 3; + if (i & 0x4) return 2; + if (i & 0x2) return 1; + if (i & 0x1) return 0; + return 0; +} + +void rle_info(const unsigned char *inbuf, int n, int *first, int *last, int *width, int *length) +{ + const char *ib= (const char *)inbuf; + char cnt; + int o= 0; + int i=0,j,num,f=-1,l=0; + + *first= 0; + *last= 0; + *width= 0; + + if (n<=0) return; + while (i<n) { + cnt= ib[i]; + if (cnt<0) { + num= 1-cnt; + if (inbuf[i+1]) { + if (f<0) f=o*8 + first_bit(inbuf[i+1]); + l= o*8 + last_bit(inbuf[i+1]); + } + o+= num; + i+= 2; + } else { + num= cnt+1; + for (j=0; j<num; j++) { + if (inbuf[i+j+1]) { + if (f<0) f=(o+j)*8 + first_bit(inbuf[i+j+1]); + l= o*8 + last_bit(inbuf[i+j+1]); + } + } + o+= num; + i+= num+1; + } + } + + if (first) *first= f; + if (last) *last= l; + if (length) *length= o; + if (width) *width= (f<0) ? 0 : l-f+1; +} + +int rle_decode(unsigned char *inbuf, int n, unsigned char *outbuf,int max) +{ + const char *ib= (const char *)inbuf; + char cnt; + int o= 0; + int i=0,j,num; + + if (n<=0) return 0; + while (i<n) { + cnt= ib[i]; + if (cnt<0) { + num= 1-cnt; + for (j=0; j<num; j++) outbuf[o+j]=inbuf[i+1]; + o+= num; + i+= 2; + } else { + num= cnt+1; + for (j=0; j<num; j++) outbuf[o+j]=inbuf[i+j+1]; + o+= num; + i+= num+1; + } + } + + return o; +} + + +scanline_t* scanline_new(void) +{ + scanline_t* tmp= (scanline_t*) xmalloc (sizeof(scanline_t)); + tmp->size= 0; + tmp->osize= 0; + tmp->buf= 0; + tmp->xmin= 0; + tmp->xmax= 0; + tmp->width= 0; + tmp->y= 0; + tmp->next= 0; + return tmp; +} + +scanline_t *scanline_store(scanline_t *line, int y, unsigned char *buf, int size) { + if (!line && !(line= scanline_new())) + return 0; + line->size= size; + line->buf= (unsigned char *) xmalloc (size); + memcpy(line->buf,buf,size); + rle_info(buf,size,&line->xmin,&line->xmax,&line->width,&line->osize); + /* fprintf(stderr,"%d %d %d %d ",size,line->xmin,line->xmax,line->width); */ + line->y= y; + return line; +} + + +bitimage_t *scanlines2bitimage(scanline_t *slimg) +{ + bitimage_t *img= 0; + scanline_t *sl; + int w= 0; + int y0= -1; + int y= 0; + int h; + + for (sl=slimg; sl!=0; sl=sl->next) { + if (sl->width) { + if (w<sl->osize) w= sl->osize; + if (y0<0) y0= sl->y; + y= sl->y; + } + } + h= y-y0+1; + + if ((!w) || (!h)) + return 0; + + img= bitimage_new(); + + img->buf= (unsigned char*) xmalloc(h*w); + memset(img->buf,0,h*w); + img->width= w; + img->height= h; + img->y0= y0; + + for (sl=slimg; sl!=0; sl=sl->next) { + y= sl->y- y0; + if ((y>=0) && (y<h)) { + rle_decode(sl->buf,sl->size,img->buf+y*w,w); + } + } + + return img; +} + +char conv(char i) { + char o= 0; + if (i & 0x80) o|=0x01; + if (i & 0x40) o|=0x02; + if (i & 0x20) o|=0x04; + if (i & 0x10) o|=0x08; + if (i & 0x08) o|=0x10; + if (i & 0x04) o|=0x20; + if (i & 0x02) o|=0x40; + if (i & 0x01) o|=0x80; + return o; +} + + +void save2xbm(const char *filename,char col, bitimage_t *img, + int xmin, int ymin, int xmax, int ymax) +{ + char *outfilename= (char*) xmalloc(strlen(filename)+16); + FILE *o; + int i,j,k,i0,i1,j0,j1,w,h; + + if (!img) return; + + if (col) + sprintf(outfilename,"%s_%c.xbm",filename,col); + else + sprintf(outfilename,"%s.xbm",filename); + + if (!(o= fopen(outfilename,"w"))) { + free(outfilename); + return; + } + + i0= (ymin>0) ? ymin-img->y0 : 0; + i1= (ymax>0) ? ymax-img->y0 : img->height; + j0= (xmin>0 && xmin<img->width*8) ? xmin/8 : 0; + j1= (xmax>0 && xmax<img->width*8) ? xmax/8 : img->width-1; + + w= j1-j0+1; + h= i1-i0; + + if (col) + fprintf(o,"#define %s_%c_width %d\n#define %s_%c_height %d\nstatic char %s_%c_bits[] = {", + outfilename,col,w*8, + outfilename,col,h, + outfilename,col); + else + fprintf(o,"#define %s_width %d\n#define %s_height %d\nstatic char %s_bits[] = {", + outfilename,w*8, + outfilename,h, + outfilename); + + fprintf(stderr,"%d %d %d %d\n",i0,h,j0,w); + for (i=i0,k=0; i<i1; i++) { + for (j=j0; j<=j1; j++) { + if (k%16 == 0) fprintf(o,"\n"); + fprintf(o,"0x%02x, ",(i>=0 && i<img->height)? conv(img->buf[i*img->width+j])&0xff : 0); + k++; + } + } + + fprintf(o," 0x00 };\n"); + + fclose(o); +} + +int nextcmd(FILE *infile,unsigned char *inbuff,int *cnt) +{ + unsigned char c1=0,c2=0; + int c; + int cmd; + + while (!feof(infile) && c1!=0x1b && (c2!=0x28 && c2!=0x5b)) { + c1=c2; c2=fgetc(infile); + } + if (feof(infile)) return 0; + + cmd=fgetc(infile); + if (feof(infile)) return 0; + + c1= fgetc(infile); + if (feof(infile)) return 0; + c2= fgetc(infile); + if (feof(infile)) return 0; + + *cnt= c1+256*c2; + + if ((c=fread(inbuff,1,*cnt,infile) != *cnt)) { + fprintf(stderr,"read error for 0x%02x - not enough data (%d/%d)!\n",cmd, + c,*cnt); + return 0; + } + + return cmd; +} + +int process(FILE *infile,scanline_t *sf[7],int *xmin_,int *xmax_,int *ymin_,int *ymax_) +{ + unsigned char inbuff[65540]; + scanline_t *sl[7], *nsl; + + int xres,yres; + int xmin=1000000,xmax=0,ymin=-1,ymax=0,width=0; + int col=0; + int line=0; + int i; + int cnt; + int cmd; + + for (i=0; i<7; i++) sf[i]= sl[i]= 0; + + if (!infile) return 0; + fseek(infile,0,SEEK_SET); + + while ((cmd= nextcmd(infile,inbuff,&cnt))) { + switch(cmd) { + case 0x64: + yres=inbuff[0]*256+inbuff[1]; + xres=inbuff[2]*256+inbuff[3]; + fprintf(stderr,"res=%dx%ddpi\n",xres,yres); + break; + case 0x65: + line+=(inbuff[0]*256+inbuff[1]); + break; + case 0x41: + switch(inbuff[0]) { + case 0x4b: col= 0; break; /* black */ + case 0x59: col= 1; break; /* yellow */ + case 0x4d: col= 2; break; /* magenta */ + case 0x43: col= 3; break; /* cyan */ + case 0x79: col= 4; break; /* lightyellow */ + case 0x6d: col= 5; break; /* lightmagenta */ + case 0x63: col= 6; break; /* lightcyan */ + default: + fprintf(stderr,"unkown color component 0x%02x\n",inbuff[0]); + exit(-1); + } + + nsl= scanline_store(0,line,inbuff+1,cnt-1); + + if (nsl) { + if (nsl->width) { + if (ymin<0) ymin=line; + ymax=line; + if (nsl->xmin<xmin) xmin=nsl->xmin; + if (nsl->xmax>xmax) xmax=nsl->xmax; + if (nsl->width>width) width=nsl->width; + if (!sf[col]) + sf[col]=nsl; + else + sl[col]->next= nsl; + sl[col]= nsl; + } else { + free (nsl); + nsl= 0; + } + + if (fgetc(infile)!=0x0d) { + fprintf(stderr,"COLOR LINE NOT TERMINATED BY 0x0d @ %lx!!\n", + ftell(infile)); + } + } + break; + case 0x62: + break; + default: + ; + } + } + + fprintf(stderr,"size=%d..%d:%d..%d = %dx%d\n",xmin,xmax,ymin,ymax,width,ymax-ymin+1); + + *xmin_= xmin; + *xmax_= xmax; + *ymin_= ymin; + *ymax_= ymax; + + return 1; +} + +/* +const char *fbin(char b) { + static char bf[9]; + + bf[0]= (b & 0x80) ? '1' : '0'; + bf[1]= (b & 0x40) ? '1' : '0'; + bf[2]= (b & 0x20) ? '1' : '0'; + bf[3]= (b & 0x10) ? '1' : '0'; + bf[4]= (b & 0x08) ? '1' : '0'; + bf[5]= (b & 0x04) ? '1' : '0'; + bf[6]= (b & 0x02) ? '1' : '0'; + bf[7]= (b & 0x01) ? '1' : '0'; + bf[8]=0; + return bf; +} +*/ + +int main(int argc, char **argv) +{ + char *infilename= 0, *outfilename=0; + FILE *infile= 0; + scanline_t *scanlines[7]; + char colname[7] = { 'K', 'Y', 'M', 'C', 'y', 'm', 'c' }; + int xmin,xmax; + int ymin,ymax; + + if (argc>1) { + if (argc>2) + outfilename= argv[2]; + else + outfilename= argv[1]; + + infilename= argv[1]; + infile= fopen(infilename,"r"); + + xsize=ysize=0; + + process(infile,scanlines,&xmin,&xmax,&ymin,&ymax); + + save2xbm(outfilename,colname[0],scanlines2bitimage(scanlines[0]),xmin,ymin,xmax,ymax); + save2xbm(outfilename,colname[1],scanlines2bitimage(scanlines[1]),xmin,ymin,xmax,ymax); + save2xbm(outfilename,colname[2],scanlines2bitimage(scanlines[2]),xmin,ymin,xmax,ymax); + save2xbm(outfilename,colname[3],scanlines2bitimage(scanlines[3]),xmin,ymin,xmax,ymax); + save2xbm(outfilename,colname[4],scanlines2bitimage(scanlines[4]),xmin,ymin,xmax,ymax); + save2xbm(outfilename,colname[5],scanlines2bitimage(scanlines[5]),xmin,ymin,xmax,ymax); + save2xbm(outfilename,colname[6],scanlines2bitimage(scanlines[6]),xmin,ymin,xmax,ymax); + + } else { + fprintf(stderr,"\nusage: bjc-unprint INFILE [OUTFILE]\n\n"); + } + + return 0; +} + diff --git a/test/cyan-sweep.tif b/test/cyan-sweep.tif Binary files differnew file mode 100644 index 0000000..f4b0139 --- /dev/null +++ b/test/cyan-sweep.tif diff --git a/test/escp2-weavetest.c b/test/escp2-weavetest.c new file mode 100644 index 0000000..a12b62e --- /dev/null +++ b/test/escp2-weavetest.c @@ -0,0 +1,408 @@ +/* + * "$Id: escp2-weavetest.c,v 1.19 2001/09/02 13:30:27 rlk Exp $" + * + * Print plug-in EPSON ESC/P2 driver for the GIMP. + * + * Copyright 1999-2000 Robert Krawitz (rlk@alum.mit.edu) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test for the soft weave algorithm. This program calculates the weave + * parameters for each input line and verifies that a number of conditions + * are met. Currently, the conditions checked are: + * + * 1) Pass # is >= 0 + * 2) The nozzle is within the physical bounds of the printer + * 3) The computed starting row of the pass is not greater than the row + * index itself. + * 4) The computed end of the pass is not less than the row index itself. + * 5) If this row is the last row of a pass, that the last pass completed + * was one less than the current pass that we're just completing. + * 6) For a given pass, the computed starting row of the pass is the same + * for all rows comprising the pass. + * 7) For a given pass, the computed last row of the pass is the same + * for all rows comprising the pass. + * 8) The input row is the same as the row computed by the algorithm. + * 9) If there are phantom rows within the pass (unused jets before the + * first jet that is actually printing anything), then the number of + * phantom rows is not less than zero nor greater than or equal to the + * number of physical jets in the printer. + * 10) The physical starting row of the pass (disregarding any phantom + * rows) is at least zero. + * 11) If there are phantom rows, the number of phantom rows is less than + * the current nozzle number. + * 12) If we are using multiple subpasses for each row, that each row within + * this pass is part of the same logical subpass. Thus, if the pass in + * question is the first subpass for a given row, that it is the first + * subpass for ALL rows comprising the pass. This doesn't matter if we're + * simply overlaying data; it's important if we have to shift the print head + * slightly between each pass to accomplish high-resolution printing. + * 13) We are not overprinting a specified (row, subpass) pair. + * + * In addition to these per-row checks, we calculate the following global + * correctness checks: + * + * 1) No pass starts (logically) at a later row than an earlier pass. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "../lib/libprintut.h" +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#define DEBUG_SIGNAL +#define MIN(x, y) ((x) <= (y) ? (x) : (y)) +#ifdef INCLUDE_GIMP_PRINT_H +#include INCLUDE_GIMP_PRINT_H +#else +#include <gimp-print/gimp-print.h> +#endif +#include <gimp-print-internal.h> + +const char header[] = "Legend:\n" +"A Negative pass number.\n" +"B Jet number out of range.\n" +"C Starting row of this pass after the current row.\n" +"D Ending row of this pass before the current row.\n" +"E Current row is the ending row of the pass, and the pass number is not\n" +" one greater than the previous completed pass.\n" +"F The current pass's starting row is not consistent with the previously\n" +" observed starting row of this pass.\n" +"G The current pass's ending row is not consistent with the previously\n" +" observed ending row of this pass.\n" +"H The current row does not match the computed current row based on jet and\n" +" start of pass.\n" +"I The number of missing start rows is less than zero or greater than or\n" +" equal to the actual number of jets.\n" +"J The first printed row of this pass is less than zero.\n" +"K The number of missing start rows of this pass is greater than the\n" +" jet used to print the current row.\n" +"L The subpass printed by the current pass is not consistent with an earlier\n" +" record of the subpass printed by this pass.\n" +"M The same physical row is being printed more than once.\n" +"N Two different active passes are in the same slot.\n" +"O Number of missing start rows is incorrect.\n" +"P Physical row number out of bounds.\n" +"Q Pass starts earlier than a prior pass.\n"; + +stp_vars_t v; + +static void +print_header(void) +{ + printf("%s", header); +} + +static void +flush_pass(stp_softweave_t *sw, int passno, int model, int width, + int hoffset, int ydpi, int xdpi, int physical_xdpi, + int vertical_subpass) +{ +} + +static void +writefunc(void *file, const char *buf, size_t bytes) +{ + FILE *prn = (FILE *)file; + fwrite(buf, 1, bytes, prn); +} + +static int +run_one_weavetest(int physjets, int physsep, int hpasses, int vpasses, + int subpasses, int nrows, int first_line, int phys_lines, + int color_jet_arrangement, int strategy, int quiet) +{ + int i; + int j; + stp_weave_t w; + int errors[26]; + char errcodes[26]; + int total_errors = 0; + int lastpass = -1; + int newestpass = -1; + int *passstarts; + int *logpassstarts; + int *passends; + int *passcounts; + signed char *physpassstuff; + signed char *rowdetail; + int *current_slot; + int vmod; + void *sw; + int head_offset[8]; + + memset(errors, 0, sizeof(int) * 26); +#if 0 + if (physjets < hpasses * vpasses * subpasses) + { + return 0; + } +#endif + + for(i=0; i<8; i++) + head_offset[i] = 0; + + if(color_jet_arrangement != 0) + { + head_offset[0] = (physjets+1)*physsep; + head_offset[1] = (physjets+1)*physsep; + head_offset[2] = 2*(physjets+1)*physsep; + } + + sw = stp_initialize_weave(physjets, physsep, hpasses, vpasses, subpasses, + 1, 1, 128, nrows, 1, first_line, + phys_lines, strategy, head_offset, v, flush_pass, + stp_fill_tiff, stp_pack_tiff, + stp_compute_tiff_linewidth); + if (!sw) + return 1; + + passstarts = xmalloc(sizeof(int) * (nrows + physsep)); + logpassstarts = xmalloc(sizeof(int) * (nrows + physsep)); + passends = xmalloc(sizeof(int) * (nrows + physsep)); + passcounts = xmalloc(sizeof(int) * (nrows + physsep)); + vmod = 2 * physsep * hpasses * vpasses * subpasses; + if (vmod == 0) + vmod = 1; + current_slot = xmalloc(sizeof(int) * vmod); + physpassstuff = xmalloc((nrows + physsep)); + rowdetail = xmalloc((nrows + physsep) * physjets); + memset(rowdetail, 0, (nrows + physsep) * physjets); + memset(physpassstuff, -1, (nrows + physsep)); + memset(current_slot, 0, (sizeof(int) * vmod)); + if (!quiet) + { + print_header(); + printf("%15s %5s %5s %5s %10s %10s %10s %10s\n", "", "row", "pass", + "jet", "missing", "logical", "physstart", "physend"); + } + for (i = 0; i < vmod; i++) + current_slot[i] = -1; + for (i = 0; i < (nrows + physsep); i++) + { + passstarts[i] = -1; + passends[i] = -1; + } + memset(errcodes, ' ', 26); + for (i = 0; i < nrows; i++) + { + for (j = 0; j < hpasses * vpasses * subpasses; j++) + { + int physrow; + stp_weave_parameters_by_row((stp_softweave_t *)sw, i+first_line, j, &w); + physrow = w.logicalpassstart + physsep * w.jet; + + errcodes[0] = (w.pass < 0 ? (errors[0]++, 'A') : ' '); + errcodes[1] = (w.jet < 0 || w.jet > physjets - 1 ? + (errors[1]++, 'B') : ' '); + errcodes[2] = (w.physpassstart > w.row ? (errors[2]++, 'C') : ' '); + errcodes[3] = (w.physpassend < w.row ? (errors[3]++, 'D') : ' '); +#if 0 + errcodes[4] = (w.physpassend == w.row && lastpass + 1 != w.pass ? + (errors[4]++, 'E') : ' '); +#endif + errcodes[5] = (w.pass >= 0 && w.pass < nrows && + passstarts[w.pass] != -1 && + passstarts[w.pass] != w.physpassstart ? + (errors[5]++, 'F') : ' '); + errcodes[6] = (w.pass >= 0 && w.pass < nrows && + passends[w.pass] != -1 && + passends[w.pass] != w.physpassend ? + (errors[6]++, 'G') : ' '); + errcodes[7] = (w.row != physrow ? (errors[7]++, 'H') : ' '); + errcodes[8] = (w.missingstartrows < 0 || + w.missingstartrows > physjets - 1 ? + (errors[8]++, 'I') : ' '); + errcodes[9] = (w.physpassstart < 0 ? (errors[9]++, 'J') : ' '); + errcodes[10] = (w.missingstartrows > w.jet ? + (errors[10]++, 'K') : ' '); + errcodes[11] = (w.pass >= 0 && w.pass < nrows && + physpassstuff[w.pass] >= 0 && + physpassstuff[w.pass] != j ? + (errors[11]++, 'L') : ' '); + errcodes[12] = (w.pass >= 0 && w.pass < nrows && w.jet >= 0 && + w.jet < physjets && + rowdetail[w.pass * physjets + w.jet] == 1 ? + (errors[12]++, 'M') : ' '); + errcodes[13] = (current_slot[w.pass % vmod] != -1 && + current_slot[w.pass % vmod] != w.pass ? + (errors[13]++, 'N') : ' '); + errcodes[14] = (w.physpassstart == w.row && + w.jet != w.missingstartrows ? + (errors[14]++, 'O') : ' '); + errcodes[15] = ((w.logicalpassstart < 0) || + (w.logicalpassstart + physsep * (physjets - 1) >= + phys_lines) ? + (errors[15]++, 'P') : ' '); + errcodes[16] = '\0'; + + if (!quiet) + printf("%15s%5d %5d %5d %10d %10d %10d %10d\n", + errcodes, w.row, w.pass, w.jet, w.missingstartrows, + w.logicalpassstart, w.physpassstart, w.physpassend); + if (w.pass >= 0 && w.pass < (nrows + physsep)) + { + if (w.physpassend == w.row) + { + lastpass = w.pass; + passends[w.pass] = -2; + current_slot[w.pass % vmod] = -1; + } + else + { + passends[w.pass] = w.physpassend; + current_slot[w.pass % vmod] = w.pass; + } + passstarts[w.pass] = w.physpassstart; + logpassstarts[w.pass] = w.logicalpassstart; + if (w.jet >= 0 && w.jet < physjets) + rowdetail[w.pass * physjets + w.jet] = 1; + if (physpassstuff[w.pass] == -1) + physpassstuff[w.pass] = j; + if (w.pass > newestpass) + newestpass = w.pass; + } + } + } + if (!quiet) + printf("Unterminated passes:\n"); + for (i = 0; i <= newestpass; i++) + if (passends[i] >= -1 && passends[i] < nrows) + { + if (!quiet) + printf("%d %d\n", i, passends[i]); + errors[16]++; + } + if (!quiet) + { + printf("Last terminated pass: %d\n", lastpass); + printf("Pass starts:\n"); + } + for (i = 0; i <= newestpass; i++) + { + char qchar = ' '; + if (i > 0) + qchar = logpassstarts[i] < logpassstarts[i - 1] ? + (errors[17]++, 'Q') : ' '; + if (!quiet) + printf("%c %d %d\n", qchar, i, logpassstarts[i]); + } + for (i = 0; i < 26; i++) + total_errors += errors[i]; + stp_destroy_weave(sw); + free(rowdetail); + free(physpassstuff); + free(current_slot); + free(passcounts); + free(passends); + free(logpassstarts); + free(passstarts); + if (!quiet || (quiet == 1 && total_errors > 0)) + printf("%d total error%s\n", total_errors, total_errors == 1 ? "" : "s"); + if (total_errors > 0) + return 1; + else + return 0; +} + + +int +main(int argc, char **argv) +{ + int nrows; + int physjets; + int physsep; + int hpasses, vpasses, subpasses; + int first_line, phys_lines; + int strategy = 1; + int color_jet_arrangement; + int quiet = 0; + int status = 0; + + /* + * Initialise libgimpprint + */ + + stp_init(); + + v = stp_allocate_vars(); + stp_set_outfunc(v, writefunc); + stp_set_errfunc(v, writefunc); + stp_set_outdata(v, stdout); + stp_set_errdata(v, stdout); + + if (argc == 1) + { + int total_cases = 0; + int failures = 0; + char linebuf[4096]; + while (fgets(linebuf, 4096, stdin)) + { + int retval; + (void) sscanf(linebuf, "%d%d%d%d%d%d%d%d%d", &physjets, &physsep, + &hpasses, &vpasses, &subpasses, &nrows, &first_line, + &phys_lines, &color_jet_arrangement); + fflush(stdout); + if (vpasses * subpasses > physjets) + continue; + printf("%d %d %d %d %d %d %d %d %d ", physjets, physsep, hpasses, + vpasses, subpasses, nrows, first_line, phys_lines, + color_jet_arrangement); + retval = run_one_weavetest(physjets, physsep, hpasses, vpasses, + subpasses, nrows, first_line, phys_lines, + color_jet_arrangement, strategy, 1); + total_cases++; + if (retval) + failures++; + else + putc('\n', stdout); + fflush(stdout); + status |= retval; + } + printf("Total cases: %d, failures: %d\n", total_cases, failures); + return status; + } + if (argc != 10) + { + fprintf(stderr, "Usage: %s jets separation hpasses vpasses subpasses rows start end arrangement\n", + argv[0]); + return 2; + } + physjets = atoi(argv[1]); + physsep = atoi(argv[2]); + hpasses = atoi(argv[3]); + vpasses = atoi(argv[4]); + subpasses = atoi(argv[5]); + nrows = atoi(argv[6]); + first_line = atoi(argv[7]); + phys_lines = atoi(argv[8]); + color_jet_arrangement = atoi(argv[9]); +#if 0 + if (physjets < hpasses * vpasses * subpasses) + { + fprintf(stderr, "Oversample exceeds jets\n"); + return 1; + } +#endif + if (getenv("QUIET")) + quiet = 2; + return (run_one_weavetest(physjets, physsep, hpasses, vpasses, + subpasses, nrows, first_line, phys_lines, + color_jet_arrangement, strategy, quiet)); +} diff --git a/test/parse-bjc b/test/parse-bjc new file mode 100755 index 0000000..48ce80c --- /dev/null +++ b/test/parse-bjc @@ -0,0 +1,145 @@ +#!/usr/bin/perl + +while (<>) { + $stuff .= $_; +} + +$OFFS=$ENV{"OFFS"}; +$GRX=$ENV{"GRX"}; + +%seqtable = ( "@", 0, + "\x0d", 0, + "[K", 4, + "(a", "VARIABLE", + "(b", "VARIABLE", + "(c", "VARIABLE", + "(d", "VARIABLE", + "(e", "GRAPHICS", + "(l", "VARIABLE", + "(m", "VARIABLE", + "(p", "VARIABLE", + "(q", "VARIABLE", + "(r", "VARIABLE", + "(t", "VARIABLE", + "(A", "GRAPHICS", + "\\", 2, + "\$", 2, + "(\\", "VARIABLE", + "(C", "VARIABLE", + ".", "SPECIAL", + "i", "SPECIAL1" + ); + +$esc = "\033"; + +$skipcount = 0; +$curpos = 0; +$verbose = 1; + +while ($stuff ne "") { + if ($stuff=~ s/^(BJLSTART.+BJLEND?)//sm) { + + printf "\n$1"; + $curpos+= length($1); + + } elsif (substr($stuff, 0, 1) eq "\xa") { + + print "<a"; + $curpos++; + substr($stuff, 0, 1) = ""; + + } elsif (substr($stuff, 0, 1) eq "\xd") { + + print "<d" if ($GRX); + $curpos++; + substr($stuff, 0, 1) = ""; + + } elsif (substr($stuff, 0, 1) eq "$esc") { + + $found = 0; + foreach $key (keys %seqtable) { + if (substr($stuff, 1, length $key) eq $key) { + $skipchars = $seqtable{$key}; + if ($skipchars eq "GRAPHICS") { + if ($GRX) { + print "\n"; + printf "%08x ", $curpos if ($OFFS); + print "1b "; + } + $startoff = 0; + $lchar = substr($stuff, (length $key) + 1, 1); + $nlchar = unpack("C", $lchar); + $hchar = substr($stuff, (length $key) + 2, 1); + $nhchar = unpack("C", $hchar); + $skipchars = ($nhchar * 256) + $nlchar; + $startoff = 2; + + if ($GRX) { + for ($i = 0; + $i < $skipchars + (length $key) + $startoff; + $i++) { + $char = substr($stuff, $i + 1, 1); + $nchar = unpack("C", $char); + if ($i < 2 && $nchar >= 32 && $nchar < 127) { + print "$char "; + } elsif ($i==4 && $nchar >= 32 && $nchar < 127) { + print "$char$char "; + } else { + printf "%02x ", unpack("C", $char); + } + } + } + $found = 1; + } else { + print "\n"; + printf "%08x ", $curpos if ($OFFS); + print "1b "; + $startoff = 0; + if ($skipchars eq "VARIABLE") { + $lchar = substr($stuff, (length $key) + 1, 1); + $nlchar = unpack("C", $lchar); + $hchar = substr($stuff, (length $key) + 2, 1); + $nhchar = unpack("C", $hchar); + $skipchars = ($nhchar * 256) + $nlchar; + $startoff = 2; + } + for ($i = 0; + $i < $skipchars + (length $key) + $startoff; + $i++) { + $char = substr($stuff, $i + 1, 1); + $nchar = unpack("C", $char); + if ($i < 2 && $nchar >= 32 && $nchar < 127) { + print "$char "; + } else { + printf "%02x ", unpack("C", $char); + } + } + $found = 1; + } + $bytes = length($key) + 1 + $skipchars + $startoff; + last; + } + } + if (! $found) { + print "\n"; + printf "%08x ", $curpos if ($OFFS); + print "1b "; + substr($stuff, 0, 1) = ""; + $curpos += 1; + } elsif ($found == 1) { + substr($stuff, 0, $bytes) = ""; + $curpos += $bytes; + } else { + } + } else { + $char = substr($stuff, 0, 1); + $nchar = unpack("C", $char); + if ($nchar >= 32 && $nchar < 127) { + print "*$char "; + } else { + printf "*%02x ", unpack("C", $char); + } + $curpos++; + substr($stuff, 0, 1) = ""; + } +} diff --git a/test/parse-escp2 b/test/parse-escp2 new file mode 100755 index 0000000..40163eb --- /dev/null +++ b/test/parse-escp2 @@ -0,0 +1,291 @@ +#!/usr/bin/perl + +require("getopts.pl"); + +do Getopts('v'); + +while (<>) { + $stuff .= $_; +} + +%seqtable = ( "@", 0, + "(R", "REMOTE", + "(", "VARIABLE", + "U", 1, + "\\", 2, + "\$", 2, + "r", 1, + ".", "SPECIAL", + "i", "SPECIAL1", + "\000", 2, + "\001", 22 + ); + +$esc = "\033"; + +$skipcount = 0; +$curpos = 0; +$verbose = $opt_v; + +sub do_remote_command { + print "\n"; + printf "%08x ", $curpos; + print "1b ( R "; + substr($stuff, 0, 3) = ""; + $curpos += 3; + $lchar = substr($stuff, 0, 1); + $nlchar = unpack("C", $lchar); + $hchar = substr($stuff, 1, 1); + $nhchar = unpack("C", $hchar); + printf "%02x %02x ", $nlchar, $nhchar; + $skipchars = ($nhchar * 256) + $nlchar; + substr($stuff, 0, 2) = ""; + $curpos += 2; + for ($i = 0; $i < $skipchars; $i++) { + $char = substr($stuff, $i, 1); + $nchar = unpack("C", $char); + if ($nchar >= 32 && $nchar < 127) { + print $char; + } else { + printf "%02x ", $nchar; + } + } + substr($stuff, 0, $skipchars) = ""; + $curpos += skipchars; + while (substr($stuff, 0, 2) =~ /[A-Z0-9][A-Z0-9]/) { + print "\n"; + printf "%08x ", $curpos; + print substr($stuff, 0, 2); + substr($stuff, 0, 2) = ""; + $curpos += 2; + $lchar = substr($stuff, 0, 1); + $nlchar = unpack("C", $lchar); + $hchar = substr($stuff, 1, 1); + $nhchar = unpack("C", $hchar); + $skipchars = ($nhchar * 256) + $nlchar; + printf "%02x %02x ", $nlchar, $nhchar; + substr($stuff, 0, 2) = ""; + $curpos += 2; + for ($i = 0; $i < $skipchars; $i++) { + printf "%02x ", unpack("C", substr($stuff, $i, 1)); + } + substr($stuff, 0, $skipchars) = ""; + $curpos += $skipchars; + } +} + +sub do_special_command { + print "\n"; + printf "%08x ", $curpos; + print "1b "; + for ($i = 1; $i < 8; $i++) { + $char = substr($stuff, $i, 1); + $nchar = unpack("C", $char); + if ($i < 2 && $nchar >= 32 && $nchar < 127) { + print " $char "; + } else { + printf "%02x ", unpack("C", $char); + } + } + $comptype = unpack("C", substr($stuff, 2, 1)); + $dots = unpack("v", substr($stuff, 6, 2)); + $something = unpack("C", substr($stuff, 5, 1)); + print " ($dots, $something) "; + $savedots = $dots; + $dots *= $something; + $curpos += 8; + substr($stuff, 0, 8) = ""; + if ($comptype == 0) { + $bytes = ($dots + 7) / 8; + if ($verbose) { + for ($k = 0; $k < $bytes; $k++) { + $char = substr($stuff, $k, 1); + printf "%02x", unpack("C", $char); + } + } + $curpos += $bytes; + substr($stuff, 0, $bytes) = ""; + } elsif ($comptype == 1) { + while ($something > 0) { + $dots = $savedots; + while ($dots > 0) { + $counter = unpack("C", substr($stuff, 0, 1)); + $curpos++; + substr($stuff, 0, 1) = ""; + if ($counter <= 127) { + $counter++; + if ($verbose) { + for ($k = 0; $k < $counter; $k++) { + $char = substr($stuff, $k, 1); + printf "%02x ", unpack("C", $char); + } + } + $curpos += $counter; + substr($stuff, 0, $counter) = ""; + $dots -= 8 * $counter; + } else { + $counter = 257 - $counter; + if ($verbose) { + for ($k = 0; $k < $counter; $k++) { + $char = substr($stuff, 0, 1); + printf "%02x ", unpack("C", $char); + } + } + $curpos++; + substr($stuff, 0, 1) = ""; + $dots -= 8 * $counter; + } + } + $something--; + } + } else { + print "\nUnknown compression type $comptype!\n"; + } +} + +sub do_special1_command { + print "\n"; + printf "%08x ", $curpos; + print "1b "; + for ($i = 1; $i < 9; $i++) { + $char = substr($stuff, $i, 1); + $nchar = unpack("C", $char); + if ($i < 2 && $nchar >= 32 && $nchar < 127) { + print " $char "; + } else { + printf "%02x ", unpack("C", $char); + } + } + $comptype = unpack("C", substr($stuff, 3, 1)); + $bitsperpixel = unpack("C", substr($stuff, 4, 1)); + $dots = unpack("v", substr($stuff, 5, 2)); + $something = unpack("v", substr($stuff, 7, 2)); + print " ($dots, $something, $bitsperpixel) "; + $dots *= 8; + $savedots = $dots; + $dots *= $something; + $curpos += 9; + substr($stuff, 0, 9) = ""; + if ($comptype == 0) { + $bytes = ($dots + 7) / 8; + if ($verbose) { + for ($k = 0; $k < $bytes; $k++) { + $char = substr($stuff, $k, 1); + printf "%02x", unpack("C", $char); + } + } + $curpos += $bytes; + substr($stuff, 0, $bytes) = ""; + } elsif ($comptype == 1) { + while ($something > 0) { + $dots = $savedots; + while ($dots > 0) { + $counter = unpack("C", substr($stuff, 0, 1)); + $curpos++; + substr($stuff, 0, 1) = ""; + if ($counter <= 127) { + $counter++; +# printf(" (%d) ", $counter); + if ($verbose) { + for ($k = 0; $k < $counter; $k++) { + $char = substr($stuff, $k, 1); + printf "%02x ", unpack("C", $char); + } + } + $curpos += $counter; + substr($stuff, 0, $counter) = ""; + $dots -= 8 * $counter; + } else { + $counter = 257 - $counter; +# printf(" (%d %d) ", $counter, unpack("C", substr($stuff, 0, 1))); + if ($verbose) { + $char = substr($stuff, 0, 1); + for ($k = 0; $k < $counter; $k++) { + printf "%02x ", unpack("C", $char); + } + } + $curpos++; + substr($stuff, 0, 1) = ""; + $dots -= 8 * $counter; + } + } + $something--; + if ($something > 0 && $verbose) { + print "\n "; + } + } + } else { + print "\nUnknown compression type $comptype!\n"; + } +} + +while ($stuff ne "") { + if (substr($stuff, 0, 1) eq "$esc") { + $found = 0; + foreach $key (sort { length $b <=> length $a } keys %seqtable) { + if (substr($stuff, 1, length $key) eq $key) { + $skipchars = $seqtable{$key}; + if ($skipchars eq "SPECIAL") { + do_special_command; + $found = 2; + } elsif ($skipchars eq "SPECIAL1") { + do_special1_command; + $found = 2; + } elsif ($skipchars eq "REMOTE") { + do_remote_command; + $found = 2; + } else { + print "\n"; + printf "%08x ", $curpos; + print "1b "; + $startoff = 0; + if ($skipchars eq "VARIABLE") { + $kchar = substr($stuff, (length $key) + 1, 1); + $nkchar = unpack("C", $kchar); + $lchar = substr($stuff, (length $key) + 2, 1); + $nlchar = unpack("C", $lchar); + $hchar = substr($stuff, (length $key) + 3, 1); + $nhchar = unpack("C", $hchar); + $skipchars = ($nhchar * 256) + $nlchar; + $startoff = 3; + } + for ($i = 0; + $i < $skipchars + (length $key) + $startoff; + $i++) { + $char = substr($stuff, $i + 1, 1); + $nchar = unpack("C", $char); + if ($i < 3 && $nchar >= 32 && $nchar < 127) { + print " $char "; + } else { + printf "%02x ", unpack("C", $char); + } + } + $found = 1; + } + $bytes = length($key) + 1 + $skipchars + $startoff; + last; + } + } + if (! $found) { + print "\n"; + printf "%08x ", $curpos; + print "1b "; + substr($stuff, 0, 1) = ""; + $curpos += 1; + } elsif ($found == 1) { + substr($stuff, 0, $bytes) = ""; + $curpos += $bytes; + } else { + } + } else { + $char = substr($stuff, 0, 1); + $nchar = unpack("C", $char); + if ($nchar >= 32 && $nchar < 127) { + print " *$char "; + } else { + printf "*%02x ", unpack("C", $char); + } + $curpos++; + substr($stuff, 0, 1) = ""; + } +} diff --git a/test/pcl-unprint.c b/test/pcl-unprint.c new file mode 100644 index 0000000..387a6f3 --- /dev/null +++ b/test/pcl-unprint.c @@ -0,0 +1,1641 @@ +/* + * "$Id: pcl-unprint.c,v 1.5 2001/06/03 20:53:24 rlk Exp $" + * + * pclunprint.c - convert an HP PCL file into an image file for viewing. + * + * Copyright 2000 Dave Hill (dave@minnie.demon.co.uk) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Revision History: + * + * See ChangeLog + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "../lib/libprintut.h" +#include<stdio.h> +#include<stdlib.h> +#include<ctype.h> +#include<string.h> + +static const char *id="@(#) $Id: pcl-unprint.c,v 1.5 2001/06/03 20:53:24 rlk Exp $"; + +/* + * Largest data attached to a command. 1024 means that we can have up to 8192 + * pixels in a row + */ +#define MAX_DATA 1024 + +FILE *read_fd,*write_fd; +char read_buffer[1024]; +char data_buffer[MAX_DATA]; +char initial_command[3]; +int initial_command_index; +char final_command; +int numeric_arg; + +int read_pointer; +int read_size; +int eof; +int combined_command = 0; + +/* + * Data about the image + */ + +typedef struct { + int colour_type; /* Mono, 3/4 colour */ + int black_depth; /* 2 level, 4 level */ + int cyan_depth; /* 2 level, 4 level */ + int magenta_depth; /* 2 level, 4 level */ + int yellow_depth; /* 2 level, 4 level */ + int lcyan_depth; /* 2 level, 4 level */ + int lmagenta_depth; /* 2 level, 4 level */ + int image_width; + int image_height; + int compression_type; /* Uncompressed or TIFF */ +} image_t; + +/* + * collected data read from file + */ + +typedef struct { + char **black_bufs; /* Storage for black rows */ + int black_data_rows_per_row; /* Number of black rows */ + char **cyan_bufs; + int cyan_data_rows_per_row; + char **magenta_bufs; + int magenta_data_rows_per_row; + char **yellow_bufs; + int yellow_data_rows_per_row; + char **lcyan_bufs; + int lcyan_data_rows_per_row; + char **lmagenta_bufs; + int lmagenta_data_rows_per_row; + int active_height; /* Height of output data */ + int output_depth; +} output_t; + +#define PCL_MONO 1 +#define PCL_CMY 3 +#define PCL_CMYK 4 +#define PCL_CMYKcm 6 + +#define PCL_COMPRESSION_NONE 0 +#define PCL_COMPRESSION_RUNHEIGHT 1 +#define PCL_COMPRESSION_TIFF 2 +#define PCL_COMPRESSION_DELTA 3 +#define PCL_COMPRESSION_CRDR 9 /* Compressed row delta replacement */ + +/* PCL COMMANDS */ + +#define PCL_RESET 1 +#define PCL_MEDIA_SIZE 2 +#define PCL_PERF_SKIP 3 +#define PCL_TOP_MARGIN 4 +#define PCL_MEDIA_TYPE 5 +#define PCL_MEDIA_SOURCE 6 +#define PCL_SHINGLING 7 +#define PCL_RASTERGRAPHICS_QUALITY 8 +#define PCL_DEPLETION 9 +#define PCL_CONFIGURE 10 +#define PCL_RESOLUTION 11 +#define PCL_COLOURTYPE 12 +#define PCL_COMPRESSIONTYPE 13 +#define PCL_LEFTRASTER_POS 14 +#define PCL_TOPRASTER_POS 15 +#define PCL_RASTER_WIDTH 16 +#define PCL_RASTER_HEIGHT 17 +#define PCL_START_RASTER 18 +#define PCL_END_RASTER 19 +#define PCL_END_RASTER_NEW 20 +#define PCL_DATA 21 +#define PCL_DATA_LAST 22 +#define PCL_PRINT_QUALITY 23 +#define PCL_PJL_COMMAND 24 +#define PCL_GRAY_BALANCE 25 +#define PCL_DRIVER_CONFIG 26 +#define PCL_PAGE_ORIENTATION 27 +#define PCL_VERTICAL_CURSOR_POSITIONING_BY_DOTS 28 +#define PCL_HORIZONTAL_CURSOR_POSITIONING_BY_DOTS 29 +#define PCL_UNIT_OF_MEASURE 30 +#define PCL_RELATIVE_VERTICAL_PIXEL_MOVEMENT 31 +#define PCL_PALETTE_CONFIGURATION 32 + +typedef struct { + const char initial_command[3]; /* First part of command */ + const char final_command; /* Last part of command */ + int has_data; /* Data follows */ + int command; /* Command name */ + const char *description; /* Text for printing */ +} commands_t; + +const commands_t pcl_commands[] = + { +/* Two-character sequences ESC <x> */ + { "E", '\0', 0, PCL_RESET, "PCL RESET" }, + { "%", '\0', 0, PCL_PJL_COMMAND, "PJL Command" }, /* Special! */ +/* Parameterised sequences */ +/* Raster positioning */ + { "&a", 'H', 0, PCL_LEFTRASTER_POS, "Left Raster Position" }, + { "&a", 'V', 0, PCL_TOPRASTER_POS, "Top Raster Position" }, +/* Media */ + { "&l", 'A', 0, PCL_MEDIA_SIZE , "Media Size" }, + { "&l", 'E', 0, PCL_TOP_MARGIN , "Top Margin" }, + { "&l", 'H', 0, PCL_MEDIA_SOURCE, "Media Source" }, + { "&l", 'L', 0, PCL_PERF_SKIP , "Perf. Skip" }, + { "&l", 'M', 0, PCL_MEDIA_TYPE , "Media Type" }, + { "&l", 'O', 0, PCL_PAGE_ORIENTATION, "Page Orientation" }, +/* Units */ + { "&u", 'D', 0, PCL_UNIT_OF_MEASURE, "Unit of Measure" }, /* from bpd05446 */ +/* Raster data */ + { "*b", 'B', 0, PCL_GRAY_BALANCE, "Gray Balance" }, /* from PCL Developer's Guide 6.0 */ + { "*b", 'M', 0, PCL_COMPRESSIONTYPE, "Compression Type" }, + { "*b", 'V', 1, PCL_DATA, "Data, intermediate" }, + { "*b", 'W', 1, PCL_DATA_LAST, "Data, last" }, + { "*b", 'Y', 0, PCL_RELATIVE_VERTICAL_PIXEL_MOVEMENT, "Relative Vertical Pixel Movement" }, +/* Palette */ + { "*d", 'W', 1, PCL_PALETTE_CONFIGURATION, "Palette Configuration" }, +/* Plane configuration */ + { "*g", 'W', 1, PCL_CONFIGURE, "Configure Raster Data" }, +/* Raster Graphics */ + { "*o", 'D', 0, PCL_DEPLETION, "Depletion" }, + { "*o", 'M', 0, PCL_PRINT_QUALITY, "Print Quality" }, + { "*o", 'Q', 0, PCL_SHINGLING, "Raster Graphics Shingling" }, + { "*o", 'W', 1, PCL_DRIVER_CONFIG, "Driver Configuration Command" }, +/* Cursor Positioning */ + { "*p", 'X', 0, PCL_HORIZONTAL_CURSOR_POSITIONING_BY_DOTS, "Horizontal Cursor Positioning by Dots" }, + { "*p", 'Y', 0, PCL_VERTICAL_CURSOR_POSITIONING_BY_DOTS, "Vertical Cursor Positioning by Dots" }, +/* Raster graphics */ + { "*r", 'A', 0, PCL_START_RASTER, "Start Raster Graphics" }, + { "*r", 'B', 0, PCL_END_RASTER, "End Raster Graphics"}, + { "*r", 'C', 0, PCL_END_RASTER_NEW, "End Raster Graphics" }, + { "*r", 'Q', 0, PCL_RASTERGRAPHICS_QUALITY, "Raster Graphics Quality" }, + { "*r", 'S', 0, PCL_RASTER_WIDTH, "Raster Width" }, + { "*r", 'T', 0, PCL_RASTER_HEIGHT, "Raster Height" }, + { "*r", 'U', 0, PCL_COLOURTYPE, "Colour Type" }, +/* Resolution */ + { "*t", 'R', 0, PCL_RESOLUTION, "Resolution" }, + }; + +int pcl_find_command (void); +void fill_buffer (void); +void pcl_read_command (void); +void write_grey (output_t *output, image_t *image); +void write_colour (output_t *output, image_t *image); +int decode_tiff (char *in_buffer, int data_height, char *decode_buf, + int maxlen); +void pcl_reset (image_t *i); +int depth_to_rows (int depth); + + +/* + * pcl_find_command(). Search the commands table for the command. + */ + +int pcl_find_command(void) +{ + + int num_commands = sizeof(pcl_commands) / sizeof(commands_t); + int i; + + for (i=0; i < num_commands; i++) { + if ((strcmp(initial_command, pcl_commands[i].initial_command) == 0) && + (final_command == pcl_commands[i].final_command)) + return(i); + } + + return (-1); +} + +/* + * fill_buffer() - Read a new chunk from the input file + */ + +void fill_buffer(void) +{ + + if ((read_pointer == -1) || (read_pointer >= read_size)) { + read_size = (int) fread(&read_buffer, sizeof(char), 1024, read_fd); + +#ifdef DEBUG + fprintf(stderr, "Read %d characters\n", read_size); +#endif + + if (read_size == 0) { +#ifdef DEBUG + fprintf(stderr, "No More to read!\n"); +#endif + eof = 1; + return; + } + read_pointer = 0; + } +} + +/* + * pcl_read_command() - Read the data stream and parse the next PCL + * command. + */ + +void pcl_read_command(void) +{ + + char c; + int minus; + int skipped_chars; + +/* + Precis from the PCL Developer's Guide 6.0:- + + There are two formats for PCL commands; "Two Character" and + "Parameterised". + + A "Two Character" command is: ESC <x>, where <x> has a decimal + value between 48 and 126 (inclusive). + + A "Parameterised" command is: ESC <x> <y> [n] <z> + where x, y and z are characters, and [n] is an optional number. + The character <x> has a decimal value between 33 and 47 (incl). + The character <y> has a decimal value between 96 and 126 (incl). + + Some commands are followed by data, in this case, [n] is the + number of bytes to read, otherwise <n> is a numeric argument. + The number <n> can consist of +, - and 0-9 (and .). + + The character <z> is either in the range 64-94 for a termination + or 96-126 for a combined command. (The ref guide gives these + as "96-126" and "64-96" which cannot be right as 96 appears twice!) + + It is possible to combine parameterised commands if the + command prefix is the same, e.g. ESC & l 26 a 0 L is the same as + ESC & l 26 A ESC & l 0 L. The key to this is that the terminator for + the first command is in the range 96-126 (lower case). + + There is a problem with the "PJL command" (ESC %) as it does not + conform to this specification, so we have to check for it specifically! +*/ + +#define PCL_DIGIT(c) (((unsigned int) c >= 48) && ((unsigned int) c <= 57)) +#define PCL_TWOCHAR(c) (((unsigned int) c >= 48) && ((unsigned int) c <= 126)) +#define PCL_PARAM(c) (((unsigned int) c >= 33) && ((unsigned int) c <= 47)) +#define PCL_PARAM2(c) (((unsigned int) c >= 96) && ((unsigned int) c <= 126)) +#define PCL_COMBINED_TERM(c) (((unsigned int) c >= 96) && ((unsigned int) c <= 126)) +#define PCL_TERM(c) (((unsigned int) c >= 64) && ((unsigned int) c <= 94)) +#define PCL_CONVERT_TERM(c) (c - (char) 32) + + numeric_arg=0; + minus = 0; + final_command = '\0'; + + fill_buffer(); + if (eof == 1) + return; + + c = read_buffer[read_pointer++]; +#ifdef DEBUG + fprintf(stderr, "Got %c\n", c); +#endif + +/* + * If we are not in a "combined command", we are looking for ESC + */ + + if (combined_command == 0) { + + if(c != (char) 0x1b) { + + fprintf(stderr, "ERROR: No ESC found (out of sync?) searching... "); + +/* + * all we can do is to chew through the file looking for another ESC. + */ + + skipped_chars = 0; + while (c != (char) 0x1b) { + skipped_chars++; + fill_buffer(); + if (eof == 1) { + fprintf(stderr, "ERROR: EOF looking for ESC!\n"); + return; + } + c = read_buffer[read_pointer++]; + } + fprintf(stderr, "%d characters skipped.\n", skipped_chars); + } + +/* + * We got an ESC, process normally + */ + + initial_command_index=0; + initial_command[initial_command_index] = '\0'; + fill_buffer(); + if (eof == 1) { + fprintf(stderr, "ERROR: EOF after ESC!\n"); + return; + } + +/* Get first command letter */ + + c = read_buffer[read_pointer++]; + initial_command[initial_command_index++] = c; + +#ifdef DEBUG + fprintf(stderr, "Got %c\n", c); +#endif + +/* Check to see if this character forms a "two character" command, + or is a PJL command. */ + + if (PCL_TWOCHAR(c) + || (c == '%')) { +#ifdef DEBUG + fprintf(stderr, "Two character or PJL command\n"); +#endif + initial_command[initial_command_index] = '\0'; + return; + } /* two character check */ + +/* Now check for a "parameterised" sequence. */ + + else if (PCL_PARAM(c)) { +#ifdef DEBUG + fprintf(stderr, "Parameterised command\n"); +#endif + +/* Get the next character in the command */ + + fill_buffer(); + if (eof == 1) { + +#ifdef DEBUG + fprintf(stderr, "EOF in middle of command!\n"); +#endif + eof = 0; /* Ignore it */ + initial_command[initial_command_index] = '\0'; + return; + } + c = read_buffer[read_pointer++]; +#ifdef DEBUG + fprintf(stderr, "Got %c\n", c); +#endif + +/* Check that it is legal and store it */ + + if (PCL_PARAM2(c)) { + initial_command[initial_command_index++] = c; + initial_command[initial_command_index] = '\0'; + +/* Get the next character in the command then fall into the numeric part */ + + fill_buffer(); + if (eof == 1) { + +#ifdef DEBUG + fprintf(stderr, "EOF in middle of command!\n"); +#endif + eof = 0; /* Ignore it */ + return; + } + c = read_buffer[read_pointer++]; +#ifdef DEBUG + fprintf(stderr, "Got %c\n", c); +#endif + + } + else { + fprintf(stderr, "ERROR: Illegal second character %c in parameterised command.\n", + c); + initial_command[initial_command_index] = '\0'; + return; + } + } /* Parameterised check */ + +/* If we get here, the command is illegal */ + + else { + fprintf(stderr, "ERROR: Illegal first character %c in command.\n", + c); + initial_command[initial_command_index] = '\0'; + return; + } + } /* End of (combined_command) */ + +/* + We get here if either this is a combined sequence, or we have processed + the beginning of a parameterised sequence. There is an optional number + next, which may be preceeded by "+" or "-". FIXME We should also handle + decimal points. +*/ + + if ((c == '-') || (c == '+') || (PCL_DIGIT(c))) { + if (c == '-') + minus = 1; + else if (c == '+') + minus = 0; + else + numeric_arg = (int) (c - '0'); + +/* Continue until non-numeric seen */ + + while (1) { + fill_buffer(); + if (eof == 1) { + fprintf(stderr, "ERROR: EOF in middle of command!\n"); + return; + } + c = read_buffer[read_pointer++]; + +#ifdef DEBUG + fprintf(stderr, "Got %c\n", c); +#endif + + if (! PCL_DIGIT(c)) { + break; /* End of loop */ + } + numeric_arg = (10 * numeric_arg) + (int) (c - '0'); + } + } + +/* + We fell out of the loop when we read a non-numeric character. + Treat this as the terminating character and check for a combined + command. We should check that the letter is a valid terminator, + but it doesn't matter as we'll just not recognize the command! + */ + + combined_command = (PCL_COMBINED_TERM(c) != 0); + if (combined_command == 1) { +#ifdef DEBUG + fprintf(stderr, "Combined command\n"); +#endif + final_command = PCL_CONVERT_TERM(c); + } + else + final_command = c; + + if (minus == 1) + numeric_arg = -numeric_arg; + + return; +} + +/* + * write_grey() - write out one line of mono PNM image + */ + +/* FIXME - multiple levels */ + +void write_grey(output_t *output, /* I: data */ + image_t *image) /* I: Image data */ +{ + int wholebytes = image->image_width / 8; + int crumbs = image->image_width - (wholebytes * 8); + char *buf = output->black_bufs[0]; + + int i, j; + char tb[8]; + +#ifdef DEBUG + fprintf(stderr, "Data Height: %d, wholebytes: %d, crumbs: %d\n", + output->active_height, wholebytes, crumbs); +#endif + + for (i=0; i < wholebytes; i++) { + for (j=0; j < 8; j++) { + tb[j] = (((buf[i] >> (7-j)) & 1)); + tb[j] = output->output_depth - tb[j]; + } + (void) fwrite(&tb[0], sizeof(char), 8, write_fd); + } + for (j=0; j < crumbs; j++) { + tb[j] = (((buf[wholebytes] >> (7-j)) & 1)); + tb[j] = output->output_depth - tb[j]; + } + (void) fwrite(&tb[0], sizeof(char), (size_t) crumbs, write_fd); +} + +/* + * write_colour() - Write out one row of RGB PNM data. + */ + +/* FIXME - multiple levels and CMYK/CMYKcm */ + +void write_colour(output_t *output, /* I: Data buffers */ + image_t *image) /* I: Image data */ +{ + int wholebytes = image->image_width / 8; + int crumbs = image->image_width - (wholebytes * 8); + + int i, j, jj; + char tb[8*3]; + + char *cyan_buf; + char *magenta_buf; + char *yellow_buf; + char *black_buf; + + cyan_buf = output->cyan_bufs[0]; + magenta_buf = output->magenta_bufs[0]; + yellow_buf = output->yellow_bufs[0]; + if (image->colour_type != PCL_CMY) + black_buf = output->black_bufs[0]; + else + black_buf = NULL; + +#ifdef DEBUG + fprintf(stderr, "Data Height: %d, wholebytes: %d, crumbs: %d, planes: %d\n", + output->active_height, wholebytes, crumbs, image->colour_type); + + fprintf(stderr, "Cyan: "); + for (i=0; i < output->active_height; i++) { + fprintf(stderr, "%02x ", (unsigned char) cyan_buf[i]); + } + fprintf(stderr, "\n"); + fprintf(stderr, "Magenta: "); + for (i=0; i < output->active_height; i++) { + fprintf(stderr, "%02x ", (unsigned char) magenta_buf[i]); + } + fprintf(stderr, "\n"); + fprintf(stderr, "Yellow: "); + for (i=0; i < output->active_height; i++) { + fprintf(stderr, "%02x ", (unsigned char) yellow_buf[i]); + } + fprintf(stderr, "\n"); + if (image->colour_type == PCL_CMYK) { + fprintf(stderr, "Black: "); + for (i=0; i < output->active_height; i++) { + fprintf(stderr, "%02x ", (unsigned char) black_buf[i]); + } + fprintf(stderr, "\n"); + } +#endif + + if (image->colour_type == PCL_CMY) { + for (i=0; i < wholebytes; i++) { + for (j=0,jj=0; j < 8; j++,jj+=3) { + tb[jj] = (((cyan_buf[i] >> (7-j)) & 1)); + tb[jj] = output->output_depth - tb[jj]; + tb[jj+1] = (((magenta_buf[i] >> (7-j)) & 1)); + tb[jj+1] = output->output_depth - tb[jj+1]; + tb[jj+2] = (((yellow_buf[i] >> (7-j)) & 1)); + tb[jj+2] = output->output_depth - tb[jj+2]; + } + (void) fwrite(&tb[0], sizeof(char), (size_t) (8*3), write_fd); + } + for (j=0,jj=0; j < crumbs; j++,jj+=3) { + tb[jj] = (((cyan_buf[wholebytes] >> (7-j)) & 1)); + tb[jj] = output->output_depth - tb[jj]; + tb[jj+1] = (((magenta_buf[wholebytes] >> (7-j)) & 1)); + tb[jj+1] = output->output_depth - tb[jj+1]; + tb[jj+2] = (((yellow_buf[wholebytes] >> (7-j)) & 1)); + tb[jj+2] = output->output_depth - tb[jj+2]; + } + (void) fwrite(&tb[0], sizeof(char), (size_t) crumbs*3, write_fd); + } + else { + for (i=0; i < wholebytes; i++) { + for (j=0,jj=0; j < 8; j++,jj+=3) { +#if !defined OUTPUT_CMYK_ONLY_K && !defined OUTPUT_CMYK_ONLY_CMY + tb[jj] = ((((cyan_buf[i]|black_buf[i]) >> (7-j)) & 1)); + tb[jj+1] = ((((magenta_buf[i]|black_buf[i]) >> (7-j)) & 1)); + tb[jj+2] = ((((yellow_buf[i]|black_buf[i]) >> (7-j)) & 1)); +#endif +#ifdef OUTPUT_CMYK_ONLY_K + tb[jj] = (((black_buf[i] >> (7-j)) & 1)); + tb[jj+1] = (((black_buf[i] >> (7-j)) & 1)); + tb[jj+2] = (((black_buf[i] >> (7-j)) & 1)); +#endif +#ifdef OUTPUT_CMYK_ONLY_CMY + tb[jj] = (((cyan_buf[i] >> (7-j)) & 1)); + tb[jj+1] = (((magenta_buf[i] >> (7-j)) & 1)); + tb[jj+2] = (((yellow_buf[i] >> (7-j)) & 1)); +#endif + tb[jj] = output->output_depth - tb[jj]; + tb[jj+1] = output->output_depth - tb[jj+1]; + tb[jj+2] = output->output_depth - tb[jj+2]; + } + (void) fwrite(&tb[0], sizeof(char), (size_t) (8*3), write_fd); + } + for (j=0,jj=0; j < crumbs; j++,jj+=3) { +#if !defined OUTPUT_CMYK_ONLY_K && !defined OUTPUT_CMYK_ONLY_CMY + tb[jj] = ((((cyan_buf[wholebytes]|black_buf[wholebytes]) >> (7-j)) & 1)); + tb[jj+1] = ((((magenta_buf[wholebytes]|black_buf[wholebytes]) >> (7-j)) & 1)); + tb[jj+2] = ((((yellow_buf[wholebytes]|black_buf[wholebytes]) >> (7-j)) & 1)); +#endif +#ifdef OUTPUT_CMYK_ONLY_K + tb[jj] = (((black_buf[wholebytes] >> (7-j)) & 1)); + tb[jj+1] = (((black_buf[wholebytes] >> (7-j)) & 1)); + tb[jj+2] = (((black_buf[wholebytes] >> (7-j)) & 1)); +#endif +#ifdef OUTPUT_CMYK_ONLY_CMY + tb[jj] = (((cyan_buf[wholebytes] >> (7-j)) & 1)); + tb[jj+1] = (((magenta_buf[wholebytes] >> (7-j)) & 1)); + tb[jj+2] = (((yellow_buf[wholebytes] >> (7-j)) & 1)); +#endif + tb[jj] = output->output_depth - tb[jj]; + tb[jj+1] = output->output_depth - tb[jj+1]; + tb[jj+2] = output->output_depth - tb[jj+2]; + } + (void) fwrite(&tb[0], sizeof(char), (size_t) crumbs*3, write_fd); + } +} + +/* + * decode_tiff() - Uncompress a TIFF encoded buffer + */ + +int decode_tiff(char *in_buffer, /* I: Data buffer */ + int data_height, /* I: Height of data */ + char *decode_buf, /* O: decoded data */ + int maxlen) /* I: Max height of decode_buf */ +{ +/* The TIFF coding consists of either:- + * + * (0 <= count <= 127) (count+1 bytes of data) for non repeating data + * or + * (-127 <= count <= -1) (data) for 1-count bytes of repeating data + */ + + int count; + int pos = 0; + int dpos = 0; +#ifdef DEBUG + int i; +#endif + + while(pos < data_height ) { + + count = in_buffer[pos]; + + if ((count >= 0) && (count <= 127)) { +#ifdef DEBUG + fprintf(stderr, "%d bytes of nonrepeated data\n", count+1); + fprintf(stderr, "DATA: "); + for (i=0; i< (count+1); i++) { + fprintf(stderr, "%02x ", (unsigned char) in_buffer[pos + 1 + i]); + } + fprintf(stderr, "\n"); +#endif + if ((dpos + count + 1) > maxlen) { + fprintf(stderr, "ERROR: Too much expanded data (%d), increase MAX_DATA!\n", dpos + count + 1); + exit(EXIT_FAILURE); + } + memcpy(&decode_buf[dpos], &in_buffer[pos+1], (size_t) (count + 1)); + dpos += count + 1; + pos += count + 2; + } + else if ((count >= -127) && (count < 0)) { +#ifdef DEBUG + fprintf(stderr, "%02x repeated %d times\n", (unsigned char) in_buffer[pos + 1], 1 - count); +#endif + if ((dpos + 1 - count) > maxlen) { + fprintf(stderr, "ERROR: Too much expanded data (%d), increase MAX_DATA!\n", dpos + 1 - count); + exit(EXIT_FAILURE); + } + memset(&decode_buf[dpos], in_buffer[pos + 1], (size_t) (1 - count)); + dpos += 1 - count; + pos += 2; + } + else { + fprintf(stderr, "ERROR: Illegal TIFF count: %d, skipped\n", count); + pos += 2; + } + } + +#ifdef DEBUG + fprintf(stderr, "TIFFOUT: "); + for (i=0; i< dpos; i++) { + fprintf(stderr, "%02x ", (unsigned char) decode_buf[i]); + } + fprintf(stderr, "\n"); +#endif + return(dpos); +} + +/* + * pcl_reset() - Rest image parameters to default + */ + +void pcl_reset(image_t *i) +{ + i->colour_type = PCL_MONO; + i->black_depth = 2; /* Assume mono */ + i->cyan_depth = 0; + i->magenta_depth = 0; + i->yellow_depth = 0; + i->lcyan_depth = 0; + i->lmagenta_depth = 0; + i->image_width = -1; + i->image_height = -1; + i->compression_type = 0; /* should this be NONE? */ +} + +/* + * depth_to_rows() - convert the depth of the colour into the number + * of data rows needed to represent it. Assumes that depth is a power + * of 2, FIXME if not! + */ + +int depth_to_rows(int depth) +{ + int rows; + + if (depth == 0) + return(0); + + for (rows = 1; rows < 8; rows++) { + if ((depth >> rows) == 1) + return(rows); + } + fprintf(stderr, "ERROR: depth %d too big to handle in depth_to_rows()!\n", + depth); + return(0); /* ?? */ +} + +/* + * Main + */ + +int main(int argc, char *argv[]) +{ + + int command_index; + int command; + int i, j; /* Loop/general variables */ + int image_row_counter = -1; /* Count of current row */ + int current_data_row = -1; /* Count of data rows received for this output row */ + int expected_data_rows_per_row = -1; + /* Expected no of data rows per output row */ + image_t image_data; /* Data concerning image */ + long filepos = -1; + +/* + * Holders for the decoded lines + */ + + output_t output_data; + +/* + * The above pointers (when allocated) are then copied into this + * variable in the correct order so that the received data can + * be stored. + */ + + char **received_rows; + + output_data.black_bufs = NULL; /* Storage for black rows */ + output_data.black_data_rows_per_row = 0; /* Number of black rows */ + output_data.cyan_bufs = NULL; + output_data.cyan_data_rows_per_row = 0; + output_data.magenta_bufs = NULL; + output_data.magenta_data_rows_per_row = 0; + output_data.yellow_bufs = NULL; + output_data.yellow_data_rows_per_row = 0; + output_data.lcyan_bufs = NULL; + output_data.lcyan_data_rows_per_row = 0; + output_data.lmagenta_bufs = NULL; + output_data.lmagenta_data_rows_per_row = 0; + output_data.active_height = 0; + + id = id; /* Remove compiler warning */ + received_rows = NULL; + + if(argc == 1){ + read_fd = stdin; + write_fd = stdout; + } + else if(argc == 2){ + read_fd = fopen(argv[1],"r"); + write_fd = stdout; + } + else { + if(*argv[1] == '-'){ + read_fd = stdin; + write_fd = fopen(argv[2],"w"); + } + else { + read_fd = fopen(argv[1],"r"); + write_fd = fopen(argv[2],"w"); + } + } + + if (read_fd == (FILE *)NULL) { + fprintf(stderr, "ERROR: Error Opening input file.\n"); + exit (EXIT_FAILURE); + } + + if (write_fd == (FILE *)NULL) { + fprintf(stderr, "ERROR: Error Opening output file.\n"); + exit (EXIT_FAILURE); + } + + read_pointer=-1; + eof=0; + initial_command_index=0; + initial_command[initial_command_index] = '\0'; + numeric_arg=0; + final_command = '\0'; + + + pcl_reset(&image_data); + + while (1) { + pcl_read_command(); + if (eof == 1) { +#ifdef DEBUG + fprintf(stderr, "EOF while reading command.\n"); +#endif + (void) fclose(read_fd); + (void) fclose(write_fd); + exit(EXIT_SUCCESS); + } + +#ifdef DEBUG + fprintf(stderr, "initial_command: %s, numeric_arg: %d, final_command: %c\n", + initial_command, numeric_arg, final_command); +#endif + + command_index = pcl_find_command(); + if (command_index == -1) { + fprintf(stderr, "ERROR: Unknown (and unhandled) command: %s%d%c\n", initial_command, + numeric_arg, final_command); +/* We may have to skip some data here */ + } + else { + command = pcl_commands[command_index].command; + if (pcl_commands[command_index].has_data == 1) { + +/* Read the data into data_buffer */ + +#ifdef DEBUG + fprintf(stderr, "Data: "); +#endif + + if (numeric_arg > MAX_DATA) { + fprintf(stderr, "ERROR: Too much data (%d), increase MAX_DATA!\n", numeric_arg); + exit(EXIT_FAILURE); + } + + for (i=0; i < numeric_arg; i++) { + fill_buffer(); + if (eof == 1) { + fprintf(stderr, "ERROR: Unexpected EOF whilst reading data\n"); + exit(EXIT_FAILURE); + } + data_buffer[i] = read_buffer[read_pointer++]; + +#ifdef DEBUG + fprintf(stderr, "%02x ", (unsigned char) data_buffer[i]); +#endif + + } + +#ifdef DEBUG + fprintf(stderr, "\n"); +#endif + + } + switch(command) { + case PCL_RESET : + fprintf(stderr, "%s\n", pcl_commands[command_index].description); + pcl_reset(&image_data); + break; + + case PCL_START_RASTER : + fprintf(stderr, "%s\n", pcl_commands[command_index].description); + +/* Make sure we have all the stuff needed to work out what we are going + to write out. */ + + i = 0; /* use as error indicator */ + + if (image_data.image_width == -1) { + fprintf(stderr, "ERROR: Image width not set!\n"); + i++; + } + if (image_data.image_height == -1) { + fprintf(stderr, "WARNING: Image height not set!\n"); + } + + if ((image_data.black_depth != 0) && + (image_data.black_depth != 2)) { + fprintf(stderr, "WARNING: Only 2 level black dithers handled.\n"); + } + if ((image_data.cyan_depth != 0) && + (image_data.cyan_depth != 2)) { + fprintf(stderr, "WARNING: Only 2 level cyan dithers handled.\n"); + } + if ((image_data.magenta_depth != 0) && + (image_data.magenta_depth != 2)) { + fprintf(stderr, "WARNING: Only 2 level magenta dithers handled.\n"); + } + if ((image_data.yellow_depth != 0) && + (image_data.yellow_depth != 2)) { + fprintf(stderr, "WARNING: only 2 level yellow dithers handled.\n"); + } + if (image_data.lcyan_depth != 0) { + fprintf(stderr, "WARNING: Light cyan dithers not yet handled.\n"); + } + if (image_data.lmagenta_depth != 0) { + fprintf(stderr, "WARNING: Light magenta dithers not yet handled.\n"); + } + + if ((image_data.compression_type != PCL_COMPRESSION_NONE) && + (image_data.compression_type != PCL_COMPRESSION_TIFF)) { + fprintf(stderr, + "Sorry, only 'no compression' or 'tiff compression' handled.\n"); + i++; + } + + if (i != 0) { + fprintf(stderr, "Cannot continue.\n"); + exit (EXIT_FAILURE); + } + + if (image_data.colour_type == PCL_MONO) + (void) fputs("P5\n", write_fd); /* Raw, Grey */ + else + (void) fputs("P6\n", write_fd); /* Raw, RGB */ + + (void) fputs("# Written by pclunprint.\n", write_fd); + +/* + * Remember the file position where we wrote the image width and height + * (you don't want to know why!) + */ + + filepos = ftell(write_fd); + + fprintf(write_fd, "%10d %10d\n", image_data.image_width, + image_data.image_height); + +/* + * Write the depth of the image + */ + + if (image_data.black_depth != 0) + output_data.output_depth = image_data.black_depth - 1; + else + output_data.output_depth = image_data.cyan_depth - 1; + fprintf(write_fd, "%d\n", output_data.output_depth); + + image_row_counter = 0; + current_data_row = 0; + + output_data.black_data_rows_per_row = depth_to_rows(image_data.black_depth); + output_data.cyan_data_rows_per_row = depth_to_rows(image_data.cyan_depth); + output_data.magenta_data_rows_per_row = depth_to_rows(image_data.magenta_depth); + output_data.yellow_data_rows_per_row = depth_to_rows(image_data.yellow_depth); + output_data.lcyan_data_rows_per_row = depth_to_rows(image_data.lcyan_depth); + output_data.lmagenta_data_rows_per_row = depth_to_rows(image_data.lmagenta_depth); + +/* + * Allocate some storage for the expected planes + */ + + if (output_data.black_data_rows_per_row != 0) { + output_data.black_bufs = xmalloc(output_data.black_data_rows_per_row * sizeof (char *)); + for (i=0; i < output_data.black_data_rows_per_row; i++) { + output_data.black_bufs[i] = xmalloc(MAX_DATA * sizeof (char)); + } + } + if (output_data.cyan_data_rows_per_row != 0) { + output_data.cyan_bufs = xmalloc(output_data.cyan_data_rows_per_row * sizeof (char *)); + for (i=0; i < output_data.cyan_data_rows_per_row; i++) { + output_data.cyan_bufs[i] = xmalloc(MAX_DATA * sizeof (char)); + } + } + if (output_data.magenta_data_rows_per_row != 0) { + output_data.magenta_bufs = xmalloc(output_data.magenta_data_rows_per_row * sizeof (char *)); + for (i=0; i < output_data.magenta_data_rows_per_row; i++) { + output_data.magenta_bufs[i] = xmalloc(MAX_DATA * sizeof (char)); + } + } + if (output_data.yellow_data_rows_per_row != 0) { + output_data.yellow_bufs = xmalloc(output_data.yellow_data_rows_per_row * sizeof (char *)); + for (i=0; i < output_data.yellow_data_rows_per_row; i++) { + output_data.yellow_bufs[i] = xmalloc(MAX_DATA * sizeof (char)); + } + } + if (output_data.lcyan_data_rows_per_row != 0) { + output_data.lcyan_bufs = xmalloc(output_data.lcyan_data_rows_per_row * sizeof (char *)); + for (i=0; i < output_data.lcyan_data_rows_per_row; i++) { + output_data.lcyan_bufs[i] = xmalloc(MAX_DATA * sizeof (char)); + } + } + if (output_data.lmagenta_data_rows_per_row != 0) { + output_data.lmagenta_bufs = xmalloc(output_data.lmagenta_data_rows_per_row * sizeof (char *)); + for (i=0; i < output_data.lmagenta_data_rows_per_row; i++) { + output_data.lmagenta_bufs[i] = xmalloc(MAX_DATA * sizeof (char)); + } + } + +/* + * Now store the pointers in the right order to make life easier in the + * decoding phase + */ + + expected_data_rows_per_row = output_data.black_data_rows_per_row + + output_data.cyan_data_rows_per_row + output_data.magenta_data_rows_per_row + + output_data.yellow_data_rows_per_row + output_data.lcyan_data_rows_per_row + + output_data.lmagenta_data_rows_per_row; + + received_rows = xmalloc(expected_data_rows_per_row * sizeof(char *)); + j = 0; + for (i = 0; i < output_data.black_data_rows_per_row; i++) + received_rows[j++] = output_data.black_bufs[i]; + for (i = 0; i < output_data.cyan_data_rows_per_row; i++) + received_rows[j++] = output_data.cyan_bufs[i]; + for (i = 0; i < output_data.magenta_data_rows_per_row; i++) + received_rows[j++] = output_data.magenta_bufs[i]; + for (i = 0; i < output_data.yellow_data_rows_per_row; i++) + received_rows[j++] = output_data.yellow_bufs[i]; + for (i = 0; i < output_data.lcyan_data_rows_per_row; i++) + received_rows[j++] = output_data.lcyan_bufs[i]; + for (i = 0; i < output_data.lmagenta_data_rows_per_row; i++) + received_rows[j++] = output_data.lmagenta_bufs[i]; + + break; + + case PCL_END_RASTER : + case PCL_END_RASTER_NEW : + fprintf(stderr, "%s\n", pcl_commands[command_index].description); + +/* + * Check that we got the correct number of rows of data. If the expected number is + * -1, invoke MAJOR BODGERY! + */ + + if (image_data.image_height == -1) { + image_data.image_height = image_row_counter; + if (fseek(write_fd, filepos, SEEK_SET) != -1) { + fprintf(write_fd, "%10d %10d\n", image_data.image_width, + image_data.image_height); + fseek(write_fd, 0L, SEEK_END); + } + } + + if (image_row_counter != image_data.image_height) + fprintf(stderr, "ERROR: Row count mismatch. Expected %d rows, got %d rows.\n", + image_data.image_height, image_row_counter); + else + fprintf(stderr, "\t%d rows processed.\n", image_row_counter); + + if (output_data.black_data_rows_per_row != 0) { + for (i=0; i < output_data.black_data_rows_per_row; i++) { + free(output_data.black_bufs[i]); + } + free(output_data.black_bufs); + output_data.black_bufs = NULL; + } + if (output_data.cyan_data_rows_per_row != 0) { + for (i=0; i < output_data.cyan_data_rows_per_row; i++) { + free(output_data.cyan_bufs[i]); + } + free(output_data.cyan_bufs); + output_data.cyan_bufs = NULL; + } + if (output_data.magenta_data_rows_per_row != 0) { + for (i=0; i < output_data.magenta_data_rows_per_row; i++) { + free(output_data.magenta_bufs[i]); + } + free(output_data.magenta_bufs); + output_data.magenta_bufs = NULL; + } + if (output_data.yellow_data_rows_per_row != 0) { + for (i=0; i < output_data.yellow_data_rows_per_row; i++) { + free(output_data.yellow_bufs[i]); + } + free(output_data.yellow_bufs); + output_data.yellow_bufs = NULL; + } + if (output_data.lcyan_data_rows_per_row != 0) { + for (i=0; i < output_data.lcyan_data_rows_per_row; i++) { + free(output_data.lcyan_bufs[i]); + } + free(output_data.lcyan_bufs); + output_data.lcyan_bufs = NULL; + } + if (output_data.lmagenta_data_rows_per_row != 0) { + for (i=0; i < output_data.lmagenta_data_rows_per_row; i++) { + free(output_data.lmagenta_bufs[i]); + } + free(output_data.lmagenta_bufs); + output_data.lmagenta_bufs = NULL; + } + free(received_rows); + received_rows = NULL; + + break; + + case PCL_MEDIA_SIZE : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 2 : + fprintf(stderr, "Letter\n"); + break; + case 3 : + fprintf(stderr, "Legal\n"); + break; + case 6 : + fprintf(stderr, "Tabloid\n"); + break; + case 26 : + fprintf(stderr, "A4\n"); + break; + case 27 : + fprintf(stderr, "A3\n"); + break; + case 101 : + fprintf(stderr, "Custom\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_MEDIA_TYPE : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 0 : + fprintf(stderr, "Plain\n"); + break; + case 1 : + fprintf(stderr, "Bond\n"); + break; + case 2 : + fprintf(stderr, "Premium\n"); + break; + case 3 : + fprintf(stderr, "Glossy/Photo\n"); + break; + case 4 : + fprintf(stderr, "Transparency\n"); + break; + case 5 : + fprintf(stderr, "Quick-dry Photo\n"); + break; + case 6 : + fprintf(stderr, "Quick-dry Transparency\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_MEDIA_SOURCE : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 0 : + fprintf(stderr, "EJECT\n"); + break; + case 1 : + fprintf(stderr, "LJ Tray 2 or Portable CSF or DJ Tray\n"); + break; + case 2 : + fprintf(stderr, "Manual\n"); + break; + case 3 : + fprintf(stderr, "Envelope\n"); + break; + case 4 : + fprintf(stderr, "LJ Tray 3 or Desktop CSF or DJ Tray 2\n"); + break; + case 5 : + fprintf(stderr, "LJ Tray 4 or DJ optional\n"); + break; + case 7 : + fprintf(stderr, "DJ Autosource\n"); + break; + case 8 : + fprintf(stderr, "LJ Tray 1\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_SHINGLING : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 0 : + fprintf(stderr, "None\n"); + break; + case 1 : + fprintf(stderr, "2 passes\n"); + break; + case 2 : + fprintf(stderr, "4 passes\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_RASTERGRAPHICS_QUALITY : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 0 : + fprintf(stderr, "(set by printer controls)\n"); + case 1 : + fprintf(stderr, "Draft\n"); + break; + case 2 : + fprintf(stderr, "High\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_DEPLETION : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 1 : + fprintf(stderr, "None\n"); + break; + case 2 : + fprintf(stderr, "25%%\n"); + break; + case 3 : + fprintf(stderr, "50%%\n"); + break; + case 5 : + fprintf(stderr, "50%% with gamma correction\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_PRINT_QUALITY : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case -1 : + fprintf(stderr, "Draft\n"); + break; + case 0 : + fprintf(stderr, "Normal\n"); + break; + case 1 : + fprintf(stderr, "Presentation\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", numeric_arg); + break; + } + break; + + case PCL_RELATIVE_VERTICAL_PIXEL_MOVEMENT : + fprintf(stderr, "%s: %d\n", pcl_commands[command_index].description, numeric_arg); + +/* Check that we are in raster mode */ + + if (expected_data_rows_per_row == -1) + fprintf(stderr, "ERROR: raster data without start raster!\n"); + +/* + What we need to do now is to write out "N" rows of all-white data to + simulate the vertical slew +*/ + + for (i=0; i<expected_data_rows_per_row; i++) + { + memset(received_rows[i], 0, (size_t) MAX_DATA * sizeof(char)); + } + for (i=0; i<numeric_arg; i++) + { + if (image_data.colour_type == PCL_MONO) + write_grey(&output_data, &image_data); + else + write_colour(&output_data, &image_data); + image_row_counter++; + } + break; + + case PCL_PERF_SKIP : + case PCL_TOP_MARGIN : + case PCL_RESOLUTION : + case PCL_LEFTRASTER_POS : + case PCL_TOPRASTER_POS : + case PCL_VERTICAL_CURSOR_POSITIONING_BY_DOTS : + case PCL_HORIZONTAL_CURSOR_POSITIONING_BY_DOTS : + case PCL_PALETTE_CONFIGURATION : + case PCL_UNIT_OF_MEASURE : + case PCL_GRAY_BALANCE : + case PCL_DRIVER_CONFIG : + fprintf(stderr, "%s: %d (ignored)", pcl_commands[command_index].description, numeric_arg); + if (pcl_commands[command_index].has_data == 1) { + fprintf(stderr, " Data: "); + for (i=0; i < numeric_arg; i++) { + fprintf(stderr, "%02x ", (unsigned char) data_buffer[i]); + } + } + fprintf(stderr, "\n"); + break; + + case PCL_COLOURTYPE : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + image_data.colour_type = -numeric_arg; + switch (image_data.colour_type) { + case PCL_MONO : + fprintf(stderr, "MONO\n"); + break; + case PCL_CMY : + fprintf(stderr, "CMY (one cart)\n"); + image_data.black_depth = 0; /* Black levels */ + image_data.cyan_depth = 2; /* Cyan levels */ + image_data.magenta_depth = 2; /* Magenta levels */ + image_data.yellow_depth = 2; /* Yellow levels */ + break; + case PCL_CMYK : + fprintf(stderr, "CMYK (two cart)\n"); + image_data.black_depth = 2; /* Black levels */ + image_data.cyan_depth = 2; /* Cyan levels */ + image_data.magenta_depth = 2; /* Magenta levels */ + image_data.yellow_depth = 2; /* Yellow levels */ + break; + default : + fprintf(stderr, "Unknown (%d)\n", -numeric_arg); + break; + } + break; + + case PCL_COMPRESSIONTYPE : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + image_data.compression_type = numeric_arg; + switch (image_data.compression_type) { + case PCL_COMPRESSION_NONE : + fprintf(stderr, "NONE\n"); + break; + case PCL_COMPRESSION_RUNHEIGHT : + fprintf(stderr, "Runheight\n"); + break; + case PCL_COMPRESSION_TIFF : + fprintf(stderr, "TIFF\n"); + break; + case PCL_COMPRESSION_CRDR : + fprintf(stderr, "Compressed Row Delta Replacement\n"); + break; + default : + fprintf(stderr, "Unknown (%d)\n", image_data.compression_type); + break; + } + break; + + case PCL_RASTER_WIDTH : + fprintf(stderr, "%s: %d\n", pcl_commands[command_index].description, numeric_arg); + image_data.image_width = numeric_arg; + break; + + case PCL_RASTER_HEIGHT : + fprintf(stderr, "%s: %d\n", pcl_commands[command_index].description, numeric_arg); + image_data.image_height = numeric_arg; + break; + + case PCL_CONFIGURE : + fprintf(stderr, "%s (size=%d)\n", pcl_commands[command_index].description, + numeric_arg); + fprintf(stderr, "\tFormat: %d\n", data_buffer[0]); + if (data_buffer[0] == 2) { + +/* + * the data that follows depends on the colour type (buffer[1]). The size + * of the data should be 2 + (6 * number of planes). + */ + + fprintf(stderr, "\tOutput Planes: "); + image_data.colour_type = data_buffer[1]; /* # output planes */ + switch (image_data.colour_type) { + case PCL_MONO : + fprintf(stderr, "MONO\n"); + +/* Size should be 8 */ + + if (numeric_arg != 8) + fprintf(stderr, "ERROR: Expected 8 bytes of data, got %d\n", numeric_arg); + + fprintf(stderr, "\tBlack: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[2]<<8)+(unsigned char)data_buffer[3], + ((unsigned char) data_buffer[4]<<8)+(unsigned char) data_buffer[5], data_buffer[7]); + image_data.black_depth = data_buffer[7]; /* Black levels */ + break; + case PCL_CMY : + fprintf(stderr, "CMY (one cart)\n"); + +/* Size should be 20 */ + + if (numeric_arg != 20) + fprintf(stderr, "ERROR: Expected 20 bytes of data, got %d\n", numeric_arg); + + fprintf(stderr, "\tCyan: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[2]<<8)+(unsigned char) data_buffer[3], + ((unsigned char) data_buffer[4]<<8)+(unsigned char) data_buffer[5], data_buffer[7]); + fprintf(stderr, "\tMagenta: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[8]<<8)+(unsigned char) data_buffer[9], + ((unsigned char) data_buffer[10]<<8)+(unsigned char) data_buffer[11], data_buffer[13]); + fprintf(stderr, "\tYellow: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[14]<<8)+(unsigned char) data_buffer[15], + ((unsigned char) data_buffer[16]<<8)+(unsigned char) data_buffer[17], data_buffer[19]); + image_data.black_depth = 0; + image_data.cyan_depth = data_buffer[7]; /* Cyan levels */ + image_data.magenta_depth = data_buffer[13]; /* Magenta levels */ + image_data.yellow_depth = data_buffer[19]; /* Yellow levels */ + break; + case PCL_CMYK : + fprintf(stderr, "CMYK (two cart)\n"); + +/* Size should be 26 */ + + if (numeric_arg != 26) + fprintf(stderr, "ERROR: Expected 26 bytes of data, got %d\n", numeric_arg); + + fprintf(stderr, "\tBlack: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[2]<<8)+(unsigned char) data_buffer[3], + ((unsigned char) data_buffer[4]<<8)+(unsigned char) data_buffer[5], data_buffer[7]); + fprintf(stderr, "\tCyan: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[8]<<8)+(unsigned char) data_buffer[9], + ((unsigned char) data_buffer[10]<<8)+(unsigned char) data_buffer[11], data_buffer[13]); + fprintf(stderr, "\tMagenta: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[14]<<8)+(unsigned char) data_buffer[15], + ((unsigned char) data_buffer[16]<<8)+(unsigned char) data_buffer[17], data_buffer[19]); + fprintf(stderr, "\tYellow: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[20]<<8)+(unsigned char) data_buffer[21], + ((unsigned char) data_buffer[22]<<8)+(unsigned char) data_buffer[23], data_buffer[25]); + image_data.black_depth = data_buffer[7]; /* Black levels */ + image_data.cyan_depth = data_buffer[13]; /* Cyan levels */ + image_data.magenta_depth = data_buffer[19]; /* Magenta levels */ + image_data.yellow_depth = data_buffer[25]; /* Yellow levels */ + break; + case PCL_CMYKcm : + fprintf(stderr, "CMYKcm (two cart photo)\n"); + +/* Size should be 38 */ + + if (numeric_arg != 38) + fprintf(stderr, "ERROR: Expected 38 bytes of data, got %d\n", numeric_arg); + + fprintf(stderr, "\tBlack: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[2]<<8)+(unsigned char) data_buffer[3], + ((unsigned char) data_buffer[4]<<8)+(unsigned char) data_buffer[5], data_buffer[7]); + fprintf(stderr, "\tCyan: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[8]<<8)+(unsigned char) data_buffer[9], + ((unsigned char) data_buffer[10]<<8)+(unsigned char) data_buffer[11], data_buffer[13]); + fprintf(stderr, "\tMagenta: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[14]<<8)+(unsigned char) data_buffer[15], + ((unsigned char) data_buffer[16]<<8)+(unsigned char) data_buffer[17], data_buffer[19]); + fprintf(stderr, "\tYellow: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[20]<<8)+(unsigned char) data_buffer[21], + ((unsigned char) data_buffer[22]<<8)+(unsigned char) data_buffer[23], data_buffer[25]); + fprintf(stderr, "\tLight Cyan: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[26]<<8)+(unsigned char) data_buffer[27], + ((unsigned char) data_buffer[28]<<8)+(unsigned char) data_buffer[29], data_buffer[31]); + fprintf(stderr, "\tLight Magenta: X dpi: %d, Y dpi: %d, Levels: %d\n", ((unsigned char) data_buffer[32]<<8)+(unsigned char) data_buffer[33], + ((unsigned char) data_buffer[34]<<8)+(unsigned char) data_buffer[35], data_buffer[37]); + image_data.black_depth = data_buffer[7]; /* Black levels */ + image_data.cyan_depth = data_buffer[13]; /* Cyan levels */ + image_data.magenta_depth = data_buffer[19]; /* Magenta levels */ + image_data.yellow_depth = data_buffer[25]; /* Yellow levels */ + image_data.lcyan_depth = data_buffer[31]; /* Cyan levels */ + image_data.lmagenta_depth = data_buffer[37]; /* Magenta levels */ + break; + default : + fprintf(stderr, "Unknown (%d)\n", data_buffer[1]); + break; + } + } + else { + fprintf(stderr, "Unknown format %d\n", data_buffer[0]); + fprintf(stderr, "Data: "); + for (i=0; i < numeric_arg; i++) { + fprintf(stderr, "%02x ", (unsigned char) data_buffer[i]); + } + fprintf(stderr, "\n"); + } + break; + + case PCL_DATA : + case PCL_DATA_LAST : +#ifdef DEBUG + fprintf(stderr, "%s\n", pcl_commands[command_index].description); + fprintf(stderr, "Data Height: %d\n", numeric_arg); +#endif + +/* + * Make sure that we have enough data to process this command! + */ + + if (expected_data_rows_per_row == -1) + fprintf(stderr, "ERROR: raster data without start raster!\n"); + +/* + * The last flag indicates that this is the end of the planes for a row + * so we check it against the number of planes we have seen and are + * expecting. + */ + + if (command == PCL_DATA_LAST) { + if (current_data_row != (expected_data_rows_per_row - 1)) + fprintf(stderr, "ERROR: 'Last Plane' set on plane %d of %d!\n", + current_data_row, expected_data_rows_per_row); + } + else { + if (current_data_row == (expected_data_rows_per_row - 1)) + fprintf(stderr, "ERROR: Expected 'last plane', but not set!\n"); + } + +/* + * Accumulate the data rows for each output row,then write the image. + */ + + if (image_data.compression_type == PCL_COMPRESSION_NONE) { + memcpy(received_rows[current_data_row], &data_buffer, (size_t) numeric_arg); + output_data.active_height = numeric_arg; + } + else + output_data.active_height = decode_tiff(data_buffer, numeric_arg, received_rows[current_data_row], MAX_DATA); + + if (command == PCL_DATA_LAST) { + if (image_data.colour_type == PCL_MONO) + write_grey(&output_data, &image_data); + else + write_colour(&output_data, &image_data); + current_data_row = 0; + image_row_counter++; + } + else + current_data_row++; + + break; + + case PCL_PJL_COMMAND : { + int c; + fprintf(stderr, "%s\n", pcl_commands[command_index].description); + +/* + * This is a special command, actually it is a PJL instruction. Read up + * to the next ESC and output it. + */ + + c = 0; + while (1) { + fill_buffer(); + if (eof == 1) { + fprintf(stderr, "\n"); + break; + } + c = read_buffer[read_pointer++]; + if (c == '\033') + break; + fprintf(stderr, "%c", c); + } + +/* + * Now we are sitting at the "ESC" that is the start of the next command. + */ + read_pointer--; + fprintf(stderr, "\n"); + fprintf(stderr, "End of %s\n", pcl_commands[command_index].description); + } + break; + + case PCL_PAGE_ORIENTATION : + fprintf(stderr, "%s: ", pcl_commands[command_index].description); + switch (numeric_arg) { + case 0 : + fprintf(stderr, "Portrait"); + break; + case 1 : + fprintf(stderr, "Landscape"); + break; + case 2 : + fprintf(stderr, "Reverse Portrait"); + break; + case 3 : + fprintf(stderr, "Reverse Landscape"); + break; + default : + fprintf(stderr, "Unknown (%d)", numeric_arg); + break; + } + fprintf(stderr, " (ignored)\n"); + break; + + default : + fprintf(stderr, "ERROR: No handler for %s!\n", pcl_commands[command_index].description); + break; + } + } + } +} diff --git a/test/run-weavetest b/test/run-weavetest new file mode 100755 index 0000000..c6c0cde --- /dev/null +++ b/test/run-weavetest @@ -0,0 +1,43 @@ +#!/bin/sh + +echo 'run-weavetest may take over an hour to complete. Please wait...' + +modes='15,3 15,6 21,4 21,8 32,4 32,8 48,3 48,6 60,1 60,2 60,4 64,2 64,4 96,2 96,4 128,1 128,2 128,4 128,8 144,1 144,2 144,4 180,1 180,2 180,4 192,1 192,2' +passes='1,1,1 2,1,1 1,2,1 1,2,2 1,4,1 4,1,1 4,2,1 2,2,1 1,4,2 2,2,2 2,4,2 8,1,1' + +jets='1 2 4 8 15 20 21 24 32 47 48 60 64 96 128 144 180 192' +separations='1 2 3 4 6 8' +arrangements='0 1' +#rows=2000 +head_limit=768 + +if [ $# -eq 0 ] ; then + extracmd='grep [a-z]' +else + extracmd=cat +fi + +(for jet in $jets ; do + for sep in $separations ; do + for pass in $passes ; do + for arrangement in $arrangements; do + ((start = $jet * $sep)) + if [ $start -le $head_limit ] ; then + ((rows = $start * 10)) + if [ $rows -lt 200 ] ; then + rows=200 + fi + ((s1 = $start - 1)) + for f in 0 41 $start $s1 ; do + ((end = $rows + $f + $start)) + ((end1 = $rows + $f)) + ((end2 = $rows + $f + 35)) + for g in $end $end1 $end2 ; do + echo "$jet $sep $pass $rows $f $g $arrangement" + done + done + fi + done + done + done +done) | sed 's/,/ /g' | ./escp2-weavetest | $extracmd diff --git a/test/testdither.c b/test/testdither.c new file mode 100644 index 0000000..2733f8b --- /dev/null +++ b/test/testdither.c @@ -0,0 +1,740 @@ +/* + * "$Id: testdither.c,v 1.11 2001/09/02 13:30:27 rlk Exp $" + * + * Test/profiling program for dithering code. + * + * Copyright 1997-2000 Michael Sweet (mike@easysw.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifdef INCLUDE_GIMP_PRINT_H +#include INCLUDE_GIMP_PRINT_H +#else +#include <gimp-print/gimp-print.h> +#endif +#include "../lib/libprintut.h" +#include "../src/main/gimp-print-internal.h" +#include <stdio.h> +#include <sys/time.h> +#include <unistd.h> + +/* + * NOTE: writing of 2-bit dither images is currently broken due to the + * separated planes generated by the dither functions. + */ + + +/* + * Definitions for dither test... + */ + +#define IMAGE_WIDTH 5760 /* 8in * 720dpi */ +#define IMAGE_HEIGHT 720 /* 4in * 720dpi */ +#define BUFFER_SIZE IMAGE_WIDTH + +#define IMAGE_MIXED 0 /* Mix of line types */ +#define IMAGE_WHITE 1 /* All white image */ +#define IMAGE_BLACK 2 /* All black image */ +#define IMAGE_COLOR 3 /* All color image */ +#define IMAGE_RANDOM 4 /* All random image */ + +#define DITHER_GRAY 0 /* Dither grayscale pixels */ +#define DITHER_COLOR 1 /* Dither color pixels */ +#define DITHER_PHOTO 2 /* Dither photo pixels */ + + +/* + * Globals... + */ + +int image_type = IMAGE_MIXED; +int dither_type = DITHER_COLOR; +int dither_bits = 1; +unsigned short white_line[IMAGE_WIDTH * 3], + black_line[IMAGE_WIDTH * 3], + color_line[IMAGE_WIDTH * 3], + random_line[IMAGE_WIDTH * 3]; + + +stp_simple_dither_range_t normal_1bit_ranges[] = +{ + { 1.0, 0x1, 1, 1 } +}; + +stp_simple_dither_range_t normal_2bit_ranges[] = +{ + { 0.45, 0x1, 1, 1 }, + { 0.68, 0x2, 1, 2 }, + { 1.0, 0x3, 1, 3 } +}; + +stp_simple_dither_range_t photo_1bit_ranges[] = +{ + { 0.33, 0x1, 0, 1 }, + { 1.0, 0x1, 1, 1 } +}; + +stp_simple_dither_range_t photo_2bit_ranges[] = +{ + { 0.15, 0x1, 0, 1 }, + { 0.227, 0x2, 0, 2 }, + { 0.45, 0x1, 1, 1 }, + { 0.68, 0x2, 1, 2 }, + { 1.0, 0x3, 1, 3 } +}; + + +double compute_interval(struct timeval *tv1, struct timeval *tv2); +void image_init(void); +void image_get_row(unsigned short *data, int row); +void write_gray(FILE *fp, unsigned char *black); +void write_color(FILE *fp, unsigned char *cyan, unsigned char *magenta, + unsigned char *yellow, unsigned char *black); +void write_photo(FILE *fp, unsigned char *cyan, unsigned char *lcyan, + unsigned char *magenta, unsigned char *lmagenta, + unsigned char *yellow, unsigned char *black); + + +double +compute_interval(struct timeval *tv1, struct timeval *tv2) +{ + return ((double) tv2->tv_sec + (double) tv2->tv_usec / 1000000.) - + ((double) tv1->tv_sec + (double) tv1->tv_usec / 1000000.); +} + +/* + * 'main()' - Test dithering code for performance measurement. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j; /* Looping vars */ + unsigned char black[BUFFER_SIZE], /* Black bitmap data */ + cyan[BUFFER_SIZE], /* Cyan bitmap data */ + magenta[BUFFER_SIZE], /* Magenta bitmap data */ + lcyan[BUFFER_SIZE], /* Light cyan bitmap data */ + lmagenta[BUFFER_SIZE], /* Light magenta bitmap data */ + yellow[BUFFER_SIZE]; /* Yellow bitmap data */ + void *dither; /* Dither data */ + unsigned short rgb[IMAGE_WIDTH * 3], /* RGB buffer */ + gray[IMAGE_WIDTH]; /* Grayscale buffer */ + int write_image; /* Write the image to disk? */ + FILE *fp; /* PPM/PGM output file */ + char filename[1024]; /* Name of file */ + stp_vars_t v; /* Dither variables */ + static const char *dither_types[] = /* Different dithering modes */ + { + "gray", + "color", + "photo" + }; + static const char *image_types[] = /* Different image types */ + { + "mixed", + "white", + "black", + "color", + "random" + }; + struct timeval tv1, tv2; + + /* + * Initialise libgimpprint + */ + + stp_init(); + v = stp_allocate_vars(); + + /* + * Get command-line args... + */ + + write_image = 1; + + for (i = 1; i < argc; i ++) + { + if (strcmp(argv[i], "no-image") == 0) + { + write_image = 0; + continue; + } + + if (strcmp(argv[i], "1-bit") == 0) + { + dither_bits = 1; + continue; + } + + if (strcmp(argv[i], "2-bit") == 0) + { + dither_bits = 2; + continue; + } + + for (j = 0; j < 3; j ++) + if (strcmp(argv[i], dither_types[j]) == 0) + break; + + if (j < 3) + { + dither_type = j; + continue; + } + + for (j = 0; j < 5; j ++) + if (strcmp(argv[i], image_types[j]) == 0) + break; + + if (j < 3) + { + image_type = j; + continue; + } + + printf("Unknown option \"%s\" ignored!\n", argv[i]); + } + + /* + * Setup the image and color functions... + */ + + image_init(); + + /* + * Output the page... + */ + + stp_set_dither_algorithm(v, "Adaptive Hybrid"); + + dither = stp_init_dither(IMAGE_WIDTH, IMAGE_WIDTH, 1, 1, v); + + for (i = 0; i < NCOLORS; i++) + stp_dither_set_black_level(dither, i, 1.0); + + if (dither_type == DITHER_PHOTO) + stp_dither_set_black_lower(dither, 0.4 / dither_bits + 0.1); + else + stp_dither_set_black_lower(dither, 0.25 / dither_bits); + + stp_dither_set_black_upper(dither, 0.5); + + switch (dither_type) + { + case DITHER_GRAY : + switch (dither_bits) + { + case 1 : + stp_dither_set_ranges(dither, ECOLOR_K, 1, normal_1bit_ranges, 1.0); + break; + case 2 : + stp_dither_set_transition(dither, 0.5); + stp_dither_set_ranges(dither, ECOLOR_K, 3, normal_2bit_ranges, 1.0); + break; + } + break; + case DITHER_COLOR : + switch (dither_bits) + { + case 1 : + stp_dither_set_ranges(dither, ECOLOR_C, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 1, normal_1bit_ranges, 1.0); + break; + case 2 : + stp_dither_set_transition(dither, 0.5); + stp_dither_set_ranges(dither, ECOLOR_C, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 3, normal_2bit_ranges, 1.0); + break; + } + break; + case DITHER_PHOTO : + switch (dither_bits) + { + case 1 : + stp_dither_set_ranges(dither, ECOLOR_C, 2, photo_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 2, photo_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 1, normal_1bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 1, normal_1bit_ranges, 1.0); + break; + case 2 : + stp_dither_set_transition(dither, 0.7); + stp_dither_set_ranges(dither, ECOLOR_C, 5, photo_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_M, 5, photo_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_Y, 3, normal_2bit_ranges, 1.0); + stp_dither_set_ranges(dither, ECOLOR_K, 3, normal_2bit_ranges, 1.0); + break; + } + break; + } + + stp_dither_set_ink_spread(dither, 12 + dither_bits); + stp_dither_set_density(dither, 1.0); + + /* + * Open the PPM/PGM file... + */ + + if (write_image) + { + sprintf(filename, "%s-%s-%dbit.%s", image_types[image_type], + dither_types[dither_type], dither_bits, + dither_type == DITHER_GRAY ? "pgm" : "ppm"); + + if ((fp = fopen(filename, "wb")) != NULL) + { + puts(filename); + if (dither_type == DITHER_GRAY) + fputs("P5\n", fp); + else + fputs("P6\n", fp); + + fprintf(fp, "%d\n%d\n255\n", IMAGE_WIDTH, IMAGE_HEIGHT); + } + else + perror(filename); + } + else + fp = NULL; + + /* + * Now dither the "page"... + */ + + (void) gettimeofday(&tv1, NULL); + + for (i = 0; i < IMAGE_HEIGHT; i ++) + { + if ((i & 15) == 0) + { + printf("\rProcessing row %d...", i); + fflush(stdout); + } + + switch (dither_type) + { + case DITHER_GRAY : + image_get_row(gray, i); + stp_dither(gray, i, dither, 0, 0, 0, 0, 0, 0, black, 0, 0); + if (fp) + write_gray(fp, black); + break; + case DITHER_COLOR : + image_get_row(rgb, i); + stp_dither(rgb, i, dither, cyan, 0, magenta, 0, + yellow, 0, black, 0, 0); + if (fp) + write_color(fp, cyan, magenta, yellow, black); + break; + case DITHER_PHOTO : + image_get_row(rgb, i); + stp_dither(rgb, i, dither, cyan, lcyan, magenta, lmagenta, + yellow, 0, black, 0, 0); + if (fp) + write_photo(fp, cyan, lcyan, magenta, lmagenta, yellow, black); + break; + } + } + + (void) gettimeofday(&tv2, NULL); + + stp_free_dither(dither); + + if (fp != NULL) + fclose(fp); + + printf("\rTotal dither time for %d pixels is %.3f seconds, or %.2f pixels/sec.\n", + IMAGE_WIDTH * IMAGE_HEIGHT, compute_interval(&tv1, &tv2), + (float)(IMAGE_WIDTH * IMAGE_HEIGHT) / compute_interval(&tv1, &tv2)); + return 0; +} + + +void +image_get_row(unsigned short *data, + int row) +{ + unsigned short *src; + + + switch (image_type) + { + case IMAGE_MIXED : + switch ((row / 100) & 3) + { + case 0 : + src = white_line; + break; + case 1 : + src = color_line; + break; + case 2 : + src = black_line; + break; + case 3 : + default: + src = random_line; + break; + } + break; + case IMAGE_WHITE : + src = white_line; + break; + case IMAGE_BLACK : + src = black_line; + break; + case IMAGE_COLOR : + src = color_line; + break; + case IMAGE_RANDOM : + default: + src = random_line; + break; + } + + if (dither_type == DITHER_GRAY) + memcpy(data, src, IMAGE_WIDTH * 2); + else + memcpy(data, src, IMAGE_WIDTH * 6); +} + + +void +image_init(void) +{ + int i, j; + unsigned short *cptr, + *rptr; + + + /* + * Set the white and black line data... + */ + + memset(white_line, 255, sizeof(white_line)); + memset(black_line, 0, sizeof(black_line)); + + /* + * Fill in the color and random data... + */ + + for (i = IMAGE_WIDTH, cptr = color_line, rptr = random_line; i > 0; i --) + { + /* + * Do 64 color or grayscale blocks over the line... + */ + + j = i / (IMAGE_WIDTH / 64); + + if (dither_type == DITHER_GRAY) + *cptr++ = 65535 * j / 63; + else + { + *cptr++ = 65535 * (j >> 4) / 3; + *cptr++ = 65535 * ((j >> 2) & 3) / 3; + *cptr++ = 65535 * (j & 3) / 3; + } + + /* + * Do random colors over the line... + */ + + *rptr++ = 65535 * (rand() & 255) / 255; + if (dither_type != DITHER_GRAY) + { + *rptr++ = 65535 * (rand() & 255) / 255; + *rptr++ = 65535 * (rand() & 255) / 255; + } + } +} + + +void +write_gray(FILE *fp, + unsigned char *black) +{ + int count; + unsigned char byte, + bit, + shift; + + + if (dither_bits == 1) + { + for (count = IMAGE_WIDTH, byte = *black++, bit = 128; count > 0; count --) + { + if (byte & bit) + putc(0, fp); + else + putc(255, fp); + + if (bit > 1) + bit >>= 1; + else + { + byte = *black++; + bit = 128; + } + } + } + else + { + for (count = IMAGE_WIDTH, byte = *black++, shift = 6; count > 0; count --) + { + putc(255 - 255 * ((byte >> shift) & 3) / 3, fp); + + if (shift > 0) + shift -= 2; + else + { + byte = *black++; + shift = 6; + } + } + } +} + + +void +write_color(FILE *fp, + unsigned char *cyan, + unsigned char *magenta, + unsigned char *yellow, + unsigned char *black) +{ + int count; + unsigned char cbyte, + mbyte, + ybyte, + kbyte, + bit, + shift; + int r, g, b, k; + + + if (dither_bits == 1) + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, mbyte = *magenta++, + ybyte = *yellow++, kbyte = *black++, bit = 128; + count > 0; + count --) + { + if (kbyte & bit) + { + putc(0, fp); + putc(0, fp); + putc(0, fp); + } + else + { + if (cbyte & bit) + putc(0, fp); + else + putc(255, fp); + + if (mbyte & bit) + putc(0, fp); + else + putc(255, fp); + + if (ybyte & bit) + putc(0, fp); + else + putc(255, fp); + } + + if (bit > 1) + bit >>= 1; + else + { + cbyte = *cyan++; + mbyte = *magenta++; + ybyte = *yellow++; + kbyte = *black++; + bit = 128; + } + } + } + else + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, mbyte = *magenta++, + ybyte = *yellow++, kbyte = *black++, shift = 6; + count > 0; + count --) + { + k = 255 * ((kbyte >> shift) & 3) / 3; + r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - k; + g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - k; + b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k; + + if (r < 0) + putc(0, fp); + else + putc(r, fp); + + if (g < 0) + putc(0, fp); + else + putc(g, fp); + + if (b < 0) + putc(0, fp); + else + putc(b, fp); + + if (shift > 0) + shift -= 2; + else + { + cbyte = *cyan++; + mbyte = *magenta++; + ybyte = *yellow++; + kbyte = *black++; + shift = 6; + } + } + } +} + + +void +write_photo(FILE *fp, + unsigned char *cyan, + unsigned char *lcyan, + unsigned char *magenta, + unsigned char *lmagenta, + unsigned char *yellow, + unsigned char *black) +{ + int count; + unsigned char cbyte, + lcbyte, + mbyte, + lmbyte, + ybyte, + kbyte, + bit, + shift; + int r, g, b, k; + + + if (dither_bits == 1) + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, lcbyte = *lcyan++, + mbyte = *magenta++, lmbyte = *lmagenta++, + ybyte = *yellow++, kbyte = *black++, bit = 128; + count > 0; + count --) + { + if (kbyte & bit) + { + putc(0, fp); + putc(0, fp); + putc(0, fp); + } + else + { + if (cbyte & bit) + putc(0, fp); + else if (lcbyte & bit) + putc(127, fp); + else + putc(255, fp); + + if (mbyte & bit) + putc(0, fp); + else if (lmbyte & bit) + putc(127, fp); + else + putc(255, fp); + + if (ybyte & bit) + putc(0, fp); + else + putc(255, fp); + } + + if (bit > 1) + bit >>= 1; + else + { + cbyte = *cyan++; + lcbyte = *lcyan++; + mbyte = *magenta++; + lmbyte = *lmagenta++; + ybyte = *yellow++; + kbyte = *black++; + bit = 128; + } + } + } + else + { + for (count = IMAGE_WIDTH, cbyte = *cyan++, lcbyte = *lcyan++, + mbyte = *magenta++, lmbyte = *lmagenta++, + ybyte = *yellow++, kbyte = *black++, shift = 6; + count > 0; + count --) + { + k = 255 * ((kbyte >> shift) & 3) / 3; + r = 255 - 255 * ((cbyte >> shift) & 3) / 3 - + 127 * ((lcbyte >> shift) & 3) / 3 - k; + g = 255 - 255 * ((mbyte >> shift) & 3) / 3 - + 127 * ((lmbyte >> shift) & 3) / 3 - k; + b = 255 - 255 * ((ybyte >> shift) & 3) / 3 - k; + + if (r < 0) + putc(0, fp); + else + putc(r, fp); + + if (g < 0) + putc(0, fp); + else + putc(g, fp); + + if (b < 0) + putc(0, fp); + else + putc(b, fp); + + if (shift > 0) + shift -= 2; + else + { + cbyte = *cyan++; + lcbyte = *lcyan++; + mbyte = *magenta++; + lmbyte = *lmagenta++; + ybyte = *yellow++; + kbyte = *black++; + shift = 6; + } + } + } +} + + +/* + * End of "$Id: testdither.c,v 1.11 2001/09/02 13:30:27 rlk Exp $". + */ diff --git a/test/unprint.c b/test/unprint.c new file mode 100644 index 0000000..0084984 --- /dev/null +++ b/test/unprint.c @@ -0,0 +1,1616 @@ +/* $Id: unprint.c,v 1.22 2001/09/29 02:32:11 rlk Exp $ */ +/* + * Generate PPM files from printer output + * + * Copyright 2000-2001 Eric Sharkey <sharkey@superk.physics.sunysb.edu> + * Andy Thaller <thaller@ph.tum.de> + * Robert Krawitz <rlk@alum.mit.edu> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "../lib/libprintut.h" +#include<stdio.h> +#include<stdlib.h> +#include<limits.h> +#include<string.h> + +#ifdef __GNUC__ +#define inline __inline__ +#endif + +/* + * Printer state variable. + */ +typedef struct { + unsigned char unidirectional; + unsigned char microweave; + int page_management_units; /* dpi */ + int relative_horizontal_units; /* dpi */ + int absolute_horizontal_units; /* dpi, assumed to be >= relative */ + int relative_vertical_units; /* dpi */ + int absolute_vertical_units; /* dpi, assumed to be >= relative */ + int horizontal_spacing; /* Horizontal dot spacing */ + int top_margin; /* dots */ + int bottom_margin; /* dots */ + int page_height; /* dots */ + int dotsize; + int bpp; /* bits per pixel */ + int current_color; + int xposition; /* dots */ + int yposition; /* dots */ + int monomode; + int nozzle_separation; + int nozzles; + int extraskip; + int got_graphics; + int left_edge; + int right_edge; + int top_edge; + int bottom_edge; +} pstate_t; + +/* We'd need about a gigabyte of ram to hold a ppm file of an 8.5 x 11 + * 1440 x 720 dpi page. That's more than I have in my laptop, so, let's + * play some games to reduce memory. Allocate each scan line separately, + * and don't require that the allocated height be full page width. This + * way, if we only want to print a 2x2 image, we only need to allocate the + * ram that we need. We'll build up the printed image in ram at low + * color depth, KCMYcm color basis, and then write out the RGB ppm file + * as output. This way we never need to have the full data in RAM at any + * time. 2 bits per color of KCMYcm is half the size of 8 bits per color + * of RGB. + * + * We would like to be able to print in bands, so that we don't have to + * read the entire page into memory in order to print it. Unfortunately, + * we may not know what the left and right margins are until we've read the + * entire file. If we can read it in two passes we could do it; use one + * pass to scan the file looking at the margins, and another pass to + * actually read in the data. This optimization may be worthwhile. + */ + +#define MAX_INKS 7 +typedef struct { + unsigned char *line[MAX_INKS]; + int startx[MAX_INKS]; + int stopx[MAX_INKS]; +} line_type; + +typedef unsigned char ppmpixel[3]; + +unsigned char *buf; +unsigned valid_bufsize; +unsigned char minibuf[256]; +unsigned bufsize; +unsigned save_bufsize; +unsigned char ch; +unsigned short sh; +int eject = 0; +int global_counter = 0; +int global_count = 0; + +pstate_t pstate; +int unweave; + +line_type **page=NULL; + +/* Color Codes: + color Epson1 Epson2 Sequential + Black 0 0 0 + Magenta 1 1 1 + Cyan 2 2 2 + Yellow 4 4 3 + L.Mag. 17 257 4 + L.Cyan 18 258 5 + L.Yellow NA NA 6 + */ + +/* convert either Epson1 or Epson2 color encoding into a sequential encoding */ +#define seqcolor(c) (((c)&3)+(((c)&276)?3:0)) /* Intuitive, huh? */ + +extern void merge_line(line_type *p, unsigned char *l, int startl, int stopl, + int color); +extern void expand_line (unsigned char *src, unsigned char *dst, int height, + int skip, int left_ignore); +extern void write_output (FILE *fp_w, int dontwrite); +extern void find_white (unsigned char *buf,int npix, int *left, int *right); +extern int update_page (unsigned char *buf, int bufsize, int m, int n, + int color, int density); +extern void parse_escp2 (FILE *fp_r); +extern void reverse_bit_order (unsigned char *buf, int n); +extern int rle_decode (unsigned char *inbuf, int n, int max); +extern void parse_canon (FILE *fp_r); + +unsigned get_mask_1[] = { 7, 6, 5, 4, 3, 2, 1, 0 }; +unsigned get_mask_2[] = { 6, 4, 2, 0 }; +unsigned get_mask_4[] = { 4, 0 }; + +static inline int +get_bits(unsigned char *p, int index) +{ + /* + * p is a pointer to a bit stream, ordered MSb first. Extract the + * indexth bpp bit width field and return that value. Ignore byte + * boundaries. + */ + int value, b; + unsigned addr; + switch (pstate.bpp) + { + case 1: + return (p[index >> 3] >> (7 - (index & 7))) & 1; + case 2: + b = get_mask_2[index & 3]; + return (p[index >> 2] >> b) & 3; + case 4: + b = get_mask_4[index & 1]; + return (p[index >> 1] >> b) & 0xf; + case 8: + return p[index]; + default: + addr = (index * pstate.bpp); + value = 0; + for (b = 0; b < pstate.bpp; b++) + { + value += value; + value |= (p[(addr + b) >> 3] >> (7 - ((addr + b) & 7))) & 1; + } + return(value); + } +} + +static unsigned clr_mask_1[] = { 0xfe, 0xfd, 0xfb, 0xf7, + 0xef, 0xdf, 0xbf, 0x7f }; +static unsigned clr_mask_2[] = { 0xfc, 0, 0xf3, 0, 0xcf, 0, 0x3f, 0 }; +static unsigned clr_mask_4[] = { 0xf0, 0, 0, 0, 0xf, 0, 0, 0 }; + +static inline void +set_bits(unsigned char *p,int index,int value) +{ + + /* + * p is a pointer to a bit stream, ordered MSb first. Set the + * indexth bpp bit width field to value value. Ignore byte + * boundaries. + */ + + int b; + switch (pstate.bpp) + { + case 1: + b = (7 - (index & 7)); + p[index >> 3] &= clr_mask_1[b]; + p[index >> 3] |= value << b; + break; + case 2: + b = get_mask_2[index & 3]; + p[index >> 2] &= clr_mask_2[b]; + p[index >> 2] |= value << b; + break; + case 4: + b = get_mask_4[index & 1]; + p[index >> 1] &= clr_mask_4[b]; + p[index >> 1] |= value << b; + break; + case 8: + p[index] = value; + break; + default: + for (b = pstate.bpp - 1; b >= 0; b--) + { + if (value & 1) + p[(index * pstate.bpp + b) / 8] |= + 1 << (7 - ((index * pstate.bpp + b) % 8)); + else + p[(index * pstate.bpp + b) / 8] &= + ~(1 << (7 - ((index * pstate.bpp + b) % 8))); + value/=2; + } + } +} + +static float ink_colors[8][4] = +{{ 0, 0, 0, 1 }, /* K */ + { 1, .1, 1, 1 }, /* M */ + { .1, 1, 1, 1 }, /* C */ + { 1, 1, .1, 1 }, /* Y */ + { 1, .7, 1, 1 }, /* m */ + { .7, 1, 1, 1 }, /* c */ + { 1, 1, .7, 1 }, /* y */ + { 1, 1, 1, 1 }}; + +static float bpp_shift[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 }; + +static inline void +mix_ink(ppmpixel p, int color, unsigned int amount, float *ink) +{ + /* this is pretty crude */ + + if (amount) + { + int i; + float size; + + size = (float) amount / bpp_shift[pstate.bpp]; + for (i = 0; i < 3; i++) + p[i] *= (1 - size) + size * ink[i]; + } +} + +void +merge_line(line_type *p, unsigned char *l, int startl, int stopl, int color) +{ + + int i; + int temp, shift, height, lvalue, pvalue, oldstop; + int width, owidth; + unsigned char *tempp; + int reversed = 0; + int need_realloc = 0; + + /* + * If we have a pixel to the left of anything previously printed, + * we need to expand our margins to the left. This is a bit tricky... + */ + if (startl < p->startx[color]) + { + temp = p->startx[color]; + p->startx[color] = startl; + startl = temp; + + temp = p->stopx[color]; + p->stopx[color] = stopl; + stopl = temp; + + tempp = p->line[color]; + p->line[color] = l; + l = tempp; + reversed = 1; + } + shift = startl - p->startx[color]; + height = stopl - startl + 1; + + oldstop = p->stopx[color]; + if (stopl > p->stopx[color]) + { + p->stopx[color] = stopl; + need_realloc = 1; + } + if (need_realloc || reversed) + { + width = ((p->stopx[color] - p->startx[color] + 1) * pstate.bpp + 7) / 8; + owidth = ((oldstop - p->startx[color] + 1) * pstate.bpp + 7) / 8; + p->line[color] = xrealloc(p->line[color], width); + memset((p->line[color] + owidth), 0, (width - owidth)); + } + /* + * Can we do an empty line optimization? + */ + for (i = 0; i < height; i++) + { + lvalue = get_bits(l, i); + if (lvalue) + { + pvalue = get_bits(p->line[color], i + shift); + pvalue += lvalue; + if (pvalue > (1 << pstate.bpp) - 1) + pvalue = (1 << pstate.bpp) - 1; + set_bits(p->line[color], i + shift, pvalue); + } + } + free(l); +} + +void +expand_line (unsigned char *src, unsigned char *dst, int height, int skip, + int left_ignore) +{ + + /* + * src is a pointer to a bit stream which is composed of fields of height + * bpp starting with the most significant bit of the first byte and + * proceding from there with no regard to byte boundaries. For the + * existing Epson printers, bpp is 1 or 2, which means fields will never + * cross byte boundaries. However, if bpp were 3, this would undoubtedly + * happen. This routine will make no assumptions about bpp, and handle each + * bit individually. It's slow, but, it's the only way that will work in + * the general case of arbitrary bpp. + * + * We want to copy each field from the src to the dst, spacing the fields + * out every skip fields. We should ignore the first left_ignore fields + * pointed to by src, though. + */ + + int i; + + if ((skip == 1) && !(left_ignore * pstate.bpp % 8)) + { + /* the trivial case, this should be faster */ + memcpy(dst, src + left_ignore * pstate.bpp / 8, + (height * pstate.bpp + 7) / 8); + } + else + { + for (i = 0; i < height; i++) + set_bits(dst, i * skip, get_bits(src, i + left_ignore)); + } +} + +int donothing; + +void +write_output(FILE *fp_w, int dontwrite) +{ + int c, l, p, left, right, first, last, width, height, i; + unsigned int amount; + ppmpixel *out_row; + int oversample = pstate.absolute_horizontal_units / + pstate.absolute_vertical_units; + if (oversample == 0) + oversample = 1; + + fprintf(stderr, "Margins: top: %d bottom: top+%d\n", pstate.top_margin, + pstate.bottom_margin); + + first = pstate.top_edge; + last = pstate.bottom_edge; + left = pstate.left_edge; + right = pstate.right_edge; + height = oversample * (last - first + 1); + + fprintf(stderr, "Image from (%d,%d) to (%d,%d).\n", + left, first, right, last); + + width = right - left + 1; + if (width < 0) + width=0; + + out_row = malloc(sizeof(ppmpixel) * width); + fprintf(stderr, "Writing output...\n"); + + /* write out the PPM header */ + fprintf(fp_w, "P6\n"); + fprintf(fp_w, "%d %d\n", width, height); + fprintf(fp_w, "255\n"); + for (l = first; l <= last; l++) + { + line_type *lt = page[l]; + memset(out_row, ~0, (sizeof(ppmpixel) * width)); + if (lt) + { + for (c = 0; c < MAX_INKS; c++) + { + float *ink = ink_colors[c]; + if (lt->line[c]) + { + if (dontwrite) + donothing += lt->line[c][0] ^ + lt->line[c][lt->stopx[c] - lt->startx[c] + 1]; + else + { + for (p = lt->startx[c]; p <= lt->stopx[c]; p++) + { + amount = get_bits(lt->line[c], p - lt->startx[c]); + mix_ink(out_row[p - left], c, amount, ink); + } + } + } + } + } + if (!dontwrite) + for (i = 0; i < oversample; i++) + fwrite(out_row, sizeof(ppmpixel), width, fp_w); + } + free(out_row); +} + +void +find_white(unsigned char *buf,int npix, int *left, int *right) +{ + + /* + * If a line has white borders on either side, count the number of + * pixels and fill that info into left and right. + */ + + int i, j, max; + int words, bytes, bits, extra; + + *left = *right = 0; + bits = npix * pstate.bpp; + bytes = bits / 8; + extra = bits % 8; + words = bytes / sizeof(long); + + /* + * First, find the leftmost pixel. We first identify the word + * containing the byte, then the byte, and finally the pixel within + * the byte. It does seem like this is unnecessarily complex, perhaps? + */ + max = words; + for (i = 0; (i < max) && (((long *)buf)[i] == 0); i++) + ; + max = (i < words) ? (i + 1) * sizeof(long) : bytes; + + i *= sizeof(long); /* Convert from longs to bytes */ + for (; (i < max) && (buf[i] == 0); i++) + ; + max = (i < bytes) ? 8 : extra; + for (j = 0; (j < max) && !(buf[i] & (1 << (7 - j))); j++) + ; + *left = (i * 8 + j) / pstate.bpp; + *right = 0; + + /* if left is everything, then right is nothing */ + if (*left == npix) + return; + + /* right side, this is a little trickier */ + for (i = 0; (i < extra) && !(buf[bytes] & (1 << (i + 8 - extra))); i++) + ; + if (i < extra) + { + *right = i / pstate.bpp; + return; + } + *right = extra; /*temporarily store right in bits to avoid rounding error*/ + + for (i = 0; (i < bytes % sizeof(long)) && !(buf[bytes - 1 - i]); i++) + ; + if (i < bytes % sizeof(long)) + { + for (j = 0; (j < 8) && !(buf[bytes - 1 - i] & (1 << j)); j++) + ; + *right = (*right + i * 8 + j) / pstate.bpp; + return; + } + *right += i * 8; + + for (i = 0; (i < words) && !(((int *)buf)[words - 1 - i]); i++) + ; + + if (i < words) + { + *right += i * sizeof(long) * 8; + for (j = 0; + (j < sizeof(long)) && !(buf[(words - i) * sizeof(long) - 1 - j]); + j++) + ; + if (j < sizeof(long)) + { + *right += j * 8; + max = (words - i) * sizeof(long) - 1 - j; + for (j = 0; (j < 8) && !(buf[max] & (1 << j)); j++) + ; + if (j < 8) + { + *right = (*right + j) / pstate.bpp; + return; + } + } + } + fprintf(stderr, "Warning: Reality failure. The impossible happened.\n"); +} + +int +update_page(unsigned char *buf, /* I - pixel data */ + int bufsize, /* I - size of buf in bytes */ + int m, /* I - height of area in pixels */ + int n, /* I - width of area in pixels */ + int color, /* I - color of pixel data */ + int density /* I - horizontal density in dpi */ + ) +{ + int y, skip, oldstart, oldstop, mi = 0; + int left_white, right_white, width; + unsigned char *oldline; + int sep; + + if ((n == 0) || (m == 0)) + return(0); /* shouldn't happen */ + + skip = pstate.relative_horizontal_units / density; + skip *= pstate.extraskip; + + if (skip == 0) + { + fprintf(stderr, "Warning! Attempting to print at %d DPI but units are " + "set to %d DPI.\n", density, pstate.relative_horizontal_units); + return(0); + } + + if (!page) + { + fprintf(stderr, + "Warning! Attempting to print before setting up page!\n"); + /* + * Let's hope that we've at least initialized the printer with + * with an ESC @ and allocate the default page. Otherwise, we'll + * have unpredictable results. But, that's a pretty acurate statement + * for a real printer, too! + */ + page = (line_type **) xcalloc(pstate.bottom_margin - pstate.top_margin, + sizeof(line_type *)); + } + if (pstate.microweave) + sep = 1; + else + sep = pstate.nozzle_separation; + for (y=pstate.yposition; y < pstate.yposition + m * sep; y += sep, mi++) + { + if (y >= pstate.bottom_margin - pstate.top_margin) + { + fprintf(stderr, + "Warning: Unprinter out of unpaper (limit %d, pos %d).\n", + pstate.bottom_margin, y); + return(1); + } + find_white(buf + mi * ((n * pstate.bpp + 7) / 8), n, + &left_white, &right_white); + if (left_white == n) + continue; /* ignore blank lines */ + if (!(page[y])) + { + page[y] = (line_type *) xcalloc(sizeof(line_type), 1); + if (y < pstate.top_edge) + pstate.top_edge = y; + if (y > pstate.bottom_edge) + pstate.bottom_edge = y; + } + if ((left_white * pstate.bpp < 8) && (skip == 1)) + { + left_white=0; /* if it's just a few bits, don't bother cropping */ + } /* unless we need to expand the line anyway */ + if (page[y]->line[color]) + { + oldline = page[y]->line[color]; + oldstart = page[y]->startx[color]; + oldstop = page[y]->stopx[color]; + } + else + { + oldline = NULL; + oldstart = -1; + oldstop = -1; + } + page[y]->startx[color] = pstate.xposition + left_white * skip; + page[y]->stopx[color] =pstate.xposition + ((n - 1 - right_white) * skip); + if (page[y]->startx[color] < pstate.left_edge) + pstate.left_edge = page[y]->startx[color]; + if (page[y]->stopx[color] > pstate.right_edge) + pstate.right_edge = page[y]->stopx[color]; + width = page[y]->stopx[color] - page[y]->startx[color]; + page[y]->line[color] = + xcalloc(((width * skip + 1) * pstate.bpp + 7) / 8, 1); + expand_line(buf + mi * ((n * pstate.bpp + 7) / 8), page[y]->line[color], + width+1, skip, left_white); + if (oldline) + merge_line(page[y], oldline, oldstart, oldstop, color); + } + if (n) + pstate.xposition += (n - 1) * skip + 1; + return(0); +} + +#define get1(error) \ +do \ +{ \ + if (!(global_count = fread(&ch, 1, 1, fp_r))) \ + { \ + fprintf(stderr, "%s at %d (%x), read %d", \ + error, global_counter, global_counter, global_count); \ + eject = 1; \ + continue; \ + } \ + else \ + global_counter += global_count; \ +} while (0) + +#define get2(error) \ +do \ +{ \ + if (!(global_count = fread(minibuf, 1, 2, fp_r))) \ + { \ + fprintf(stderr, "%s at %d (%x), read %d", \ + error, global_counter, global_counter, global_count); \ + eject = 1; \ + continue; \ + } \ + else \ + { \ + global_counter += global_count; \ + sh = minibuf[0] + minibuf[1] * 256; \ + } \ +} while (0) + +#define getn(n,error) \ +do \ +{ \ + if (!(global_count = fread(buf, 1, n, fp_r))) \ + { \ + fprintf(stderr, "%s at %d (%x), read %d", \ + error, global_counter, global_counter, global_count); \ + eject = 1; \ + continue; \ + } \ + else \ + global_counter += global_count; \ +} while (0) + +#define getnoff(n,offset,error) \ +do \ +{ \ + if (!(global_count = fread(buf + offset, 1, n, fp_r))) \ + { \ + fprintf(stderr, "%s at %d (%x), read %d", \ + error, global_counter, global_counter, global_count); \ + eject = 1; \ + continue; \ + } \ + else \ + global_counter += global_count; \ +} while (0) + +static void +parse_escp2_data(FILE *fp_r) +{ + int i, m = 0, n = 0, c = 0; + int currentcolor = 0; + int density = 0; + int bandsize; + switch (ch) + { + case 'i': + get1("Error reading color.\n"); + currentcolor = seqcolor(ch); + get1("Error reading compression mode!\n"); + c = ch; + get1("Error reading bpp!\n"); + if (ch != pstate.bpp) + { + fprintf(stderr, "Warning! Color depth altered by ESC i.\n"); + pstate.bpp=ch; + } + if (pstate.bpp > 2) + fprintf(stderr, "Warning! Excessively deep color detected.\n"); + if (pstate.bpp == 0) + fprintf(stderr, "Warning! Zero bit pixel depth detected.\n"); + get2("Error reading number of horizontal dots!\n"); + n = (unsigned) sh * 8 / pstate.bpp; + get2("Error reading number of vertical dots!\n"); + m = (unsigned) sh; + density = pstate.horizontal_spacing; + break; + case '.': + get1("Error reading compression mode!\n"); + c=ch; + if (c > 2) + { + fprintf(stderr,"Warning! Unknown compression mode.\n"); + break; + } + get1("Error reading vertical density!\n"); + /* What should we do with the vertical density here??? */ + get1("Error reading horizontal density!\n"); + density=3600/ch; + get1("Error reading number of vertical dots!\n"); + m=ch; + get2("Error reading number of horizontal dots!\n"); + n=sh; + currentcolor=pstate.current_color; + break; + } + bandsize = m * ((n * pstate.bpp + 7) / 8); + if (valid_bufsize < bandsize) + { + buf = realloc(buf, bandsize); + valid_bufsize = bandsize; + } + switch (c) + { + case 0: /* uncompressed */ + bufsize = bandsize; + getn(bufsize,"Error reading raster data!\n"); + update_page(buf, bufsize, m, n, currentcolor, density); + break; + case 1: /* run length encoding */ + i = 0; + while (!eject && (i < bandsize)) + { + get1("Error reading global_counter!\n"); + if (ch < 128) + { + bufsize = ch + 1; + getnoff(bufsize, i, "Error reading RLE raster data!\n"); + } + else + { + bufsize = 257 - (unsigned int) ch; + get1("Error reading compressed RLE raster data!\n"); + memset(buf + i, ch, bufsize); + } + i += bufsize; + } + if (i != bandsize) + { + fprintf(stderr, "Error decoding RLE data.\n"); + fprintf(stderr, "Total bufsize %d, expected %d\n", + i, bandsize); + eject = 1; + } + else + update_page(buf, i, m, n, currentcolor, density); + break; + case 2: /* TIFF compression */ + fprintf(stderr, "TIFF mode not yet supported!\n"); + /* FIXME: write TIFF stuff */ + break; + default: /* unknown */ + fprintf(stderr, "Unknown compression mode %d.\n", c); + break; + } +} + +static void +parse_escp2_extended(FILE *fp_r) +{ + int unit_base; + int i; + + get1("Corrupt file. Incomplete extended command.\n"); + if (eject) + return; + get2("Corrupt file. Error reading buffer size.\n"); + bufsize = sh; + getn(bufsize, "Corrupt file. Error reading command payload.\n"); + /* fprintf(stderr,"Command %X bufsize %d.\n",ch,bufsize); */ + switch (ch) + { + case 'R': + if (bufsize == 8 && memcmp(buf, "\0REMOTE1", 8) == 0) + { + int rc1 = 0, rc2 = 0; + /* Remote mode 1 */ + do + { + get1("Corrupt file. Error in remote mode.\n"); + rc1 = ch; + get1("Corrupt file. Error reading remote mode command.\n"); + rc2 = ch; + get2("Corrupt file. Error reading remote mode command size.\n"); + bufsize = sh; + if (bufsize) + getn(bufsize, "Corrupt file. Error reading remote mode command parameters.\n"); + if (rc1 == 0x1b && rc2 == 0) /* ignore quietly */ + ; + else + fprintf(stderr, + "Remote mode command `%c%c' ignored.\n", + rc1,rc2); + } + while (!eject && !(rc1 == 0x1b && rc2 == 0)); + } + else + { + fprintf(stderr,"Warning! Commands in unrecognised remote mode %s ignored.\n", buf); + do + { + while((!eject) && (ch!=0x1b)) + get1("Error in remote mode.\n"); + get1("Error reading remote mode terminator\n"); + } + while ((!eject) && (ch != 0)); + } + break; + case 'G': /* select graphics mode */ + /* FIXME: this is supposed to have more side effects */ + pstate.microweave = 0; + pstate.dotsize = 0; + pstate.bpp = 1; + break; + case 'U': /* set page units */ + switch (bufsize) + { + case 1: + pstate.page_management_units = + pstate.absolute_horizontal_units = + pstate.relative_horizontal_units = + pstate.relative_vertical_units = + pstate.horizontal_spacing = + pstate.absolute_vertical_units = 3600 / buf[0]; + if (pstate.page_management_units < 720) + pstate.extraskip = 1; + fprintf(stderr, "Setting units to 1/%d\n", + pstate.absolute_horizontal_units); + break; + case 5: + unit_base = buf[4] * 256 + buf[3]; + pstate.extraskip=1; + pstate.page_management_units= unit_base / buf[0]; + pstate.relative_vertical_units = + pstate.absolute_vertical_units = unit_base/buf[1]; + pstate.relative_horizontal_units = + pstate.horizontal_spacing = + pstate.absolute_horizontal_units = unit_base / buf[2]; + fprintf(stderr, "Setting page management units to 1/%d\n", + pstate.page_management_units); + fprintf(stderr, "Setting vertical units to 1/%d\n", + pstate.relative_vertical_units); + fprintf(stderr, "Setting horizontal units to 1/%d\n", + pstate.relative_horizontal_units); + break; + } + break; + case 'i': /* set MicroWeave mode */ + if (bufsize != 1) + fprintf(stderr,"Malformed microweave setting command.\n"); + else + pstate.microweave = buf[0] % 0x30; + break; + case 'e': /* set dot size */ + if ((bufsize != 2) || (buf[0] != 0)) + fprintf(stderr,"Malformed dotsize setting command.\n"); + else if (pstate.got_graphics) + fprintf(stderr,"Changing dotsize while printing not supported.\n"); + else + { + pstate.dotsize = buf[1]; + if (pstate.dotsize & 0x10) + pstate.bpp = 2; + else + pstate.bpp = 1; + } + fprintf(stderr, "Setting dot size to 0x%x (bits %d)\n", + pstate.dotsize, pstate.bpp); + break; + case 'c': /* set page format */ + if (page) + { + fprintf(stderr,"Setting the page format in the middle of printing a page is not supported.\n"); + break; + } + switch (bufsize) + { + case 4: + pstate.top_margin = buf[1] * 256 + buf[0]; + pstate.bottom_margin = buf[3] * 256 + buf[2]; + break; + case 8: + pstate.top_margin = (buf[3] << 24) + + (buf[2] << 16) + (buf[1] << 8) + buf[0]; + pstate.bottom_margin = (buf[7] << 24) + + (buf[6] << 16) + (buf[5] << 8) + buf[4]; + break; + default: + fprintf(stderr,"Malformed page format. Ignored.\n"); + } + pstate.yposition = 0; + if (pstate.top_margin + pstate.bottom_margin > pstate.page_height) + pstate.page_height = pstate.top_margin + pstate.bottom_margin; + page = (line_type **) xcalloc(pstate.bottom_margin - pstate.top_margin, + sizeof(line_type *)); + fprintf(stderr, "Setting top margin to %d (%.3f)\n", + pstate.top_margin, + (double) pstate.top_margin / pstate.page_management_units); + fprintf(stderr, "Setting bottom margin to %d (%.3f)\n", + pstate.bottom_margin, + (double) pstate.bottom_margin / pstate.page_management_units); + break; + case 'V': /* set absolute vertical position */ + i = 0; + switch (bufsize) + { + case 4: + i = (buf[2] << 16) + (buf[3]<<24); + /* FALLTHROUGH */ + case 2: + i += (buf[0]) + (256 * buf[1]); + if (pstate.top_margin + i * (pstate.relative_vertical_units / + pstate.absolute_vertical_units) >= + pstate.yposition) + pstate.yposition = i * (pstate.relative_vertical_units / + pstate.absolute_vertical_units) + + pstate.top_margin; + else + fprintf(stderr, "Warning: Setting Y position in negative direction ignored\n"); + break; + default: + fprintf(stderr, "Malformed absolute vertical position set.\n"); + } + if (pstate.yposition > pstate.bottom_margin - pstate.top_margin) + { + fprintf(stderr, + "Warning! Printer head moved past bottom margin. Dumping output and exiting.\n"); + eject = 1; + } + break; + case 'v': /* set relative vertical position */ + i = 0; + switch (bufsize) + { + case 4: + i = (buf[2] << 16) + (buf[3] << 24); + /* FALLTHROUGH */ + case 2: + i += (buf[0]) + (256 * buf[1]); + if (unweave) + i = pstate.nozzles; + pstate.yposition+=i; + break; + default: + fprintf(stderr,"Malformed relative vertical position set.\n"); + } + if (pstate.yposition > pstate.bottom_margin - pstate.top_margin) + { + fprintf(stderr,"Warning! Printer head moved past bottom margin. Dumping output and exiting.\n"); + eject = 1; + } + break; + case 'K': + if (bufsize!=2) + fprintf(stderr,"Malformed monochrome/color mode selection.\n"); + else if (buf[0]) + fprintf(stderr,"Non-zero first byte in monochrome selection command. Ignored.\n"); + else if (buf[0] > 0x02) + fprintf(stderr,"Unknown color mode 0x%X.\n",buf[1]); + else + pstate.monomode = buf[1]; + + break; + case 's': /* Set print speed */ + break; + case 'S': /* set paper dimensions */ + switch (bufsize) + { + case 4: + i = (buf[1] << 16) + buf[0]; + fprintf(stderr, "Setting paper width to %d (%.3f)\n", i, + (double) i / pstate.page_management_units); + i = (buf[3] << 16) + buf[2]; + fprintf(stderr, "Setting paper height to %d (%.3f)\n", i, + (double) i / pstate.page_management_units); + break; + case 8: + i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]; + fprintf(stderr, "Setting paper width to %d (%.3f)\n", i, + (double) i / pstate.page_management_units); + i = (buf[7] << 24) + (buf[6] << 16) + (buf[5] << 8) + buf[4]; + fprintf(stderr, "Setting paper height to %d (%.3f)\n", i, + (double) i / pstate.page_management_units); + break; + default: + fprintf(stderr, "Invalid set paper dimensions command.\n"); + } + break; + case 'D': + if (bufsize != 4) + fprintf(stderr, "Malformed set resolution request.\n"); + else + { + int res_base = (256 * buf[1]) + buf[0]; + pstate.nozzle_separation = + pstate.absolute_vertical_units / (res_base / buf[2]); + pstate.horizontal_spacing = res_base / buf[3]; + fprintf(stderr, "Setting nozzle separation to %d\n", + pstate.nozzle_separation); + fprintf(stderr, "Setting vertical spacing to 1/%d\n", + res_base / buf[2]); + fprintf(stderr, "Setting horizontal spacing to 1/%d\n", + pstate.horizontal_spacing); + } + break; + case 'r': /* select color */ + if (bufsize!=2) + fprintf(stderr,"Malformed color selection request.\n"); + else + { + sh = 256 * buf[0] + buf[1]; + if ((buf[1] > 4) || (buf[1] == 3) || (buf[0] > 1) || + (buf[0] && (buf[1]==0))) + fprintf(stderr,"Invalid color 0x%X.\n",sh); + else + pstate.current_color = seqcolor(sh); + } + break; + case '\\': /* set relative horizontal position */ + case '/': + i = (buf[3] << 8) + buf[2]; + if (pstate.xposition + i < 0) + { + fprintf(stderr,"Warning! Attempt to move to -X region ignored.\n"); + fprintf(stderr," Command: ESC ( %c %X %X %X %X Original " + "position: %d\n", + ch, buf[0], buf[1], buf[2], buf[3], pstate.xposition); + } + else /* FIXME: Where is the right margin??? */ + pstate.xposition+=i; + break; + case '$': /* set absolute horizontal position */ + i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]; + pstate.xposition = i * (pstate.relative_horizontal_units / + pstate.absolute_horizontal_units); + break; + case 'C': /* set page height */ + switch (bufsize) + { + case 2: + i = (buf[1] << 8) | buf[0]; + fprintf(stderr, "Setting page height to %d (%.3f)\n", i, + (double) i / pstate.page_management_units); + break; + case 4: + i = (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0]; + fprintf(stderr, "Setting page height to %d (%.3f)\n", i, + (double) i / pstate.page_management_units); + break; + default: + fprintf(stderr, "Invalid set page height command.\n"); + } + break; + default: + fprintf(stderr,"Warning: Unknown command ESC ( 0x%X at 0x%08X.\n", + ch, global_counter - 5 - bufsize); + } +} + +static void +parse_escp2_command(FILE *fp_r) +{ + get1("Corrupt file. No command found.\n"); + switch (ch) + { + case 1: /* Magic EJL stuff to get USB port working */ + fprintf(stderr,"Ignoring EJL commands.\n"); + do + { + get1("Error reading EJL commands.\n"); + } + while (!eject && ch != 0x1b); + if (eject) + break; + get1("Expect esc-NULL to close EJL command.\n"); + if (ch != 0x40) + fprintf(stderr, "Expect esc-NULL to close EJL command.\n"); + break; + case '@': /* initialize printer */ + if (page) + eject = 1; + else + { + pstate.unidirectional = 0; + pstate.microweave = 0; + pstate.dotsize = 0; + pstate.bpp = 1; + pstate.page_management_units = 360; + pstate.relative_horizontal_units = 180; + pstate.absolute_horizontal_units = 60; + pstate.relative_vertical_units = 360; + pstate.absolute_vertical_units = 360; + pstate.top_margin = 120; + pstate.bottom_margin = + pstate.page_height = 22 * 360; /* 22 inches is default ??? */ + pstate.monomode = 0; + pstate.left_edge = INT_MAX; + pstate.right_edge = 0; + pstate.top_edge = INT_MAX; + pstate.bottom_edge = 0; + } + break; + case 'U': /* turn unidirectional mode on/off */ + get1("Error reading unidirectionality.\n"); + if ((ch <= 2) || ((ch >= 0x30) && (ch <= 0x32))) + pstate.unidirectional=ch; + break; + case 'i': /* transfer raster image */ + case '.': + pstate.got_graphics = 1; + parse_escp2_data(fp_r); + break; + case '\\': /* set relative horizontal position */ + get2("Error reading relative horizontal position.\n"); + if (pstate.xposition + (signed short)sh < 0) + { + fprintf(stderr, "Warning! Move off left of region ignored.\n"); + fprintf(stderr, " Command: ESC %c %X %X " + "Original Position: %d\n", + ch, minibuf[0], minibuf[1], pstate.xposition); + } + else /* FIXME: Where is the right margin??? */ + pstate.xposition += (signed short)sh; + break; + case '$': /* set absolute horizontal position */ + get2("Error reading absolute horizontal position.\n"); + pstate.xposition = sh * (pstate.relative_horizontal_units / + pstate.absolute_horizontal_units); + break; + case 0x6: /* flush buffers */ + /* Woosh. Consider them flushed. */ + break; + case 0x19: /* control paper loading */ + get1("Error reading paper control byte.\n"); + /* paper? */ + break; + case 'r': /* select printing color */ + get1("Error reading color.\n"); + if ((ch <= 4) && (ch != 3)) + pstate.current_color = seqcolor(ch); + else + fprintf(stderr, "Invalid color %d.\n", ch); + break; + case '(': /* commands with a payload */ + parse_escp2_extended(fp_r); + break; + default: + fprintf(stderr,"Warning: Unknown command ESC 0x%X at 0x%08X.\n",ch,global_counter-2); + } +} + +void +parse_escp2(FILE *fp_r) +{ + global_counter = 0; + + while ((!eject) && (fread(&ch, 1, 1, fp_r))) + { + global_counter++; + switch (ch) + { + case 0xd: /* carriage return */ + pstate.xposition = 0; + break; + case 0xc: /* form feed */ + eject = 1; + break; + case 0x0: + break; + case 0x1b: /* Command! */ + parse_escp2_command(fp_r); + break; + default: + fprintf(stderr, + "Corrupt file? No ESC found. Found: %02X at 0x%08X\n", + ch, global_counter-1); + break; + } + } +} + + +/* 'reverse_bit_order' + * + * reverse the bit order in an array of bytes - does not reverse byte order! + */ +void +reverse_bit_order(unsigned char *buf, int n) +{ + int i; + unsigned char a; + if (!n) return; /* nothing to do */ + + for (i= 0; i<n; i++) { + a= buf[i]; + buf[i]= + (a & 0x01) << 7 | + (a & 0x02) << 5 | + (a & 0x04) << 3 | + (a & 0x08) << 1 | + (a & 0x10) >> 1 | + (a & 0x20) >> 3 | + (a & 0x40) >> 5 | + (a & 0x80) >> 7; + } +} + +/* 'rle_decode' + * + * run-length-decodes a given buffer of height "n" + * and stores the result in the same buffer + * not exceeding a size of "max" bytes. + */ +int +rle_decode(unsigned char *inbuf, int n, int max) +{ + unsigned char outbuf[1440*3]; + signed char *ib= (signed char *)inbuf; + signed char cnt; + int num; + int i= 0, j; + int o= 0; + +#ifdef DEBUG_RLE + fprintf(stderr,"input: %d\n",n); +#endif + if (n<=0) return 0; + if (max>1440*3) max= 1440*3; /* FIXME: this can be done much better! */ + + while (i<n && o<max) { + cnt= ib[i]; + if (cnt<0) { + /* cnt identical bytes */ + /* fprintf(stderr,"rle 0x%02x = %4d = %4d\n",cnt&0xff,cnt,1-cnt); */ + num= 1-cnt; + /* fprintf (stderr,"+%6d ",num); */ + for (j=0; j<num && o+j<max; j++) outbuf[o+j]= inbuf[i+1]; + o+= num; + i+= 2; + } else { + /* cnt individual bytes */ + /* fprintf(stderr,"raw 0x%02x = %4d = %4d\n",cnt&0xff,cnt,cnt + 1); */ + num= cnt+1; + /* fprintf (stderr,"*%6d ",num); */ + for (j=0; j<num && o+j<max; j++) outbuf[o+j]= inbuf[i+j+1]; + o+= num; + i+= num+1; + } + } + if (o>=max) { + fprintf(stderr,"Warning: rle decompression exceeds output buffer.\n"); + return 0; + } + /* copy decompressed data to inbuf: */ + memset(inbuf,0,max-1); + memcpy(inbuf,outbuf,o); +#ifdef DEBUG_RLE + fprintf(stderr,"output: %d\n",o); +#endif + return o; +} + +void +parse_canon(FILE *fp_r) +{ + + int m=0; + int currentcolor,currentbpp,density,eject; + int cmdcounter; + int delay_c=0, delay_m=0, delay_y=0, delay_C=0, + delay_M=0, delay_Y=0, delay_K=0, currentdelay=0; + + global_counter=0; + + page= 0; + eject=pstate.got_graphics=currentbpp=currentcolor=density=0; + while ((!eject)&&(fread(&ch,1,1,fp_r))){ + global_counter++; + if (ch==0xd) { /* carriage return */ + pstate.xposition=0; +#ifdef DEBUG_CANON + fprintf(stderr,"< "); +#endif + continue; + } + if (ch==0xc) { /* form feed */ + eject=1; + continue; + } + if (ch=='B') { + fgets((char *)buf,sizeof(buf),fp_r); + global_counter+= strlen((char *)buf); + if (!strncmp((char *)buf,"JLSTART",7)) { + while (strncmp((char *)buf,"BJLEND",6)) { + fgets((char *)buf,sizeof(buf),fp_r); + global_counter+= strlen((char *)buf); + fprintf(stderr,"got BJL-plaintext-command %s",buf); + } + } else { + fprintf(stderr,"Error: expected BJLSTART but got B%s",buf); + } + global_counter= ftell(fp_r); + continue; + } + if (ch!=0x1b) { + fprintf(stderr,"Corrupt file? No ESC found. Found: %02X at 0x%08X\n", + ch,global_counter-1); + continue; + } + get1("Corrupt file. No command found.\n"); + /* fprintf(stderr,"Got a %X.\n",ch); */ + switch (ch) { + case '[': /* 0x5b initialize printer */ + get1("Error reading CEM-code.\n"); + cmdcounter= global_counter; + get2("Error reading CEM-data size.\n"); + getn(sh,"Error reading CEM-data.\n"); + + if (ch=='K') /* 0x4b */ { + if (sh!=2 || buf[0]!=0x00 ) { + fprintf(stderr,"Error initializing printer with ESC [ K\n"); + eject=1; + continue; + } + if (page) { + eject=1; + continue; + } else { + pstate.unidirectional=0; + pstate.microweave=0; + pstate.dotsize=0; + pstate.bpp=1; + pstate.page_management_units=360; + pstate.relative_horizontal_units=180; + pstate.absolute_horizontal_units=60; + pstate.relative_vertical_units=360; + pstate.absolute_vertical_units=360; + pstate.top_margin=120; + pstate.bottom_margin= + pstate.page_height=22*360; /* 22 inches is default ??? */ + pstate.monomode=0; + pstate.xposition= 0; + pstate.yposition= 0; + pstate.left_edge = INT_MAX; + pstate.right_edge = 0; + pstate.top_edge = INT_MAX; + pstate.bottom_edge = 0; + fprintf(stderr,"canon: init printer\n"); + } + } else { + fprintf(stderr,"Warning: Unknown command ESC %c 0x%X at 0x%08X.\n", + 0x5b,ch,global_counter); + } + break; + + case '@': /* 0x40 */ + eject=1; + break; + + case '(': /* 0x28 */ + get1("Corrupt file. Incomplete extended command.\n"); + cmdcounter= global_counter; + get2("Corrupt file. Error reading buffer size.\n"); + bufsize=sh; + getn(bufsize,"Corrupt file. Error reading data buffer.\n"); + + switch(ch) { +/* Color Codes: + color Epson1 Epson2 Sequential + Black 0 0 0 K + Magenta 1 1 1 M + Cyan 2 2 2 C + Yellow 4 4 3 Y + L.Mag. 17 257 4 m + L.Cyan 18 258 5 c + L.Yellow NA NA 6 y + */ + case 'A': /* 0x41 - transfer graphics data */ + switch (*buf) { + case 'K': currentcolor= 0; currentdelay= delay_K; break; + case 'M': currentcolor= 1; currentdelay= delay_M; break; + case 'C': currentcolor= 2; currentdelay= delay_C; break; + case 'Y': currentcolor= 3; currentdelay= delay_Y; break; + case 'm': currentcolor= 4; currentdelay= delay_m; break; + case 'c': currentcolor= 5; currentdelay= delay_c; break; + case 'y': currentcolor= 6; currentdelay= delay_y; break; + default: + fprintf(stderr,"Error: unsupported color type 0x%02x.\n",*buf); + /* exit(-1); */ + } + pstate.current_color= currentcolor; + m= rle_decode(buf+1,bufsize-1,sizeof(buf)-1); + /* reverse_bit_order(buf+1,m); */ + pstate.yposition+= currentdelay; + if (m) update_page(buf+1,m,1,(m*8)/pstate.bpp,currentcolor, + pstate.absolute_horizontal_units); + pstate.yposition-= currentdelay; +#ifdef DEBUG_CANON + fprintf(stderr,"%c:%d>%d ",*buf,sh-1,m); +#endif + break; + case 'a': /* 0x61 - turn something on/off */ + break; + case 'b': /* 0x62 - turn something else on/off */ + break; + case 'c': /* 0x63 - some information about the print job */ + break; + case 'd': /* 0x64 - set resolution */ + if (page) { + fprintf(stderr,"Setting the page format in the middle of printing " + "a page is not supported.\n"); + exit(-1); + } + pstate.relative_vertical_units= + pstate.absolute_vertical_units= + buf[1]+256*buf[0]; + pstate.relative_horizontal_units= + pstate.absolute_horizontal_units= + buf[3]+256*buf[2]; + pstate.bottom_margin= pstate.relative_vertical_units* 22; + /* FIXME: replace with real page height */ + fprintf(stderr,"canon: res is %d x %d dpi\n", + pstate.relative_horizontal_units, + pstate.relative_vertical_units); + + page=(line_type **)xcalloc(pstate.bottom_margin,sizeof(line_type *)); + break; + case 'e': /* 0x65 - vertical head movement */ + pstate.yposition+= (buf[1]+256*buf[0]); +#ifdef DEBUG_CANON + fprintf(stderr,"\n"); +#endif + break; + case 'l': /* 0x6c - some more information about the print job*/ + break; + case 'm': /* 0x6d - used printheads and other things */ + break; + case 'p': /* 0x70 - set printable area */ + break; + case 'q': /* 0x71 - turn yet something else on/off */ + break; + case 't': /* 0x74 - contains bpp and line delaying*/ + pstate.bpp= buf[0]; + fprintf(stderr,"canon: using %d bpp\n",pstate.bpp); + if (buf[1]&0x04) { + delay_y= 0; + delay_m= 0; + delay_c= 0; + delay_Y= 0; + delay_M= delay_Y+112; + delay_C= delay_M+112; + delay_K= delay_C+112; + fprintf(stderr,"canon: using line delay code\n"); + } + break; + + default: + fprintf(stderr,"Warning: Unknown command ESC ( 0x%X at 0x%08X.\n", + ch,global_counter); + } + break; + + default: + fprintf(stderr,"Warning: Unknown command ESC 0x%X at 0x%08X.\n", + ch,global_counter-2); + } + } +} + +int +main(int argc,char *argv[]) +{ + + int arg; + char *s; + char *UNPRINT; + FILE *fp_r, *fp_w; + int force_extraskip = -1; + int no_output = 0; + + unweave = 0; + pstate.nozzle_separation = 6; + fp_r = fp_w = NULL; + for (arg = 1; arg < argc; arg++) + { + if (argv[arg][0] == '-') + { + switch (argv[arg][1]) + { + case 0: + if (fp_r) + fp_w = stdout; + else + fp_r = stdin; + break; + case 'n': + if (argv[arg][2]) + { + s = argv[arg] + 2; + } + else + { + if (argc <= arg + 1) + { + fprintf(stderr, "Missing nozzle separation\n"); + exit(-1); + } + else + { + s = argv[++arg]; + } + } + if (!sscanf(s, "%d", &pstate.nozzle_separation)) + { + fprintf(stderr,"Error parsing nozzle separation\n"); + exit(-1); + } + break; + case 's': + if (argv[arg][2]) + { + s = argv[arg] + 2; + } + else + { + if (argc <= arg + 1) + { + fprintf(stderr,"Missing extra skip\n"); + exit(-1); + } + else + { + s = argv[++arg]; + } + } + if (!sscanf(s, "%d", &force_extraskip)) + { + fprintf(stderr, "Error parsing extra skip\n"); + exit(-1); + } + break; + case 'q': + no_output = 1; + break; + case 'u': + unweave = 1; + break; + } + } + else + { + if (fp_r) + { + if (!(fp_w = fopen(argv[arg],"w"))) + { + perror("Error opening ouput file"); + exit(-1); + } + } + else + { + if (!(fp_r = fopen(argv[arg],"r"))) + { + perror("Error opening input file"); + exit(-1); + } + } + } + } + if (!fp_r) + fp_r = stdin; + if (!fp_w) + fp_w = stdout; + + if (unweave) { + pstate.nozzle_separation = 1; + } + pstate.nozzles = 96; + buf = malloc(256 * 256); + valid_bufsize = 256 * 256; + + UNPRINT = getenv("UNPRINT"); + if ((UNPRINT)&&(!strcmp(UNPRINT,"canon"))) + { + if (force_extraskip > 0) + pstate.extraskip = force_extraskip; + else + pstate.extraskip = 1; + parse_canon(fp_r); + } + else + { + if (force_extraskip > 0) + pstate.extraskip = force_extraskip; + else + pstate.extraskip = 2; + parse_escp2(fp_r); + } + fprintf(stderr,"Done reading.\n"); + write_output(fp_w, no_output); + fclose(fp_w); + fprintf(stderr,"Image dump complete.\n"); + + return(0); +} |