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