1 /******************************************************************************
2  * pixma_parse.c parser for Canon BJL printjobs
3  * Copyright (c) 2005 - 2007 Sascha Sommer <saschasommer@freenet.de>.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  *****************************************************************************/
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <inttypes.h>
25 
26 
27 #define MAX_COLORS 36  /* was: 8 maximum number of Colors: CMYKcmyk */
28 
29 #define DEBUG 0 /* 1 for debugging only: all output goes to stderr */
30 
31 #include "pixma_parse.h"
32 
33 /*TODO:
34   1. change color loops to search for each named color rather than using a predefined order.
35   2. keep iP6700 workaround, but check what happens with the real printer.
36 */
37 
38 /* redirection for debug output */
39 FILE* fout;
40 
41 /* nextcmd(): find a command in a printjob
42  * commands in the printjob start with either ESC[ or ESC(
43  * ESC@ (go to neutral mode) and 0xc (form feed) are handled directly
44  * params:
45  *  infile: handle to the printjob
46  *  cmd: the command type
47  *  buf: the buffer to hold the arguments, has to be at least 0xFFFF bytes
48  *  cnt: len of the arguments
49  *
50  * return values:
51  *   0 when a command has been successfully read
52  *   1 when EOF has been reached
53  *  -1 when an error occurred
54  */
nextcmd(FILE * infile,unsigned char * cmd,unsigned char * buf,unsigned int * cnt,unsigned int * xml_read,unsigned int startxmllen,unsigned int endxmllen)55 static int nextcmd( FILE *infile,unsigned char* cmd,unsigned char *buf, unsigned int *cnt, unsigned int *xml_read,unsigned int startxmllen,unsigned int endxmllen)
56 {
57 	unsigned char c1,c2;
58 	unsigned int startxml, endxml;
59 	if (feof(infile))
60 		return -1;
61 	while (!feof(infile)){
62 		c1 = fgetc(infile);
63 		if(feof(infile)) /* NORMAL EOF */
64 			return 1;
65 		/* add skip for XML header and footer */
66 		if (c1 == 60 ){  /* "<" for XML start */
67 		  if (*xml_read==0){
68 		    /* start */
69 		    startxml=startxmllen-1;
70 		    fread(buf,1,startxml,infile); /* 1 less than startxmllen */
71 		    fprintf(fout,"nextcmd: read starting XML %d %d\n", *xml_read, startxml);
72 		    *xml_read=1;
73 		  }else if (*xml_read==1) {
74 		    /* end */
75 		    endxml=endxmllen-1;
76 		    fread(buf,1,endxml,infile); /* 1 less than endxmllen */
77 		    fprintf(fout,"nextcmd: read ending XML %d %d\n", *xml_read, endxml);
78 		    *xml_read=2;
79 		  }
80 		  /* no alternatives yet */
81 		}else if (c1 == 27 ){  /* A new ESC command */
82 			c2 = fgetc(infile);
83 			if(feof(infile))
84 				return 1;
85 			if (c2=='[' || c2=='(' ){   /* ESC[ or ESC( command */
86 				*cmd = fgetc(infile);    /* read command type  (1 byte) */
87 				if(feof(infile))
88 					return 1;
89 				c1 = fgetc(infile); /* read size 16 bit little endian */
90 				c2 = fgetc(infile);
91 				*cnt = c1 + (c2<<8);
92 				if (*cnt){  /* read arguments */
93 					unsigned int read;
94 					if((read=fread(buf,1,*cnt,infile)) != *cnt){
95 						fprintf(fout,"nextcmd: read error - not enough data %d %d\n", read, *cnt);
96 						return -1;
97 					}
98 				}
99 				return 0;
100 			}else if(c2 == '@'){ /* ESC@ */
101 				fprintf(fout,"ESC @ Return to neutral mode\n");
102 			} else {
103 				fprintf(fout,"unknown byte following ESC %x \n",c2);
104 			}
105 		}else if(c1==0x0c){ /* Form Feed */
106 			fprintf(fout,"-->Form Feed\n");
107 		}else{
108 			fprintf(fout,"UNKNOWN BYTE 0x%x @ %lu\n",c1,ftell(infile));
109 		}
110 	}
111 	return -1;
112 }
113 
114 
115 /* return pointer to color info structure matching name */
get_color(image_t * img,char name)116 static color_t* get_color(image_t* img,char name){
117 	int i;
118 	for(i=0;i<MAX_COLORS;i++)
119 		if(img->color[i].name==name)
120 			return &(img->color[i]);
121 	return NULL;
122 }
123 
124 #if 0
125 /* return pointer to color info structure matching name less 0x80 */
126 static color_t* get_color2(image_t* img,char name){
127 	int i;
128 	for(i=0;i<MAX_COLORS;i++) {
129 	  /*printf("get_color2: %i -- name=%c\n",i,img->color[i].name);*/
130 	  if(img->color[i].name==(name)) { /* add 0x80 to get the hex value in the inkset */
131 	    /*printf("get_color2: %i returning for %c\n",i,img->color[i].name);*/
132 	    return &(img->color[i]);
133 	  }
134 	}
135 	return NULL;
136 }
137 #endif
138 
valid_color(unsigned char color)139 static int valid_color(unsigned char color){
140 	int i;
141 	for(i=0;i<sizeof(valid_colors) / sizeof(valid_colors[0]);i++)
142 		if(valid_colors[i] == color)
143 			return 1;
144 	fprintf(fout," [valid_color] unknown color 0x%x\n",color);
145 	return 0;
146 }
147 
148 
149 /* eight2ten()
150  * decompression routine for canons 10to8 compression that stores 5 3-valued pixels in 8-bit
151  */
eight2ten(unsigned char * inbuffer,unsigned char * outbuffer,int num_bytes,int outbuffer_size)152 static int eight2ten(unsigned char* inbuffer,unsigned char* outbuffer,int num_bytes,int outbuffer_size){
153 	PutBitContext s;
154 	int read_pos=0;
155 	init_put_bits(&s, outbuffer,outbuffer_size);
156 	while(read_pos < num_bytes){
157 		unsigned short value=Table8[inbuffer[read_pos]];
158 		++read_pos;
159 		put_bits(&s,10,value);
160 	}
161 	return s.buf_ptr-s.buf;
162 }
163 
164 /* decompression routine for 3 4-bit pixels of 5 levels each */
eight2twelve(unsigned char * inbuffer,unsigned char * outbuffer,int num_bytes,int outbuffer_size)165 static int eight2twelve(unsigned char* inbuffer,unsigned char* outbuffer,int num_bytes,int outbuffer_size){
166 	PutBitContext s;
167 	int read_pos=0;
168 	init_put_bits(&s, outbuffer,outbuffer_size);
169 	while(read_pos < num_bytes){
170 		unsigned short value=Table5Level[inbuffer[read_pos]];
171 		++read_pos;
172 		put_bits(&s,12,value);
173 	}
174 	return s.buf_ptr-s.buf;
175 }
176 
177 #if 0
178 static int analysiseight2twelve(unsigned char* inbuffer,unsigned char* outbuffer,int num_bytes,int outbuffer_size){
179 	PutBitContext s;
180 	int maxlevels;
181 	int maxnum;
182 	int read_pos=0;
183 	init_put_bits(&s, outbuffer,outbuffer_size);
184 	while(read_pos < num_bytes){
185 		unsigned short value=Table5Level[inbuffer[read_pos]];
186 		++read_pos;
187 		/*put_bits(&s,12,value);*/
188 		if (value>125) {
189 		  maxlevels+=1;
190 		  if (value>maxnum) {
191 		    maxnum=value;
192 		  }
193 		}
194 	}
195 	/*return s.buf_ptr-s.buf;*/
196 	return maxnum;
197 }
198 #endif
199 
200 /* decompression routine for 3 4-bit pixels of 6 levels each */
eight2twelve2(unsigned char * inbuffer,unsigned char * outbuffer,int num_bytes,int outbuffer_size)201 static int eight2twelve2(unsigned char* inbuffer,unsigned char* outbuffer,int num_bytes,int outbuffer_size){
202 	PutBitContext s;
203 	int read_pos=0;
204 	init_put_bits(&s, outbuffer,outbuffer_size);
205 	while(read_pos < num_bytes){
206 	  unsigned short value=Table6Level[inbuffer[read_pos]];
207 		++read_pos;
208 		put_bits(&s,12,value);
209 	}
210 	return s.buf_ptr-s.buf;
211 }
212 
213 #if 0
214 static int analysiseight2twelve2(unsigned char* inbuffer,unsigned char* outbuffer,int num_bytes,int outbuffer_size){
215 	PutBitContext s;
216 	int maxlevels;
217 	int maxnum;
218 	int read_pos=0;
219 	init_put_bits(&s, outbuffer,outbuffer_size);
220 	while(read_pos < num_bytes){
221 		unsigned short value=Table6Level[inbuffer[read_pos]];
222 		++read_pos;
223 		/*put_bits(&s,12,value);*/
224 		if (value>216) {
225 		  maxlevels+=1;
226 		  if (value>maxnum) {
227 		    maxnum=value;
228 		  }
229 		}
230 	}
231 	/*return s.buf_ptr-s.buf;*/
232 	return maxnum;
233 }
234 #endif
235 
236 /* reads a run length encoded block of raster data, decodes and uncompresses it */
Raster(image_t * img,unsigned char * buffer,unsigned int len,unsigned char color_name,unsigned int maxw)237 static int Raster(image_t* img,unsigned char* buffer,unsigned int len,unsigned char color_name,unsigned int maxw){
238 	color_t* color=get_color(img,color_name);
239         char* buf = (char*)buffer;
240 	int size=0; /* size of unpacked buffer */
241 	int cur_line=0; /* line relative to block begin */
242 	unsigned char* dst=malloc(len*256); /* the destination buffer */
243 	unsigned char* dstr=dst;
244 
245 #if 0
246 	/*int numbigvals;*/ /* number of values greater than number of decompression table max index value */
247 	int maxtablevalue; /* try to catch the range of table values needed for decompression table */
248 	maxtablevalue=0;
249 #endif
250 
251 	/* if(!color){
252 	   printf("no matching color for %c (0x%x, %i) in the database => ignoring %i bytes\n",color_name,color_name,color_name, len);
253 	   } */
254 	if (DEBUG) {
255 	  fprintf(fout,"DEBUG enter Raster len=%i,color=%c\n",len,color_name);
256 	}
257 
258 	/* decode pack bits */
259 	while( len > 0){ /* why does this not work: because unsigned integer wraps! */
260 		int c = *buf;
261 		++buf;
262 		--len;
263 
264 		/*printf("DEBUG top of while loop len=%i\n",len);*/
265 
266 		if(c >= 128)
267 			c -=256;
268 		if(c== -128){ /* end of line => decode and copy things here */
269 		  /*printf("DEBUG end of line---decode and copy things here\n");*/
270 			/* create new list entry */
271 			if(color && size){
272 				if(!color->tail)
273 					color->head = color->tail = color->pos = calloc(1,sizeof(rasterline_t));
274 				else {
275 					color->head->next = calloc(1,sizeof(rasterline_t));
276 					color->head=color->head->next;
277 				}
278 				color->head->line = img->height + cur_line;
279 				if(!color->compression){
280 					color->head->buf=calloc(1,size+8); /* allocate slightly bigger buffer for get_bits */
281 					memcpy(color->head->buf,dstr,size);
282 					color->head->len=size;
283 					if (DEBUG) {
284 					  printf("DEBUG color not compressed\n");
285 					}
286 				}else{
287 				  if (img->color->bpp==2) {/* handle 5pixel in 8 bits compression --- this is pixel-packing rather than compression, just not wasting space */
288 				    color->head->buf=calloc(1,size*2+8);
289 				    size=color->head->len=eight2ten(dstr,color->head->buf,size,size*2);
290 				    /*printf("DEBUG 3-level color compressed\n");*/
291 				  } else if(img->color->bpp==4){ /* handle 4-bit ink compression */
292 				    if (img->color->level==5) {/* 5-level compression --- this is pixel-packing rather than compression, just not wasting space */
293 				      color->head->buf=calloc(1,size*2+8);
294 				      size=color->head->len=eight2twelve(dstr,color->head->buf,size,size*2);
295 				      if (DEBUG) {
296 					printf("DEBUG 5-level color compressed\n");
297 				      }
298 				      /*maxtablevalue=analysiseight2twelve(dstr,color->head->buf,size,size*2);
299 				      if (maxtablevalue!=0) {
300 					printf("maxtablevalue: %x",maxtablevalue);
301 					}*/
302 				    } else if (img->color->level==6) { /* 6-level compression --- this is pixel-packing rather than compression, just not wasting space */
303 				      color->head->buf=calloc(1,size*2+8);
304 				      size=color->head->len=eight2twelve2(dstr,color->head->buf,size,size*2);
305 				      if (DEBUG) {
306 					printf("DEBUG 6-level color compressed\n");
307 				      }
308 				      /*maxtablevalue=analysiseight2twelve2(dstr,color->head->buf,size,size*2);
309 				      if (maxtablevalue!=0) {
310 					printf("maxtablevalue: %x",maxtablevalue);
311 					}*/
312 				    }
313 				  }
314 				}
315 			}
316 			/* adjust the maximum image width */
317 			if(color && color->bpp && img->width < size*8/color->bpp){
318 				unsigned int newwidth = size * 8 / color->bpp;
319 				if(maxw && newwidth > maxw)
320 					newwidth = maxw;
321 				img->width = newwidth;
322 			}
323 			/* reset output buffer */
324 			size=0;
325 			dst=dstr;
326 			++cur_line;
327 		}else {
328 			int i;
329 			if(c < 0){ /* repeat char */
330 				i= - c + 1;
331 				c=*buf;
332 				++buf;
333 				--len;
334 				/*printf("DEBUG repeat character %i\n",len);*/
335 				memset(dst,c,i);
336 				dst +=i;
337 				size+=i;
338 			}else{ /* normal code */
339 			        /*printf("DEBUG normal code\n");*/
340 				i=c+1;
341 				len-=i;
342 				/*printf("DEBUG before memcpy dst,buf,i. %d, %i\n",i,len);*/
343 				memcpy( dst, buf, i);
344 				buf +=i;
345 				dst +=i;
346 				size+=i;
347 			}
348 		}
349 	}
350 	free(dstr);
351 	return 0;
352 }
353 
354 
355 /* checks if the buffer contains a pixel definition at the given x and y position */
inside_range(color_t * c,int x,int y)356 static inline int inside_range(color_t* c,int x,int y){
357   /* debug*/
358   /*  if ((c->name=='C' || c->name=='M' || c->name=='Y' || c->name=='c' || c->name=='m') && x==0 && y==0){
359     printf("%c: bpp: %d\n",c->name,c->bpp);
360     printf("%c: y: %d\n",c->name,y);
361     printf("%c: c->pos->line: %d\n",c->name,c->pos->line);
362     printf("%c: c->pos->len: %d\n",c->name,c->pos->len);
363     printf("%c: x: %d\n",c->name,x);
364     printf("%c: c->bpp*x: %d\n",c->name,c->bpp*x);
365     printf("%c: c->pos->len *8: %d\n",c->name,c->pos->len *8);
366     printf("---\n");
367     }*/
368 	if(c->bpp && c->pos &&  c->pos->line==y && c->pos->len && (c->pos->len *8 >= c->bpp*x))
369 		return 1;
370 	return 0;
371 }
372 
373 
374 /* moves all iterators in the rasterline list */
advance(image_t * img,unsigned int to)375 static void advance(image_t* img,unsigned int to){
376 	int i;
377 	for(i=0;i<MAX_COLORS;i++){
378 		while(img->color[i].pos && img->color[i].pos->line < to && img->color[i].pos->next && img->color[i].pos->next->line <= to){
379 			img->color[i].pos = img->color[i].pos->next;
380 			if(!img->color[i].pos->next)
381 				break;
382 		}
383 	}
384 }
385 
386 /* write 1 line of decoded raster data */
write_line(image_t * img,FILE * fp,int pos_y)387 static void write_line(image_t*img,FILE* fp,int pos_y){
388 	int i;
389 	unsigned int x;
390 	unsigned int written;
391 	unsigned char* line=malloc(img->width*3);
392 	color_t* C=get_color(img,'C');
393 	color_t* M=get_color(img,'M');
394 	color_t* Y=get_color(img,'Y');
395 	color_t* K=get_color(img,'K');
396 	color_t* c=get_color(img,'c');
397 	color_t* m=get_color(img,'m');
398 	color_t* y=get_color(img,'y');
399 	color_t* k=get_color(img,'k');
400 	/* color_t* H=get_color(img,'H'); */
401 	/*color_t* R=get_color(img,'R');*/
402 	/*color_t* G=get_color(img,'G');*/
403 	/* experimenting with strange colors */
404 	/* color_t* P=get_color2(img,'P');
405 	color_t* Q=get_color2(img,'Q');
406 	color_t* R=get_color2(img,'R');
407 	color_t* S=get_color2(img,'S');
408 	color_t* T=get_color2(img,'T'); */
409 
410 	/* color_t* A=get_color(img,'A'); */
411 	/* color_t* B=get_color(img,'B'); */
412 	/* color_t* D=get_color(img,'D'); */
413 	/* color_t* E=get_color(img,'E'); */
414 	/* color_t* F=get_color(img,'F'); */
415 	/* color_t* I=get_color(img,'I'); */
416 	/* color_t* J=get_color(img,'J'); */
417 	/* color_t* L=get_color(img,'L'); */
418 	/* color_t* N=get_color(img,'N'); */
419 	/* color_t* O=get_color(img,'O'); */
420 	/* color_t* P=get_color(img,'P'); */
421 	/* color_t* Q=get_color(img,'Q'); */
422 	/* color_t* S=get_color(img,'S'); */
423 	/* color_t* T=get_color(img,'T'); */
424 	/* color_t* U=get_color(img,'U'); */
425 	/* color_t* V=get_color(img,'V'); */
426 	/* color_t* W=get_color(img,'W'); */
427 	/* color_t* X=get_color(img,'X'); */
428 	/* color_t* Z=get_color(img,'Z'); */
429 	/* color_t* a=get_color(img,'a'); */
430 	/* color_t* b=get_color(img,'b'); */
431 	/* color_t* d=get_color(img,'d'); */
432 	/* color_t* e=get_color(img,'e'); */
433 	/* color_t* f=get_color(img,'f'); */
434 	GetBitContext gb[MAX_COLORS];
435 	/* move iterator */
436 	advance(img,pos_y);
437 	/* init get bits */
438 	for(i=0;i<MAX_COLORS;i++){
439 		if(inside_range(&(img->color[i]),0,pos_y)){
440 			init_get_bits(&(gb[i]),img->color[i].pos->buf,img->color[i].pos->len);
441 		}
442 	}
443 	for(x=0;x<img->width;x++){
444 		int lK=0,lM=0,lY=0,lC=0;
445 		/* initialize so can add same colors together later  */
446 		for(i=0;i<MAX_COLORS;i++){
447 		  img->color[i].value=0;
448 		  }
449 		for(i=0;i<MAX_COLORS;i++){
450 		  if(inside_range(&img->color[i],x,pos_y)) {
451 		    /*img->color[i].value = get_bits(&gb[i],img->color[i].bpp);*/
452 		    img->color[i].value += get_bits(&gb[i],img->color[i].bpp);
453 		    /*		    printf("getting pixel values for color %d\n",i);*/
454 		    /*if (img->color[i].value != 0)
455 		      printf("what pixel values for color %d: %x\n",i,img->color[i].value);*/
456 		    if (i>7){
457 		      fprintf(fout,"getting pixel values for color %d\n",i);/* only going 0 1 2 4 5 --- missing i>7 bugger! */
458 		      /*img->color[i].value = 1;*/
459 		      fprintf(fout,"color %c has value %d\n",img->color[i].name,img->color[i].value);
460 		    }
461 		    /* add 0x80 to colors where 0x80 is seen added in inkset */
462 		  }
463 		  else if(i>7) {
464 		    /* can we force some results here? */
465 		    /*img->color[i].value = 1;*/
466 		    /*get_bits(&gb[i],img->color[i].bpp);*/
467 		  }
468 		  else {
469 		    /*printf(" NOT getting pixel values for color %d\n",i);*/
470 		    img->color[i].value = 0;
471 		  }
472 		  /* update statistics */
473 		  (img->color[i].dots)[img->color[i].value] += 1;
474 		  /* set to 1 if the level is used */
475 		  (img->color[i].usedlevels)[img->color[i].value]=1;
476 		}
477 		/* calculate CMYK values */
478 		/*
479 		lK=K->density * K->value/(K->level-1) + k->density * k->value/(k->level-1);
480 		lM=M->density * M->value/(M->level-1) + m->density * m->value/(m->level-1);
481 		lY=Y->density * Y->value/(Y->level-1) + y->density * y->value/(y->level-1);
482 		lC=C->density * C->value/(C->level-1) + c->density * c->value/(c->level-1);*/
483 
484 		lK=K->density * K->value/(K->level-1) + k->density * k->value/(k->level-1);
485 		lM=M->density * M->value/(M->level-1) + m->density * m->value/(m->level-1);
486 		lY=Y->density * Y->value/(Y->level-1) + y->density * y->value/(y->level-1);
487 		lC=C->density * C->value/(C->level-1) + c->density * c->value/(c->level-1);
488 
489 
490 		/* detect image edges */
491 		if(lK || lM || lY || lC){
492 			if(!img->image_top)
493 				img->image_top = pos_y;
494 			img->image_bottom = pos_y;
495 			if(x < img->image_left)
496 				img->image_left = x;
497 			if(x > img->image_right)
498 				img->image_right = x;
499 		}
500 
501                 /* clip values */
502                 if(lK > 255)
503                    lK = 255;
504                 if(lM > 255)
505                    lM = 255;
506                 if(lC > 255)
507                    lC = 255;
508                 if(lY > 255)
509                    lY = 255;
510 		/* convert to RGB */
511 		/* 0 == black, 255 == white */
512 		line[x*3]=255 - lC - lK;
513 		line[x*3+1]=255 - lM -lK;
514 		line[x*3+2]=255 - lY -lK;
515 		++img->dots;
516 	}
517 
518 	/* output line */
519 	if((written = fwrite(line,img->width,3,fp)) != 3) {
520 		fprintf(fout,"fwrite failed %u vs %u\n",written,img->width*3);
521 	}
522 	free(line);
523 }
524 
525 
526 /* create a ppm image from the decoded raster data */
write_ppm(image_t * img,FILE * fp)527 static void write_ppm(image_t* img,FILE* fp){
528 	int i;
529 	/* allocate buffers for dot statistics */
530         for(i=0;i<MAX_COLORS;i++){
531 	  /*img->color[i].dots=calloc(1,sizeof(int)*(img->color[i].level+1));*/
532 	  img->color[i].dots=calloc(1,sizeof(int)*(1<<((img->color[i].bpp)+1)));
533 	}
534 	/* allocate buffers for levels used*/
535         for(i=0;i<MAX_COLORS;i++){
536 	  img->color[i].usedlevels=calloc(1,sizeof(int)*(1<<((img->color[i].bpp)+1)));
537 	}
538 
539 	/* write header */
540 	fputs("P6\n", fp);
541 	fprintf(fp, "%d\n%d\n255\n", img->width, img->height);
542 
543 	/* set top most left value */
544 	img->image_left = img->width;
545 
546 	/* write data line by line */
547 	for(i=0;i<img->height;i++){
548 		write_line(img,fp,i);
549 	}
550 
551 	/* output some statistics */
552 	printf("statistics:\n");
553 	for(i=0;i<MAX_COLORS;i++){
554 	  int level;
555 	  if (img->color[i].bpp > 0) {
556 	    /*for(level=0;level < img->color[i].level;level++)*/
557 	    for(level=0;level < 1<<(img->color[i].bpp);level++)
558 	      printf("color %c level %i dots %i\n",img->color[i].name,level,img->color[i].dots[level]);
559 	  }
560 	}
561 	printf("Level values actually used:\n");
562 	for(i=0;i<MAX_COLORS;i++){
563 	  int level;
564 	  if (img->color[i].bpp > 0) {
565 	    printf("color %c bpp %i available levels %i declared levels %i --- actual level values used:\n",img->color[i].name,img->color[i].bpp,1<<(img->color[i].bpp),img->color[i].level);
566 	    for(level=0;level < 1<<(img->color[i].bpp);level++)
567 	      printf("%i",img->color[i].usedlevels[level]);
568 	    printf("\n");
569 	  }
570 	}
571 	/* translate area coordinates to 1/72 in (the gutenprint unit)*/
572 	img->image_top = img->image_top * 72.0 / img->yres ;
573 	img->image_bottom = img->image_bottom * 72.0 / img->yres ;
574 	img->image_left = img->image_left * 72.0 / img->xres ;
575 	img->image_right = img->image_right * 72.0 / img->xres ;
576 	printf("top %u bottom %u left %u right %u\n",img->image_top,img->image_bottom,img->image_left,img->image_right);
577 	printf("width %u height %u\n",img->image_right - img->image_left,img->image_bottom - img->image_top);
578 
579 	/* clean up */
580         for(i=0;i<MAX_COLORS;i++){
581 		if(img->color[i].dots)
582 			free(img->color[i].dots);
583 	}
584 
585 }
586 
read_uint32(unsigned char * a)587 static unsigned int read_uint32(unsigned char* a){
588         unsigned int value = ( a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
589         return value;
590 }
591 
592 
593 /* process a printjob command by command */
process(FILE * in,FILE * out,int verbose,unsigned int maxw,unsigned int maxh,unsigned int startxmllen,unsigned int endxmllen)594 static int process(FILE* in, FILE* out,int verbose,unsigned int maxw,unsigned int maxh,unsigned int startxmllen,unsigned int endxmllen){
595 	image_t* img=calloc(1,sizeof(image_t));
596 	unsigned char* buf=malloc(0xFFFF);
597 	int returnv=0;
598 	int i;
599 	int num_colors;
600 	unsigned int xml_read;
601 	xml_read=0;
602 
603 	fprintf(fout,"------- parsing the printjob -------\n");
604 	while(!returnv && !feof(in)){
605 		unsigned char cmd;
606 		unsigned int cnt = 0;
607 		if((returnv = nextcmd(in,&cmd,buf,&cnt,&xml_read,startxmllen,endxmllen)))
608 			break;
609 		switch(cmd){
610 			case 'c':
611 				fprintf(fout,"ESC (c set media (len=%i):\n",cnt);
612 				fprintf(fout," model id %x bw %x",buf[0]>> 4,buf[0]&0xf);
613 				fprintf(fout," media %x",buf[1]);
614 				fprintf(fout," direction %x quality %x\n",(buf[2]>>4)&3 ,buf[2]&0xf);
615 				break;
616 			case 'K':
617 				if(buf[1]==0x1f){
618 				  fprintf(fout,"ESC [K go to command mode\n");
619 					do{
620 						fgets((char*)buf,0xFFFF,in);
621 						fprintf(fout," %s",buf);
622 					}while(strcmp((char*)buf,"BJLEND\n"));
623 				}else if(cnt == 2 && buf[1]==0x0f){
624 					fprintf(fout,"ESC [K reset printer\n");
625 					img->width=0;
626 					img->height=0;
627 				}else{
628 					fprintf(fout,"ESC [K unsupported param (len=%i): %x\n",cnt,buf[1]);
629 				}
630 				break;
631 			case 'b':
632 				fprintf(fout,"ESC (b set data compression (len=%i): %x\n",cnt,buf[0]);
633 				break;
634 			case 'I':
635 				fprintf(fout,"ESC (I select data transmission (len=%i): ",cnt);
636 				if(buf[0]==0)fprintf(fout,"default");
637 				else if(buf[0]==1)fprintf(fout,"multi raster");
638 				else fprintf(fout,"unknown 0x%x %i",buf[0],buf[0]);
639 				fprintf(fout,"\n");
640 				break;
641 			case 'l':
642 				fprintf(fout,"ESC (l select paper loading (len=%i):\n",cnt);
643 				fprintf(fout," model id 0x%x ",buf[0]>>4);
644 				fprintf(fout," source 0x%x",buf[0]&15);
645 				if ( cnt == 3 ) {
646 				  fprintf(fout," media: %x",buf[1]);
647 				  fprintf(fout," paper gap: %x\n",buf[2]);
648 				} else
649 				  fprintf(fout," media: %x\n",buf[1]);
650 				break;
651 			case 'd':
652 				img->xres = (buf[0]<<8)|buf[1];
653 				img->yres = (buf[2]<<8)|buf[3];
654 				fprintf(fout,"ESC (d set raster resolution (len=%i): %i x %i\n",cnt,img->xres,img->yres);
655 				break;
656 			case 't':
657 			  fprintf(fout,"ESC (t set image cnt %i\n",cnt);
658 				if(buf[0]>>7){
659 				        /* usual order */
660 				        char order[]="CMYKcmyk";
661 				        /*char order[]="CMYKcmykHRGABDEFIJLMNOPQSTUVWXZabdef";*/
662 				        /* iP3500 test */
663 				        /*char order[]="CMYKcmykHRGBCMYcmykabd";*/
664 				        /*char order[]="CMYKcmykHpnoPQRSTykabd";*/
665 				        /*char order[]="KCMYkcmyHpnoPQRSTykabd";*/
666 				        /* MP960 photo modes: k instead of K */
667 					/* char order[]="CMYkcmyKHRGABDEFIJLMNOPQSTUVWXZabdef";*/
668 					/* T-shirt transfer mode: y changed to k --- no y, no K */
669 					/*char order[]="CMYKcmkyHRGABDEFIJLMNOPQSTUVWXZabdef";*/
670 					/* MP990, MG6100, MG8100 plain modes */
671 				        /*char order[]="KCcMmYykRHGABDEFIJLMNOPQSTUVWXZabdef";*/
672 					/* MP990 etc. photo modes */
673 				        /* char order[]="KCcMmYykRHGABDEFIJLMNOPQSTUVWXZabdef"; */
674 					/* int black_found = 0; */
675 					num_colors = (cnt - 3)/3;
676 					fprintf(fout," bit_info: using detailed color settings for max %i colors\n",num_colors);
677 					if(buf[1]==0x80)
678 					  fprintf(fout," format: BJ indexed color image format\n");
679                                         else if(buf[1]==0x00)
680 						fprintf(fout," format: iP8500 flag set, BJ indexed color image format\n");
681                                         else if(buf[1]==0x90)
682 						fprintf(fout," format: Pro9500 flag set, BJ indexed color image format\n");
683 					else{
684 						fprintf(fout," format: settings not supported 0x%x\n",buf[1]);
685 						/* returnv = -2; */
686 					}
687 					if(buf[2]==0x1)
688 					        fprintf(fout," ink: BJ indexed setting, also for iP8500 flag\n");
689 					else if(buf[2]==0x4)
690 					        fprintf(fout," ink: Pro series setting \n");
691 					else{
692 						fprintf(fout," ink: settings not supported 0x%x\n",buf[2]);
693 						/* returnv = -2; */
694 					}
695 
696 					for(i=0;i<num_colors;i++){
697 					  if(i<MAX_COLORS){
698 					    img->color[i].name=order[i];
699 					    img->color[i].compression=buf[3+i*3] >> 5;
700 					    img->color[i].bpp=buf[3+i*3] & 31;
701 					    img->color[i].level=(buf[3+i*3+1] << 8) + buf[3+i*3+2];/* check this carefully */
702 
703 					    /* work around for levels not matching (bpp gives more) */
704 					    /*if ((img->color[i].level == 3) && (img->color[i].bpp == 2)) {
705 					      printf("WARNING: color %c bpp %i declared levels %i, setting to 4 for testing \n",img->color[i].name,img->color[i].bpp,img->color[i].level);
706 					      img->color[i].level = 4;
707 					      } */
708 					    /*else if ((img->color[i].level == 4) && (img->color[i].bpp == 4)) {*/
709 					    /* levels is 16 but only each 2nd level is used */
710 					    /*  printf("WARNING: color %c bpp %i declared levels %i, setting to 16 for testing \n",img->color[i].name,img->color[i].bpp,img->color[i].level);
711 						img->color[i].level = 16;
712 						} */
713 
714 					    /* this is not supposed to give accurate images */
715 					    /* if(i<4) */ /* set to actual colors CMYK */
716 					    if((img->color[i].name =='K')||(img->color[i].name =='C')||(img->color[i].name =='M')||(img->color[i].name =='Y') ) {
717 					      img->color[i].density = 255;
718 					      /*if (i>7)*/
719 						/*img->color[i].density -= 128; */
720 					      /* see if can subtract something from CMYK where 0x80 involved */
721 					    }
722 					    else
723 					      img->color[i].density = 128; /*128+96;*/ /* try to add 0x80 to sub-channels for MP450 hi-quality mode */
724                                             /*
725 					    if((order[i] == 'K' || order[i] == 'k') && img->color[i].bpp)
726 					      black_found = 1;
727 					    */
728 					    /*
729 					    if(order[i] == 'y' && !black_found && img->color[i].level){
730 					      printf("iP6700 hack: treating color definition at the y position as k\n");
731 					      img->color[i].name = 'k';
732 					      order[i] = 'k';
733 					      order[i+1] = 'y';
734 					      black_found = 1;
735 					      img->color[i].density = 255;
736 					    }
737 					    */
738 					    /* %c*/
739 					    fprintf(fout," Color %c Compression: %i bpp %i level %i\n",img->color[i].name,
740 						   img->color[i].compression,img->color[i].bpp,img->color[i].level);
741 					  }else{
742 					    fprintf(fout," Color %i out of bounds!\n", i);
743 					    /*printf(" Color ignoring setting %x %x %x\n",buf[3+i*3],buf[3+i*3+1],buf[3+i*3+2]);*/
744 					  }
745 
746 					}
747 
748 
749 				}else if(buf[0]==0x1 && buf[1]==0x0 && buf[2]==0x1){
750 					fprintf(fout," 1bit-per pixel\n");
751 					num_colors = cnt*3; /*no idea yet! 3 for iP4000 */
752 					/*num_colors=9;*/
753 					/*for(i=0;i<MAX_COLORS;i++){*/
754 					for(i=0;i<num_colors;i++){
755 					  if(i<MAX_COLORS){
756 					        /* usual */
757   					        char order[]="CMYKcmyk";
758 					        /* const char order[]="CMYKcmykHRGABDEFIJLMNOPQSTUVWXZabdef";*/
759 				                /* iP3500 test */
760 				                /* char order[]="CMYKcmykHRGBCMYcmykabd"; */
761 						/* MP990, MG6100, MG8100 plain modes */
762 						/*const char order[]="KCcMmYykRHGABDEFIJLMNOPQSTUVWXZabdef";*/
763 						img->color[i].name=order[i];
764 						img->color[i].compression=0;
765 						img->color[i].bpp=1;
766 						img->color[i].level=2;
767 						img->color[i].density = 255;
768 						/*add color printout for this type also %c */
769 						fprintf(fout," Color %c Compression: %i bpp %i level %i\n",img->color[i].name,
770 						       img->color[i].compression,img->color[i].bpp,img->color[i].level);
771 					  }else{
772 					    fprintf(fout," Color %i out of bounds!", i);
773 						/*printf(" Color ignoring setting %x %x %x\n",buf[3+i*3],buf[3+i*3+1],buf[3+i*3+2]);*/
774 					  }
775 					}
776 				}else{
777 					fprintf(fout," bit_info: unknown settings 0x%x 0x%x 0x%x\n",buf[0],buf[1],buf[2]);
778 					/* returnv=-2; */
779 				}
780 				break;
781 			case 'L':
782 				fprintf(fout,"ESC (L set component order for F raster command (len=%i): ",cnt);
783 				img->color_order=calloc(1,cnt+1);
784 				/* check if the colors are sane => the iP4000 driver appends invalid bytes in the highest resolution mode */
785 				for(i=0;i<cnt;i++){
786 				  if (!valid_color(buf[i]))
787                                     {
788 				    /*if (!(valid_color(buf[i]-0x60))) {*/
789 				    /*  printf("invalid color char %c [failed on initial]\n", buf[i]);*/
790 				    /*  break; */
791 				    /*}*/
792 				    /*else {*/
793 				      buf[i]=buf[i]-0x60;
794 				      fprintf(fout,"subtracting 0x60 to give [corrected]: %c\n", buf[i]);
795 				    }
796 				  else
797 				    fprintf(fout,"found valid color char: %c\n",buf[i]);
798 				}
799 				cnt = i;
800 				memcpy(img->color_order,buf,cnt);
801 				fprintf(fout,"%s\n",img->color_order);
802 				img->num_colors = cnt;
803 				img->cur_color=0;
804 				break;
805 			case 'p':
806 				fprintf(fout,"ESC (p set extended margin (len=%i):\n",cnt);
807                                 fprintf(fout," printed length %i left %i\n",((buf[0]<<8 )+buf[1]) *6 / 5 - 1,(buf[2]<<8) + buf[3]);
808                                 fprintf(fout," printed width %i top %i\n",((buf[4]<<8 )+buf[5]) * 6 / 5 - 1,(buf[6]<<8) + buf[7]);
809 
810                                 if(cnt > 8){
811 					int unit = (buf[12] << 8)| buf[13];
812 					int area_right = read_uint32(buf+14);
813 					int area_top = read_uint32(buf+18);
814 					unsigned int area_width = read_uint32(buf+22);
815 					unsigned int area_length = read_uint32(buf+26);
816 					int paper_right = read_uint32(buf+30);
817 					int paper_top = read_uint32(buf+34);
818 					unsigned int paper_width = read_uint32(buf+38);
819 					unsigned int paper_length = read_uint32(buf+42);
820                                         fprintf(fout," unknown %i\n",read_uint32(buf+8));
821                                         fprintf(fout," unit %i [1/in]\n",unit);
822                                         fprintf(fout," area_right %i %.1f mm\n",area_right,area_right * 25.4 / unit);
823                                         fprintf(fout," area_top %i %.1f mm\n",area_top,area_top * 25.4 / unit);
824                                         fprintf(fout," area_width %u %.1f mm\n",area_width, area_width * 25.4 / unit);
825                                         fprintf(fout," area_length %u %.1f mm\n",area_length,area_length * 25.4 / unit);
826                                         fprintf(fout," paper_right %i %.1f mm\n",paper_right,paper_right * 25.4 / unit);
827                                         fprintf(fout," paper_top %i %.1f mm\n",paper_top,paper_top * 25.4 / unit);
828                                         fprintf(fout," paper_width %u %.1f mm\n",paper_width,paper_width * 25.4 / unit);
829                                         fprintf(fout," paper_length %u %.1f mm\n",paper_length,paper_length * 25.4 / unit);
830 					img->top = (float)area_top / unit;
831 					img->left = (float)area_top / unit;
832                                 }
833 				break;
834 			case '$':
835 				fprintf(fout,"ESC ($ set duplex (len=%i)\n",cnt);
836 				break;
837 			case 'J':
838 				fprintf(fout,"ESC (J select number of raster lines per block (len=%i): %i\n",cnt,buf[0]);
839 				img->lines_per_block=buf[0];
840 				break;
841 			case 'F':
842 				if(verbose)
843 					fprintf(fout,"ESC (F raster block (len=%i):\n",cnt);
844 				if((returnv = Raster(img,buf,cnt,img->color_order[img->cur_color],maxw)))
845 					break;
846 				++img->cur_color;
847 				if(img->cur_color >= img->num_colors){
848 					img->cur_color=0;
849 					img->height+=img->lines_per_block;
850 				}
851 				break;
852 			case 'q':
853 				fprintf(fout,"ESC (q set page id (len=%i):%i\n",cnt,buf[0]);
854 				break;
855 			case 'r':
856 				fprintf(fout,"ESC (r printer specific command (len=%i): ",cnt);
857 				for(i=0;i<cnt;i++)
858 					fprintf(fout,"0x%x ",buf[i]);
859 				fprintf(fout,"\n");
860 				break;
861 			case 'A':
862 				if(verbose)
863 					fprintf(fout,"ESC (A raster line (len=%i): color %c\n",cnt,buf[0]);
864 				/* the single line rasters are not terminated by 0x80 => do it here
865 				 * instead of 0x80 every raster A command is followed by a 0x0d byte
866 				 * the selected color is stored in the first byte
867 				 */
868 				buf[cnt]=0x80;
869 				returnv = Raster(img,buf+1,cnt,buf[0],maxw);
870 				if (fgetc(in)!=0x0d){
871 					fprintf(fout,"Raster A not terminated by 0x0d\n");
872 					returnv=-4;
873 				}
874 				break;
875 			case 'e': /* Raster skip */
876 				if(verbose)
877 					fprintf(fout,"ESC (e advance (len=%i): %i\n",cnt,buf[0]*256+buf[1]);
878 				if(img->lines_per_block){
879 					img->height += (buf[0]*256+buf[1])*img->lines_per_block;
880 					img->cur_color=0;
881 				}else
882 					img->height += (buf[0]*256+buf[1]);
883 				break;
884 			default: /* Last but not least completely unknown commands */
885 				fprintf(fout,"ESC (%c UNKNOWN (len=%i)\n",cmd,cnt);
886 				for(i=0;i<cnt;i++)
887 					fprintf(fout," 0x%x",buf[i]);
888 				fprintf(fout,"\n");
889 
890 		}
891 	}
892 
893 	fprintf(fout,"-------- finished parsing   --------\n");
894 	if(returnv < -2){ /* was < 0 :  work around to see what we get */
895 		fprintf(fout,"error: parsing the printjob failed error %i\n",returnv);
896 	} else {
897 
898 		fprintf(fout,"created bit image with width %i height %i\n",img->width,img->height);
899 		if(maxh > 0){
900 			fprintf(fout,"limiting height to %u\n",maxh);
901 			img->height=maxh;
902 		}
903 
904 		/* now that we have a complete nice raster image
905 	 	* lets build a bitmap from it
906          	*/
907 		if(out)
908 			write_ppm(img,out);
909 		fprintf(fout,"dots: %u\n",img->dots);
910 
911 	}
912 	/* deallocate resources */
913 	free(buf);
914 	for(i=0;i<MAX_COLORS;i++){
915 		rasterline_t** r=&img->color[i].tail;
916 		while(*r){
917 			rasterline_t* tmp=(*r)->next;
918 			free((*r)->buf);
919 			free(*r);
920 			*r=tmp;
921 		}
922 	}
923 	if(img->color_order)
924 		free(img->color_order);
925 	free(img);
926 	return returnv;
927 }
928 
929 
930 
display_usage(void)931 static void display_usage(void){
932 	printf("usage: pixma_parse [options] infile [outfile]\n");
933 	printf("infile: the printjob to parse\n");
934 	printf("outfile: if specified a ppm file will be generated from the raster data\n");
935 	printf("options:\n");
936 	printf(" -v: verbose print ESC e),F) and A) commands\n");
937 	printf(" -x width: cut the output ppm to the given width\n");
938 	printf(" -y height: cut the output ppm to the given height\n");
939 	printf(" -s if XML prolog is present, define number of bytes (default 680) \n");
940 	printf(" -e if XML epilog is present, define number of bytes (default 263) \n");
941 	printf(" -h: display this help\n");
942 }
943 
944 
945 
main(int argc,char * argv[])946 int main(int argc,char* argv[]){
947 	int verbose = 0;
948 	unsigned int maxh=0;
949 	unsigned int maxw=0;
950 	unsigned int startxmllen, endxmllen;
951 
952 	char* filename_in=NULL,*filename_out=NULL;
953 	FILE *in,*out=NULL;
954 	int i;
955 
956 	startxmllen=680; // 1086; 732; 680; embedded parameters varies with driver -- TODO: parse XML separately
957 	endxmllen=263; // default value
958 
959 	if (DEBUG)
960 	  fout = stderr; /* unbuffered */
961 	else
962 	  fout = stdout; /* buffered */
963 
964 	printf("pixma_parse - parser for Canon BJL printjobs (c) 2005-2007 Sascha Sommer <saschasommer@freenet.de>\n");
965 
966 	/* parse args */
967 	for(i=1;i<argc;i++){
968 		if(strlen(argv[i]) >= 2 && argv[i][0] == '-'){
969 			if(argv[i][1] == 'v'){
970 				verbose = 1;
971 			}else if(argv[i][1] == 'h'){
972 				display_usage();
973 				return 0;
974 			}else if(argv[i][1] == 'y'){
975 				if(argc > i+1){
976 					++i;
977 					maxh = atoi(argv[i]);
978 				}else{
979 					display_usage();
980 					return 1;
981 				}
982 			}else if(argv[i][1] == 'x'){
983 				if(argc > i+1){
984 					++i;
985 					maxw = atoi(argv[i]);
986 				}else{
987 					display_usage();
988 					return 1;
989 				}
990 			}else if(argv[i][1] == 's'){
991 				if(argc > i+1){
992 					++i;
993 					startxmllen = atoi(argv[i]);
994 				}else{
995 					display_usage();
996 					return 1;
997 				}
998 			}else if(argv[i][1] == 'e'){
999 				if(argc > i+1){
1000 					++i;
1001 					endxmllen = atoi(argv[i]);
1002 				}else{
1003 					display_usage();
1004 					return 1;
1005 				}
1006 			}else {
1007 			  printf("unknown parameter %s\n",argv[i]);
1008 				return 1;
1009 			}
1010 		}else if(!filename_in){
1011 			filename_in = argv[i];
1012 		}else if(!filename_out){
1013 			filename_out = argv[i];
1014 		}else{
1015 			display_usage();
1016 			return 1;
1017 		}
1018 	}
1019 	if(!filename_in){
1020 		display_usage();
1021 		return 1;
1022 	}
1023 
1024 	/* open input file */
1025 	if(!(in=fopen(filename_in,"rb"))){
1026 	  printf("unable to open input file %s\n",filename_in);
1027 		return 1;
1028 	}
1029 
1030 	/* open output file */
1031 	if(filename_out && !(out=fopen(filename_out,"wb"))){
1032 	  printf("can't create the output file %s\n",filename_out);
1033 		fclose(in);
1034 		return 1;
1035 	}
1036 
1037 	/* process the printjob */
1038 	process(in,out,verbose,maxw,maxh,startxmllen,endxmllen);
1039 
1040 	/* cleanup */
1041 	fclose(in);
1042 	if(out)
1043 		fclose(out);
1044 	return 0;
1045 }
1046