summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorRoger Leigh <rleigh@debian.org>2008-10-26 16:10:50 +0000
committerRoger Leigh <rleigh@debian.org>2008-10-26 16:10:50 +0000
commiteb5718390731a9746c556317e641320b671f2091 (patch)
tree762876b4adf298c1281142328e2ae87007330904 /test
Imported Upstream version 4.2.0
Diffstat (limited to 'test')
-rw-r--r--test/.cvsignore12
-rw-r--r--test/Makefile.am73
-rw-r--r--test/bjc-unprint.c490
-rw-r--r--test/cyan-sweep.tifbin0 -> 16674 bytes
-rw-r--r--test/escp2-weavetest.c408
-rwxr-xr-xtest/parse-bjc145
-rwxr-xr-xtest/parse-escp2291
-rw-r--r--test/pcl-unprint.c1641
-rwxr-xr-xtest/run-weavetest43
-rw-r--r--test/testdither.c740
-rw-r--r--test/unprint.c1616
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
new file mode 100644
index 0000000..f4b0139
--- /dev/null
+++ b/test/cyan-sweep.tif
Binary files differ
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);
+}