Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / contrib / isode / others / quipu / photo / encode.c
CommitLineData
11492ebf
C
1/* encode.c - implement encoding routines */
2
3#ifndef lint
4static char *rcsid = "$Header: /f/osi/others/quipu/photo/RCS/encode.c,v 7.4 91/02/22 09:29:14 mrose Interim $";
5#endif
6
7/*
8 * $Header: /f/osi/others/quipu/photo/RCS/encode.c,v 7.4 91/02/22 09:29:14 mrose Interim $
9 *
10 *
11 * $Log: encode.c,v $
12 * Revision 7.4 91/02/22 09:29:14 mrose
13 * Interim 6.8
14 *
15 * Revision 1.6 91/01/08 21:56:34 kej
16 * Correct bug in flush_output; it wasn't writing the last incomplete
17 * byte to the output stream.
18 *
19 * Revision 1.5 91/01/07 22:20:34 kej
20 * Fully specify the BIT STRING which contains the G3NonBasicParams.
21 *
22 * Revision 1.4 91/01/07 23:50:25 kej
23 * Support fax images encoded as a SEQUENCE which contains a SET followed by
24 * a SEQUENCE of BIT STRING.
25 *
26 * Revision 1.3 91/01/05 23:31:07 kej
27 * Implement support for specification of all G3-Fax nonbasic parameters.
28 *
29 * Revision 1.2 91/01/05 00:31:34 kej
30 * ISODE claimed to be creating fax images as ASN.1-encoded BIT STRING's.
31 * However, the encoding was incorrect. This revision corrects the
32 * problem, implements 1-d and 2-d encoding of fax images, and it provides
33 * a backward compatible mechanism for reading the old, broken images.
34 *
35 * Revision 1.1 91/01/02 21:35:28 kej
36 * Initial revision
37 *
38 * Revision 7.1 90/07/09 14:40:25 mrose
39 * sync
40 *
41 * Revision 7.0 89/11/23 22:01:39 mrose
42 * Release 6.0
43 *
44 */
45
46/*
47 * NOTICE
48 *
49 * Acquisition, use, and distribution of this module and related
50 * materials are subject to the restrictions of a license agreement.
51 * Consult the Preface in the User's Manual for the full terms of
52 * this agreement.
53 *
54 */
55
56
57
58#include <stdio.h>
59#include "quipu/photo.h"
60
61extern int PIC_LINESIZE,STOP,NUMLINES;
62
63int a0, a1, b1, b2; /* markers */
64int optlen;
65
66char * malloc();
67
68/*
69 * G3-Fax nonbasic parameters.
70 */
71
72int twoDimensional = 0;
73int fineResolution = 1;
74int unlimitedLength = 0;
75int b4Length = 0;
76int a3Width = 0;
77int b4Width = 0;
78int uncompressed = 0;
79int standardwidth = 0;
80int forcesize = 0;
81/* encoding format options */
82
83int nopreamble = 0;
84int oldformat = 0;
85
86
87/* ROUTINE: encode_t4
88/*
89/* SYNOPSIS: Implements CCITT recommendation T.4.
90/* This recomendation is concerned with compressing of bit maps.
91/*
92/* DESCRIPTION:
93/* This routine sets up the data buffers, then calls routines
94/* to encode one line of the bit map. A line can be encoded either one
95/* dimensionally or two dimensionally depending upon the 'k parameter'.
96/*
97/* When a line is encoded two dimensionally, the line before is used as a
98/* reference. For each line encoded, a record of where the run changes occur
99/* are kept. This is the used as the reference.
100/*
101*/
102
103
104char * encode_t4 (k_param, inbuf, eolnskip)
105int k_param;
106char * inbuf;
107int eolnskip;
108
109{
110 bit_string ref_line; /* Reference line */
111 bit_string t4_line; /* Output encoded line */
112 bit_string code_line; /* Line we are codeing */
113
114 short i,j; /* Loop variable */
115 int run_buf [LINEBUF], run_buf2 [LINEBUF];
116
117 if (a3Width)
118 forcesize = 2432;
119 if (b4Width)
120 forcesize = 2048;
121 if (standardwidth)
122 forcesize = 1728;
123
124 ref_line.run_top = run_buf;
125 code_line.run_top = run_buf2;
126
127 code_line.dbuf_top = inbuf;
128 t4_line.dbuf_top = malloc ((PIC_LINESIZE * NUMLINES) + 28);
129
130 set_input (&code_line);
131 set_output (&t4_line);
132
133 /* Repeat this loop once for every input line expected */
134
135 for (i = 0; i < NUMLINES; i++) {
136
137 if (code_line.run_top == run_buf) { /*swap buffers*/
138 ref_line.run_top = run_buf;
139 code_line.run_top = run_buf2;
140 } else {
141 ref_line.run_top = run_buf2;
142 code_line.run_top = run_buf;
143 }
144
145 /* reset pointers */
146
147 code_line.run_pos = code_line.run_top;
148 ref_line.run_pos = ref_line.run_top;
149
150 /* fill buffer for coding line */
151
152 get_runs (&code_line);
153 code_line.run_pos = code_line.run_top;
154
155 put_eoln (&t4_line);
156
157 if (k_param > 1) {
158 if (i % k_param == 0) {
159 set_bit (&t4_line); /* tag bit, 1-d line follows */
160 code_one (&code_line, &t4_line);
161 }
162 else {
163 clr_bit (&t4_line); /* tag bit, 2-d line follows */
164 code_two (&ref_line, &code_line, &t4_line);
165 }
166 }
167 else
168 code_one (&code_line, &t4_line);
169
170 /* skip any extra eoln bit in orig data */
171
172 for (j = 0; j < eolnskip; j++)
173 get_bit (&code_line);
174
175 }
176
177 /* now finish with 6 EOL's, as per T.4 */
178
179 for (i = 0; i < 5; ++i) {
180 put_eoln (&t4_line);
181 if (k_param > 1) set_bit (&t4_line);
182 }
183
184 /* flush buffers, write preamble */
185
186 flush_output (&t4_line);
187 return (t4_line.dbuf_top);
188}
189
190
191
192/* ROUTINE: code_one
193/*
194/* SYNOPSIS: codes one line of a bit map into t4
195/*
196/* DESCRIPTION:
197/* To encode a line one dimensionally, bits are read in until
198/* a change is noticed, when this happens, the run_length code for the number
199/* of bits read in is found, and written to the output file.
200/*
201/* A run_length code may consist of two parts if the run is large, a make up
202/* and a terminal code.
203*/
204
205code_one (lineptr,t4_lineptr)
206
207bit_string * lineptr; /* input line */
208bit_string * t4_lineptr; /* output line */
209
210{
211 char colour = WHITE; /* the colour of the current bit */
212 full_code code; /* the code for the characters run_length */
213 int old_pos = 1; /* the number of bits of the same colur read in */
214 int len = 0;
215 int tlen;
216
217 if (forcesize) {
218 len = (forcesize - PIC_LINESIZE)/ 2;
219 code = get_code ( len, WHITE);
220 if (code.make.length != 0)
221 put_code (t4_lineptr,code.make); /* the make code */
222 put_code (t4_lineptr, code.term); /* the terminal code */
223 code = get_code (0,BLACK);
224 put_code (t4_lineptr, code.term);
225 }
226
227 do {
228
229 /* get code for next run = pos of current change - pos of last change */
230 tlen = *++lineptr->run_pos - old_pos;
231 len += tlen;
232 code = get_code (tlen,colour);
233
234 if (code.make.length != 0)
235 put_code (t4_lineptr,code.make); /* the make code */
236 put_code (t4_lineptr, code.term); /* the terminal code */
237 colour = 1 - colour;
238 old_pos = *lineptr->run_pos;
239
240 } while (*lineptr->run_pos <= PIC_LINESIZE);
241
242 if (forcesize) {
243 if (colour == BLACK) {
244 code = get_code (0,colour);
245 put_code (t4_lineptr, code.term);
246 }
247 colour = 1 - colour;
248
249 code = get_code ( forcesize - len, colour);
250 if (code.make.length != 0)
251 put_code (t4_lineptr,code.make); /* the make code */
252 put_code (t4_lineptr, code.term); /* the terminal code */
253 }
254}
255
256
257
258
259
260
261/* ROUTINE: code_two
262/*
263/* SYNOPSIS: Codes one line of a bit map two dimensionally as
264/* described by CCITT T.4.
265/*
266/* DESCRIPTION: Two lines are compared by looking at the list of run changes.
267/* In order to do this, this list has to be created for the line we are about
268/* to encode. The encoding procedure then follows the flow chart in the CCITT
269/* recommendation. This is summarised as follows:
270/*
271/* 1. Find the positions a0, a1, b1, b2.
272/* 2. Compare to see which mode is required.
273/*
274/* The positions of a1, b1, b2 are found from the run change list. a0 is known
275/* in advance.
276*/
277
278code_two (ref_lineptr,code_lineptr,t4_lineptr)
279
280bit_string * ref_lineptr; /* reference line */
281bit_string * code_lineptr; /* line to encode */
282bit_string * t4_lineptr; /* output line */
283
284{
285 char colour = WHITE;
286 char ref_colour = WHITE;
287
288 a0 = 0;
289 code_lineptr->run_pos = code_lineptr->run_top;
290
291 do {
292
293 /* find a1 */
294
295 while (*code_lineptr->run_pos > a0)
296 --code_lineptr->run_pos;
297
298 while (*code_lineptr->run_pos <= a0 && *code_lineptr->run_pos < STOP)
299 ++code_lineptr->run_pos;
300
301 a1 = *code_lineptr->run_pos;
302
303 /* find b1 and b2 */
304
305 while (*ref_lineptr->run_pos > a0) {
306 ref_colour = 1 - ref_colour;
307 --ref_lineptr->run_pos;
308 }
309
310 while (*ref_lineptr->run_pos <= a0 && *ref_lineptr->run_pos < STOP ) {
311 ref_colour = 1 - ref_colour;
312 ++ref_lineptr->run_pos;
313 }
314
315 if (ref_colour == colour && *ref_lineptr->run_pos < STOP) {
316 ref_lineptr->run_pos++;
317 ref_colour = 1 - ref_colour;
318 }
319
320 b1 = *ref_lineptr->run_pos;
321 if (b1 >= STOP)
322 b2 = STOP;
323 else
324 b2 = *(ref_lineptr->run_pos + 1);
325
326 /* select mode and code it */
327
328 if (a1 > b2) {
329 pass_mode (t4_lineptr);
330 }
331 else if (abs (a1 - b1) <= 3) {
332 vertical_mode (t4_lineptr);
333 colour = 1 - colour;
334 }
335 else
336 horizontal_mode (code_lineptr,t4_lineptr,colour);
337
338 } while (a0 < STOP);
339}
340
341
342/* ROUTINE: Pass_mode
343/*
344/* SYNOPSIS: Encodes pass_mode
345/*
346/* DESCRIPTION: When pass mode is detected, the pass mode code is written to
347/* the output, and a0 is moved to underneath b2.
348*/
349
350pass_mode (t4_lineptr)
351bit_string * t4_lineptr;
352
353{
354 static code_word code = {4,0x0200};
355
356 put_code (t4_lineptr,code);
357 a0 = b2;
358}
359
360
361/* ROUTINE: Vertical_mode
362/*
363/* SYNOPSIS: Encodes vertical mode.
364/*
365/* DESCRIPTION: Vertical mode is encoded by writing a particualr code
366/* depending on the offset between a1 and b1.
367/* a0 is moved to a1
368*/
369
370vertical_mode (t4_lineptr)
371
372bit_string * t4_lineptr;
373
374{
375 static code_word code [7] = {
376 {7,0x080 }, /* -3 */
377 {6,0x100 }, /* -2 */
378 {3,0x800 }, /* -1 */
379 {1,0x1000 }, /* 0 */
380 {3,0xc00 }, /* 1 */
381 {6,0x180 }, /* 2 */
382 {7,0xc0 }, /* 3 */
383 };
384
385 put_code (t4_lineptr, code[a1 - b1 + 3]);
386 a0 = a1;
387}
388
389
390
391
392/* ROUTINE: Horizontal_mode
393/*
394/* SYNOPSIS: Encodes horizontal mode
395/*
396/* DESCRIPTION: When horizontal mode is detected no further compaction can
397/* can take place, so the next two run lengths are written to the output.
398/* a0 is moved to after these runs.
399*/
400
401horizontal_mode (code_lineptr,t4_lineptr,colour)
402
403bit_string * t4_lineptr;
404bit_string * code_lineptr;
405char colour;
406
407{
408 int a2;
409 static code_word h_code = {3,0x0400};
410 full_code code;
411
412 if (a0 == 0) /* special case at start of line */
413 a0 = 1;
414
415 /* find a2 */
416
417 a2 = *(++code_lineptr->run_pos);
418 if (a2 >= STOP)
419 code_lineptr->run_pos--;
420
421 put_code (t4_lineptr, h_code); /* code for horiz mode */
422
423 /* get & put first run */
424
425 code = get_code (a1 - a0, colour);
426 if (code.make.length != 0)
427 put_code (t4_lineptr, code.make);
428 put_code (t4_lineptr, code.term);
429
430 /* get & put second run */
431
432 code = get_code (a2 - a1, 1 - colour);
433 if (code.make.length != 0)
434 put_code (t4_lineptr, code.make);
435 put_code (t4_lineptr, code.term);
436
437 a0 = a2;
438}
439
440
441/* ROUTINE: Put_code () */
442/* */
443/* SYNOPSIS: appends the code word to the 'line'. */
444/* */
445
446put_code (lineptr,code)
447
448bit_string * lineptr;
449code_word code;
450{
451
452 int i;
453 short mask;
454
455 mask = MSB_MASK; /* set mask to first bit of pattern */
456
457 for (i=0; i< code.length ; i++) {
458 if ((code.pattern & mask) == WHITE)
459 clr_bit (lineptr);
460 else
461 set_bit (lineptr);
462
463 mask >>= 1;
464 }
465}
466
467
468
469
470/* ROUTINE: put_eoln */
471/* */
472/* SYNOPSIS: Puts an end of line marker at the end of a t4 line. */
473/* An end of line (eoln) marker is 11 (or more) zero's */
474/* followed by a 1. */
475
476put_eoln (lineptr)
477
478bit_string * lineptr;
479
480{
481 int i;
482
483 for (i=0 ; i< 11; i++)
484 clr_bit (lineptr);
485
486 set_bit (lineptr);
487}
488
489
490
491/* ROUTINE: get_runs
492 *
493 * SYNOPSIS: set the runs change buffer fo the next input line
494 *
495 * DESCRIPTION: To optimise the input process, sequences of all 1's or 0's
496 * - the most likely combinations are looked for as special cases, if not
497 * found the runs are counted as bits.
498 *
499 */
500
501get_runs (lineptr)
502bit_string * lineptr;
503
504{
505 register i,j;
506 char colour = WHITE;
507
508 *lineptr->run_pos++ = 0;
509
510 for (i = 1; i <= PIC_LINESIZE; i++)
511 if (get_bit (lineptr) != colour) {
512 *(lineptr->run_pos++) = i;
513 colour = 1 - colour;
514 }
515
516 *lineptr->run_pos++ = STOP;
517 *lineptr->run_pos = STOP;
518}
519
520/* ROUTINE: set_output;
521 *
522 * SYNOPSIS: Initialises the output buffers, writes the ENODE id, and
523 * leaves room for the length (to be filled in later);
524*/
525
526set_output (lineptr)
527bit_string * lineptr;
528{
529 lineptr->dbuf_top += 28; /* leave room for ASN.1 preamble */
530 lineptr->dbuf = lineptr->dbuf_top;
531 lineptr->mask = BIT_MASK;
532}
533
534
535
536/* ROUTINE: flush_output;
537 *
538 * SYNOPSIS: Flush the output buffer, and set the ASN.1 preamble if
539 * allowed. The normal preamble consists of a SEQUENCE definition
540 * which wraps a SET and a SEQUENCE of BIT STRING. The SET
541 * includes G3-Fax nonbasic parameter indications (such as
542 * twoDimensional, fineResolution, etc.). Optionally, the
543 * old BIT STRING-ish preamble may be selected.
544 */
545
546flush_output (lineptr)
547bit_string * lineptr;
548{
549 long length, len;
550 int count, i;
551
552 if ( lineptr->mask != BIT_MASK ) /* writes last char if necessary */
553 *lineptr->dbuf++ = lineptr->pos;
554
555 if ( nopreamble ) {
556 optlen = lineptr->dbuf - lineptr->dbuf_top;
557 return;
558 }
559
560 /* set byte which indicates unused bits in last byte of image data */
561
562 if ( !oldformat )
563 *(--lineptr->dbuf_top) = 0x00;
564
565 /* set image length */
566
567 len = length = lineptr->dbuf - lineptr->dbuf_top;
568
569 if (length <= 127) { /* short form length */
570 *(--lineptr->dbuf_top) = length;
571 }
572 else {
573
574 /* see how many bytes needed for length */
575
576 count = 0;
577
578 while (len != 0)
579 {
580 len >>= 8;
581 count++;
582 }
583
584 /* go back and write this info */
585
586 for (i = 0; i < count; i++)
587 *(--lineptr->dbuf_top) = (length >> (8 * i));
588
589 *(--lineptr->dbuf_top) = 0x80 + count; /* length marker*/
590 }
591
592 /* set BIT STRING identifier */
593
594 *(--lineptr->dbuf_top) = 0x03;
595
596 if ( oldformat ) {
597 optlen = lineptr->dbuf - lineptr->dbuf_top;
598 return;
599 }
600
601 /* set length of BIT STRING sequence */
602
603 len = length = lineptr->dbuf - lineptr->dbuf_top;
604
605 if (length <= 127) { /* short form length */
606 *(--lineptr->dbuf_top) = length;
607 }
608 else {
609
610 /* see how many bytes needed for length */
611
612 count = 0;
613
614 while (len != 0)
615 {
616 len >>= 8;
617 count++;
618 }
619
620 /* go back and write this info */
621
622 for (i = 0; i < count; i++)
623 *(--lineptr->dbuf_top) = (length >> (8 * i));
624
625 *(--lineptr->dbuf_top) = 0x80 + count; /* length marker*/
626 }
627
628 /* set SEQUENCE identifier */
629
630 *(--lineptr->dbuf_top) = 0x30;
631
632 /* set SET which includes g3NonBasicParams */
633
634 *(--lineptr->dbuf_top) = uncompressed ? 0x02 : 0x00;
635
636 *(--lineptr->dbuf_top) = 0;
637 if (unlimitedLength) *lineptr->dbuf_top |= 0x08;
638 if (b4Length) *lineptr->dbuf_top |= 0x04;
639 if (a3Width) *lineptr->dbuf_top |= 0x02;
640 if (b4Width) *lineptr->dbuf_top |= 0x01;
641
642 *(--lineptr->dbuf_top) = 0;
643 if (twoDimensional) *lineptr->dbuf_top |= 0x80;
644 if (fineResolution) *lineptr->dbuf_top |= 0x40;
645
646 *(--lineptr->dbuf_top) = 0x00; /* first byte of BIT STRING */
647 *(--lineptr->dbuf_top) = 0x01; /* count of unused bits */
648 *(--lineptr->dbuf_top) = 5; /* BIT STRING length */
649 *(--lineptr->dbuf_top) = 0x81; /* [1] IMPLICIT G3NonBasicParams */
650 *(--lineptr->dbuf_top) = 7; /* length of SET */
651 *(--lineptr->dbuf_top) = 0x31; /* SET */
652
653 /* set length of entire sequence */
654
655 len = length = lineptr->dbuf - lineptr->dbuf_top;
656
657 if (length <= 127) { /* short form length */
658 *(--lineptr->dbuf_top) = length;
659 }
660 else {
661
662 /* see how many bytes needed for length */
663
664 count = 0;
665
666 while (len != 0)
667 {
668 len >>= 8;
669 count++;
670 }
671
672 /* go back and write this info */
673
674 for (i = 0; i < count; i++)
675 *(--lineptr->dbuf_top) = (length >> (8 * i));
676
677 *(--lineptr->dbuf_top) = 0x80 + count; /* length marker*/
678 }
679
680 /* set [3] IMPLICIT G3Fax identifier */
681
682 *(--lineptr->dbuf_top) = 0xa3;
683
684 optlen = lineptr->dbuf - lineptr->dbuf_top;
685}
686
687
688/* ROUTINE: set_input;
689/*
690/* SYNOPSIS: Initialises the input buffers
691*/
692
693set_input (lineptr)
694bit_string * lineptr;
695{
696 lineptr->mask = BIT_MASK;
697 lineptr->dbuf = lineptr->dbuf_top;
698 lineptr->pos = *lineptr->dbuf++;
699}