Commit | Line | Data |
---|---|---|
e37aebf7 C |
1 | /* decode.c - the generic decoder */ |
2 | ||
3 | #ifndef lint | |
4 | static char *rcsid = "$Header: /f/osi/others/quipu/photo/RCS/decode.c,v 7.3 90/09/25 18:44:48 mrose Exp $"; | |
5 | #endif | |
6 | ||
7 | /* | |
8 | * $Header: /f/osi/others/quipu/photo/RCS/decode.c,v 7.3 90/09/25 18:44:48 mrose Exp $ | |
9 | * | |
10 | * | |
11 | * $Log: decode.c,v $ | |
12 | * Revision 7.3 90/09/25 18:44:48 mrose | |
13 | * ... | |
14 | * | |
15 | * Revision 7.2 90/09/24 15:36:41 mrose | |
16 | * update | |
17 | * | |
18 | * Revision 7.1 90/07/09 14:40:20 mrose | |
19 | * sync | |
20 | * | |
21 | * Revision 7.0 89/11/23 22:01:37 mrose | |
22 | * Release 6.0 | |
23 | * | |
24 | */ | |
25 | ||
26 | /* | |
27 | * NOTICE | |
28 | * | |
29 | * Acquisition, use, and distribution of this module and related | |
30 | * materials are subject to the restrictions of a license agreement. | |
31 | * Consult the Preface in the User's Manual for the full terms of | |
32 | * this agreement. | |
33 | * | |
34 | */ | |
35 | ||
36 | ||
37 | ||
38 | #include <stdio.h> | |
39 | #include <sgtty.h> | |
40 | #include <signal.h> | |
41 | #include "quipu/photo.h" | |
42 | ||
43 | #define ERR_RUN 0x0f | |
44 | ||
45 | #ifdef lint | |
46 | #define FAXDIR "/tmp" | |
47 | #endif | |
48 | ||
49 | /* this file contains the main routines for decoding X400 */ | |
50 | ||
51 | extern int PIC_LINESIZE,STOP,NUMLINES; | |
52 | ||
53 | /* variables for top of the code word trees */ | |
54 | node * bl_tree_top; | |
55 | node * wt_tree_top; | |
56 | node * two_tree_top; | |
57 | ||
58 | unsigned int position; | |
59 | ||
60 | static char ref_colour; | |
61 | static char colour; | |
62 | char * malloc (); | |
63 | char *bitmap; | |
64 | ||
65 | /* ROUTINE: Decode_t4 | |
66 | /* | |
67 | /* SYNOPSIS: Decodes a bit map stored in format T4 as recommended | |
68 | /* by CCITT. | |
69 | /* | |
70 | /* DESCRIPTION: After setting up the buffers, a line at a time is dealt with. | |
71 | /* Each line is recognised as being one or two dimensionally coded, depending | |
72 | /* upon the tag bit. | |
73 | /* The run change buffers for each line are kept incase the next line is two | |
74 | /* dimensionally, when it will be used as a reference. | |
75 | /* | |
76 | */ | |
77 | ||
78 | int decode_t4 (inbuf, winname, length) | |
79 | char *inbuf, *winname; | |
80 | int length; | |
81 | { | |
82 | bit_string code_line, /* output line */ | |
83 | ref_line, /* reference line */ | |
84 | t4_line; /* input line */ | |
85 | ||
86 | int done = 0; | |
87 | run_type run; | |
88 | ||
89 | int *buffer1, *buffer2; | |
90 | int *run_buf1, *run_buf2; | |
91 | char tag,nextbit; | |
92 | ||
93 | if (photo_start (winname) == -1) | |
94 | return (-1); | |
95 | ||
96 | if (build_trees (FAXDIR) == -1) | |
97 | return (-1); | |
98 | ||
99 | buffer1 = (int *) malloc (LINEBUF * sizeof(int)); | |
100 | buffer2 = (int *) malloc (LINEBUF * sizeof(int)); | |
101 | if (buffer1 == NULL || buffer2 == NULL) { | |
102 | no_mem: ; | |
103 | (void) fprintf (stderr, "PHOTO: out of memory for %s", winname); | |
104 | losing: ; | |
105 | if (buffer1) | |
106 | free (buffer1); | |
107 | if (buffer2) | |
108 | free (buffer2); | |
109 | return (-1); | |
110 | } | |
111 | buffer1[0] = 0; /* to halt backtracting if needed at start of line */ | |
112 | buffer2[0] = 0; | |
113 | run_buf1 = buffer1; | |
114 | run_buf2 = buffer2; | |
115 | ref_line.run_top = ++run_buf1; | |
116 | code_line.run_top = ++run_buf2; | |
117 | ||
118 | if ((code_line.dbuf_top = malloc (BUFSIZ)) == NULL) | |
119 | goto no_mem; | |
120 | t4_line.dbuf_top = inbuf; | |
121 | ||
122 | if (set_dinput (&t4_line, length) == -1) | |
123 | goto losing; | |
124 | set_doutput (&code_line); | |
125 | ||
126 | /* t4 starts with an initial end of line */ | |
127 | run = next_run(&t4_line,WHITE); | |
128 | if (run.r_type == ERR_RUN) | |
129 | goto losing; | |
130 | if (run.r_type != EOLN) { | |
131 | (void) fprintf (stderr,"PHOTO: Initial end of line missing for %s", | |
132 | winname); | |
133 | goto losing; | |
134 | } | |
135 | if ( get_bit(&t4_line) != 1){ | |
136 | (void) fprintf (stderr,"PHOTO: Initial end of line (2) missing for %s", | |
137 | winname); | |
138 | goto losing; | |
139 | } | |
140 | ||
141 | NUMLINES = -1; | |
142 | ||
143 | tag = nextbit = get_bit(&t4_line); | |
144 | ||
145 | do { | |
146 | NUMLINES++; | |
147 | ||
148 | position = 1; | |
149 | if (nextbit != tag ) | |
150 | { if (code_line.run_top == run_buf1) | |
151 | { ref_line.run_top = run_buf1; | |
152 | code_line.run_top = run_buf2; | |
153 | } | |
154 | else | |
155 | { ref_line.run_top = run_buf2; | |
156 | code_line.run_top = run_buf1; | |
157 | } | |
158 | done = decode_two (&ref_line,&code_line,&t4_line); | |
159 | } | |
160 | else | |
161 | { code_line.run_pos = code_line.run_top; | |
162 | done = decode_one (&code_line,&t4_line); | |
163 | } | |
164 | ||
165 | if (done == -1) | |
166 | goto losing; | |
167 | ||
168 | flush_doutput (&code_line); | |
169 | set_doutput (&code_line); | |
170 | ||
171 | photo_line_end (&code_line); | |
172 | ||
173 | if (!done) | |
174 | nextbit = get_bit(&t4_line); | |
175 | ||
176 | } while (! done); | |
177 | ||
178 | flush_doutput (&code_line); | |
179 | bitmap = code_line.dbuf_top; | |
180 | ||
181 | (void) free ( (char *)buffer1); | |
182 | (void) free ( (char *)buffer2); | |
183 | ||
184 | return (photo_end (winname)); | |
185 | ||
186 | } | |
187 | ||
188 | ||
189 | ||
190 | /* ROUTINE: next_run | |
191 | * | |
192 | * SYNOPSIS: Reads the next run length from the input file. | |
193 | * | |
194 | * DESCRIPTION: As each bit is read, it is used to move down the decode tree, | |
195 | * when a node is found that contains a value, the value is returned. | |
196 | * The code is assumed to be one dimensional. | |
197 | */ | |
198 | ||
199 | run_type | |
200 | next_run (lineptr,xcolour) | |
201 | bit_string * lineptr; | |
202 | char xcolour; | |
203 | { | |
204 | ||
205 | node * ptr; | |
206 | run_type result ; | |
207 | result.run_length = 0; | |
208 | ||
209 | if (xcolour == BLACK) { | |
210 | ptr = bl_tree_top; | |
211 | } else { | |
212 | ptr = wt_tree_top; | |
213 | } | |
214 | ||
215 | if (ptr == NULL) { | |
216 | (void) fprintf (stderr,"PHOTO: tree error"); | |
217 | result.r_type = ERR_RUN; | |
218 | return (result); | |
219 | } | |
220 | ||
221 | do { | |
222 | ||
223 | if (get_bit (lineptr) == 0) | |
224 | ptr = ptr->zero; | |
225 | else | |
226 | ptr = ptr->one; | |
227 | ||
228 | if (ptr == NULL) { | |
229 | /* it may be possible to recover from this in the future */ | |
230 | (void) fprintf (stderr,"PHOTO: Sequencing error (1)"); | |
231 | result.r_type = ERR_RUN; | |
232 | return (result); | |
233 | } | |
234 | ||
235 | } while (ptr->n_type == INTERNAL); | |
236 | ||
237 | /* if the above value was a make up code, now read the terminal code */ | |
238 | if (ptr->n_type == MAKE) { | |
239 | result.run_length = ptr->value; | |
240 | if (xcolour == BLACK) { | |
241 | ptr = bl_tree_top; | |
242 | } else { | |
243 | ptr = wt_tree_top; | |
244 | } | |
245 | ||
246 | if (ptr == NULL) { | |
247 | (void) fprintf (stderr,"PHOTO: tree error"); | |
248 | result.r_type = ERR_RUN; | |
249 | return (result); | |
250 | } | |
251 | ||
252 | do { | |
253 | ||
254 | if (get_bit (lineptr) == 0) { | |
255 | ptr = ptr->zero; | |
256 | } else { | |
257 | ptr = ptr->one; | |
258 | } | |
259 | ||
260 | if (ptr == NULL) { | |
261 | /* it may be possible to recover from this ! */ | |
262 | (void) fprintf (stderr,"PHOTO: Sequencing error (2)"); | |
263 | result.r_type = ERR_RUN; | |
264 | return (result); | |
265 | } | |
266 | } while (ptr->n_type == INTERNAL); | |
267 | ||
268 | } | |
269 | ||
270 | result.run_length += ptr->value; | |
271 | result.r_type = ptr->n_type; | |
272 | return (result); | |
273 | ||
274 | } | |
275 | ||
276 | ||
277 | ||
278 | /* ROUTINE: decode_one | |
279 | /* | |
280 | /* SYNOPSIS: decodes one line of t4. | |
281 | /* | |
282 | /* DESCRIPTION: reads a run, then writes that many bit of the appropiate | |
283 | /* colour to the output. | |
284 | */ | |
285 | ||
286 | decode_one (lineptr, t4_lineptr) | |
287 | bit_string * lineptr; | |
288 | bit_string * t4_lineptr; | |
289 | ||
290 | { | |
291 | run_type run; | |
292 | char xcolour = WHITE; | |
293 | int done; | |
294 | int savelinesize; | |
295 | ||
296 | savelinesize = PIC_LINESIZE; | |
297 | PIC_LINESIZE = 0; | |
298 | run = next_run (t4_lineptr,xcolour); | |
299 | if (run.r_type == ERR_RUN) | |
300 | return (-1); | |
301 | ||
302 | while (run.r_type != EOLN) { | |
303 | PIC_LINESIZE += run.run_length; | |
304 | put_run (lineptr,run.run_length,xcolour); | |
305 | xcolour = 1 - xcolour; | |
306 | run = next_run (t4_lineptr,xcolour); | |
307 | if (run.r_type == ERR_RUN) | |
308 | return (-1); | |
309 | } | |
310 | while (get_bit(t4_lineptr) != 01) | |
311 | ; /* skip fill characters */ | |
312 | ||
313 | if (lineptr->run_pos == lineptr->run_top){ | |
314 | done = 1; | |
315 | PIC_LINESIZE = savelinesize; | |
316 | } else | |
317 | done = 0; | |
318 | ||
319 | STOP = PIC_LINESIZE + 1; | |
320 | *(lineptr->run_pos++) = STOP; | |
321 | *(lineptr->run_pos) = STOP; | |
322 | ||
323 | return (done); | |
324 | } | |
325 | ||
326 | ||
327 | ||
328 | /* ROUTINE: decode_two | |
329 | /* | |
330 | /* SYNOPSIS: decodes a two dim line. | |
331 | /* | |
332 | /* DESCRIPTION: The binary codes read in are looked up in the decode tree, | |
333 | /* and the appropiate routine called to decode that mode. | |
334 | */ | |
335 | ||
336 | decode_two (ref_lineptr,code_lineptr,t4_lineptr) | |
337 | ||
338 | bit_string * ref_lineptr; | |
339 | bit_string * code_lineptr; | |
340 | bit_string * t4_lineptr; | |
341 | ||
342 | { | |
343 | node * ptr; | |
344 | int done; | |
345 | ||
346 | ref_lineptr->run_pos = ref_lineptr->run_top; | |
347 | code_lineptr->run_pos = code_lineptr->run_top; | |
348 | colour = WHITE; | |
349 | ref_colour = BLACK; | |
350 | do { | |
351 | ptr = two_tree_top; | |
352 | do { | |
353 | if (ptr == NULL) { | |
354 | (void) fprintf (stderr,"PHOTO: 2-d line failure"); | |
355 | return (-1); | |
356 | } | |
357 | ||
358 | if (get_bit (t4_lineptr) == 0) | |
359 | ptr = ptr->zero; | |
360 | else | |
361 | ptr = ptr->one; | |
362 | } while (ptr->n_type == INTERNAL); | |
363 | ||
364 | switch (ptr->value) { | |
365 | ||
366 | case P: undo_pass_mode (ref_lineptr,code_lineptr); | |
367 | break; | |
368 | ||
369 | case H: if (undo_horiz_mode (t4_lineptr,code_lineptr) == -1) | |
370 | return (-1); | |
371 | break; | |
372 | ||
373 | case EOLN: break; | |
374 | ||
375 | default: undo_vert_mode (ref_lineptr,code_lineptr,ptr->value); | |
376 | ||
377 | } | |
378 | ||
379 | } while (ptr->n_type != EOLN ); | |
380 | ||
381 | /* fill to end of line with current colour */ | |
382 | put_run (code_lineptr,(int)( PIC_LINESIZE - position + 1 ), colour); | |
383 | ||
384 | if (code_lineptr->run_pos == code_lineptr->run_top) /* no runs found */ | |
385 | done = 1; | |
386 | else | |
387 | done = 0; | |
388 | ||
389 | while (get_bit (t4_lineptr) != 1) | |
390 | ; /* skip fill characters */ | |
391 | ||
392 | *(code_lineptr->run_pos++) = STOP; | |
393 | *(code_lineptr->run_pos) = STOP; | |
394 | ||
395 | return (done); | |
396 | } | |
397 | ||
398 | ||
399 | /* ROUTINE: undo_pass_mode | |
400 | /* | |
401 | /* SYNOPSIS: decodes a section recognised as pass mode. | |
402 | /* | |
403 | /* DESCRIPTION: find b2, then write to output the same colour as before | |
404 | /* up until position b2. | |
405 | */ | |
406 | ||
407 | undo_pass_mode (ref_lineptr,code_lineptr) | |
408 | bit_string * ref_lineptr; | |
409 | bit_string * code_lineptr; | |
410 | ||
411 | { | |
412 | goto_b1 (ref_lineptr); | |
413 | ||
414 | ref_lineptr->run_pos++; | |
415 | ref_colour = 1 - ref_colour; | |
416 | ||
417 | put_run (code_lineptr,(int) (*(ref_lineptr->run_pos) - position), colour); | |
418 | code_lineptr->run_pos--; /* don't count this as a change */ | |
419 | } | |
420 | ||
421 | ||
422 | ||
423 | ||
424 | /* ROUTINE: undo_horiz_mode | |
425 | /* | |
426 | /* SYNOPSIS: decodes a section recognised as horizontal mode. | |
427 | /* | |
428 | /* DESCRIPTION: Read two run lengths for the input, and write the appropiate | |
429 | /* number of 1's or 0's to the output. | |
430 | */ | |
431 | ||
432 | undo_horiz_mode (t4_lineptr,code_lineptr) | |
433 | ||
434 | bit_string * t4_lineptr; | |
435 | bit_string * code_lineptr; | |
436 | ||
437 | { | |
438 | run_type run; | |
439 | ||
440 | run = next_run (t4_lineptr,colour); | |
441 | if (run.r_type == ERR_RUN) | |
442 | return (-1); | |
443 | put_run (code_lineptr,run.run_length,colour); | |
444 | ||
445 | run = next_run (t4_lineptr,1-colour); | |
446 | if (run.r_type == ERR_RUN) | |
447 | return (-1); | |
448 | put_run (code_lineptr,run.run_length,1-colour); | |
449 | ||
450 | return (0); | |
451 | } | |
452 | ||
453 | ||
454 | /* ROUTINE: undo_vert_mode | |
455 | /* | |
456 | /* SYNOPSIS: decodes vertical mode | |
457 | /* | |
458 | /* DESCRIPTION: Find b1, the write 1's or 0's upto it allowing for the offset. | |
459 | */ | |
460 | ||
461 | undo_vert_mode (ref_lineptr,code_lineptr,offset) | |
462 | ||
463 | bit_string * ref_lineptr; | |
464 | bit_string * code_lineptr; | |
465 | char offset; | |
466 | ||
467 | { | |
468 | int length; | |
469 | ||
470 | /* find b1 */ | |
471 | goto_b1 (ref_lineptr); | |
472 | ||
473 | length = (*ref_lineptr->run_pos - position) + offset - FIXED_OFFSET; | |
474 | put_run ( code_lineptr, length , colour); | |
475 | colour = 1 - colour; | |
476 | } | |
477 | ||
478 | /* ROUTINE: goto_b1 | |
479 | * | |
480 | * SYNOPSIS: move the pointer in the reference line to b1 | |
481 | * | |
482 | * DESCRIPTION: b1 is the first changing bit in the reference line | |
483 | * of a different colour to a0. May need to move backwards or forwards | |
484 | * | |
485 | */ | |
486 | ||
487 | goto_b1 (lineptr) | |
488 | bit_string * lineptr; | |
489 | ||
490 | { | |
491 | ||
492 | if ( *lineptr->run_pos > position ) | |
493 | do | |
494 | ref_colour = 1 - ref_colour; | |
495 | while ( *--lineptr->run_pos > position ) ; | |
496 | ||
497 | if ( *lineptr->run_pos < position ) | |
498 | do | |
499 | ref_colour = 1 - ref_colour; | |
500 | while ( *++lineptr->run_pos < position ) ; | |
501 | ||
502 | if (ref_colour == colour) { | |
503 | lineptr->run_pos++; | |
504 | ref_colour = 1 - ref_colour; | |
505 | ||
506 | } else | |
507 | /* special case when b1 = a0, and the colours are different, | |
508 | move b1 to the next change of same colour, | |
509 | this must be allowed at the beginning of a line to get a run of | |
510 | zero, as every line must start with a white element */ | |
511 | if ((*lineptr->run_pos == position) && (*lineptr->run_pos >1 )) { | |
512 | lineptr->run_pos++; | |
513 | lineptr->run_pos++; | |
514 | } | |
515 | ||
516 | } | |
517 | ||
518 | ||
519 | /* ROUTINE: put_run */ | |
520 | /* */ | |
521 | /* SYNOPSIS: writes a run_length to the indiacated bit_string, */ | |
522 | /* */ | |
523 | ||
524 | put_run (lineptr, length, xcolour) | |
525 | bit_string * lineptr; | |
526 | int length; | |
527 | char xcolour; | |
528 | { | |
529 | register i; | |
530 | ||
531 | if ( xcolour == WHITE) | |
532 | photo_white (length); | |
533 | else | |
534 | photo_black (length); | |
535 | ||
536 | /* now fill line buffer for purpose of decoding 2-d lines */ | |
537 | ||
538 | if (length > 16) | |
539 | { position += length; | |
540 | *lineptr->run_pos++ = position; | |
541 | ||
542 | if (lineptr->mask != BIT_MASK) { /* fill current byte */ | |
543 | if (xcolour == WHITE) | |
544 | do { | |
545 | clr_bit (lineptr); | |
546 | length--; | |
547 | } while (lineptr->mask != BIT_MASK); | |
548 | ||
549 | else | |
550 | do { | |
551 | set_bit (lineptr); | |
552 | length--; | |
553 | } while (lineptr->mask != BIT_MASK); | |
554 | } | |
555 | ||
556 | /* write out the bytes */ | |
557 | if (xcolour == WHITE) | |
558 | for (i=0; i<length/8; i++) | |
559 | *lineptr->dbuf++ = 0; | |
560 | else | |
561 | for (i=0; i<length/8; i++) | |
562 | *lineptr->dbuf++ = 0xff; | |
563 | ||
564 | ||
565 | /* put the last few bits into the next byte */ | |
566 | if (xcolour == WHITE) | |
567 | for (i=0; i<length%8; i++) | |
568 | clr_bit (lineptr); | |
569 | else | |
570 | for (i=0; i<length%8; i++) | |
571 | set_bit (lineptr); | |
572 | } | |
573 | else | |
574 | { /* length < 16 - can't optimise, so deal with bits */ | |
575 | ||
576 | if (xcolour == WHITE) { | |
577 | for (i=0; i<length; i++) clr_bit (lineptr); | |
578 | position += length; | |
579 | *lineptr->run_pos++ = position; | |
580 | } else { | |
581 | for (i=0; i<length; i++) | |
582 | set_bit (lineptr); | |
583 | position += length; | |
584 | *lineptr->run_pos++ = position; | |
585 | } | |
586 | ||
587 | } | |
588 | ||
589 | } | |
590 | ||
591 | /* ROUTINE: set_doutput; | |
592 | /* | |
593 | /* SYNOPSIS: Initialises the output buffers | |
594 | */ | |
595 | ||
596 | set_doutput (lineptr) | |
597 | bit_string * lineptr; | |
598 | { | |
599 | lineptr->dbuf = lineptr->dbuf_top; | |
600 | lineptr->mask = BIT_MASK; | |
601 | } | |
602 | ||
603 | ||
604 | ||
605 | ||
606 | /* ROUTINE: flush_doutput; | |
607 | /* | |
608 | /* SYNOPSIS: flush the output buffer; | |
609 | */ | |
610 | ||
611 | flush_doutput (lineptr) | |
612 | bit_string * lineptr; | |
613 | { | |
614 | int count = 0; | |
615 | ||
616 | while ( lineptr->mask != BIT_MASK ) { | |
617 | clr_bit (lineptr); | |
618 | count++; | |
619 | } | |
620 | photo_white (count); | |
621 | } | |
622 | ||
623 | ||
624 | ||
625 | /* ROUTINE: set_dinput; | |
626 | /* | |
627 | /* SYNOPSIS: Initialises the input buffers | |
628 | */ | |
629 | ||
630 | set_dinput (lineptr, length) | |
631 | bit_string * lineptr; | |
632 | int length; | |
633 | { | |
634 | bit_string temp; | |
635 | int i; | |
636 | ||
637 | lineptr->dbuf = lineptr->dbuf_top; | |
638 | ||
639 | if (length == 0) { | |
640 | /* check id + skip length */ | |
641 | if ( *lineptr->dbuf++ != 0x03 ) { | |
642 | (void) fprintf (stderr,"PHOTO: Not a g3fax bit map"); | |
643 | return (-1); | |
644 | } | |
645 | ||
646 | if ((length = piclen (lineptr->dbuf_top)) == -1) | |
647 | return (-1); | |
648 | } | |
649 | ||
650 | while ((lineptr->pos = *lineptr->dbuf++) != 0x00) | |
651 | ; /* no op */ | |
652 | ||
653 | lineptr->mask = BIT_MASK; | |
654 | ||
655 | return (0); | |
656 | } | |
657 | ||
658 | piclen (s1) | |
659 | char * s1; | |
660 | { | |
661 | int length=0,cnt,i; | |
662 | char * temp; | |
663 | ||
664 | if (*s1 == 0x03) { | |
665 | /* we have a coded picture */ | |
666 | ||
667 | temp = s1; | |
668 | temp++; | |
669 | cnt = *temp++ & 0x7f; /*assume len > 127 for now */ | |
670 | for (i=0; i<cnt; i++) | |
671 | length = (length << 8) | (*temp++ & 0xff) ; | |
672 | ||
673 | length += 2 + cnt; | |
674 | return (length); | |
675 | ||
676 | } else { | |
677 | (void) fprintf (stderr,"PHOTO: length error"); | |
678 | return (-1); | |
679 | } | |
680 | ||
681 | } | |
682 |