|
|
1.1 root 1: /* encode.c - implement encoding routines */
2:
3: #ifndef lint
4: static char *rcsid = "$Header: /f/osi/others/quipu/photo/RCS/encode.c,v 7.1 90/07/09 14:40:25 mrose Exp $";
5: #endif
6:
7: /*
8: * $Header: /f/osi/others/quipu/photo/RCS/encode.c,v 7.1 90/07/09 14:40:25 mrose Exp $
9: *
10: *
11: * $Log: encode.c,v $
12: * Revision 7.1 90/07/09 14:40:25 mrose
13: * sync
14: *
15: * Revision 7.0 89/11/23 22:01:39 mrose
16: * Release 6.0
17: *
18: */
19:
20: /*
21: * NOTICE
22: *
23: * Acquisition, use, and distribution of this module and related
24: * materials are subject to the restrictions of a license agreement.
25: * Consult the Preface in the User's Manual for the full terms of
26: * this agreement.
27: *
28: */
29:
30:
31:
32: #include <stdio.h>
33: #include "quipu/photo.h"
34:
35: extern int PIC_LINESIZE,STOP,NUMLINES;
36:
37: int a0, a1, b1, b2; /* markers */
38: int optlen;
39:
40: char * malloc();
41:
42:
43: /* ROUTINE: encode_t4
44: /*
45: /* SYNOPSIS: Implements CCITT recommendation T.4.
46: /* This recomendation is concerned with compressing of bit maps.
47: /*
48: /* DESCRIPTION:
49: /* This routine sets up the data buffers, then calls routines
50: /* to encode one line of the bit map. A line can be encoded either one
51: /* dimensionally or two dimensionally depending upon the 'k parameter'.
52: /* When a line is encode two dimensionally, the line before is used as a
53: /* reference. For each line encoded a record of where the run changes occur
54: /* are kept. this is the used as the reference.
55: /*
56: */
57:
58:
59: char * encode_t4 (k_param,inbuf, eolnskip)
60: int k_param;
61: char * inbuf;
62: int eolnskip;
63:
64: {
65: bit_string ref_line; /* Reference line */
66: bit_string t4_line; /* Output encoded line */
67: bit_string code_line; /* Line we are codeing */
68:
69: short i,j; /* Loop variable */
70: int run_buf [LINEBUF], run_buf2 [LINEBUF];
71:
72:
73: ref_line.run_top = run_buf;
74: code_line.run_top = run_buf2;
75:
76: code_line.dbuf_top = inbuf;
77: t4_line.dbuf_top = malloc (PIC_LINESIZE * NUMLINES);
78:
79: set_input (&code_line);
80: set_output (&t4_line);
81:
82: /* Repeat this loop once for every input line expected */
83: for (i=0; i< NUMLINES; i++) {
84:
85: put_eoln (&t4_line); /* eoln marker before each new data line */
86: if (code_line.run_top == run_buf) { /*swap buffers*/
87: ref_line.run_top = run_buf;
88: code_line.run_top = run_buf2;
89: } else {
90: ref_line.run_top = run_buf2;
91: code_line.run_top = run_buf;
92: }
93:
94: /* reset pointers */
95: code_line.run_pos = code_line.run_top;
96: ref_line.run_pos = ref_line.run_top;
97:
98: /* fill buffer for coding line */
99:
100: get_runs (&code_line);
101: code_line.run_pos = code_line.run_top;
102:
103: if (i % k_param == 0) {
104: set_bit (&t4_line); /* tag bit, 1-d line follows */
105: code_one (&code_line,&t4_line);
106:
107: } else {
108: clr_bit (&t4_line); /* tag bit, 2-d line follows */
109: code_two (&ref_line,&code_line,&t4_line);
110: }
111: /* skip any extra eoln bit in orig data */
112: for (j=0;j<eolnskip;j++)
113: get_bit (&code_line);
114:
115: }
116: /* now finish as per X409 */
117: put_eoln (&t4_line);
118: set_bit (&t4_line);
119: put_eoln (&t4_line);
120: set_bit (&t4_line);
121: put_eoln (&t4_line);
122: set_bit (&t4_line);
123: put_eoln (&t4_line);
124: set_bit (&t4_line);
125: put_eoln (&t4_line);
126: set_bit (&t4_line);
127: put_eoln (&t4_line);
128: set_bit (&t4_line);
129:
130: /* flush buffers, write length */
131: flush_output (&t4_line);
132: return (t4_line.dbuf_top);
133: }
134:
135:
136:
137: /* ROUTINE: code_one
138: /*
139: /* SYNOPSIS: codes one line of a bit map into t4
140: /*
141: /* DESCRIPTION:
142: /* To encode a line one dimensionally, bits are read in until
143: /* a change is noticed, when this happens, the run_length code for the number
144: /* of bits read in is found, and written to the output file.
145: /* A run_length code may consist of two parts if the run is large, a make up
146: /* and a terminal code.
147: */
148:
149: code_one (lineptr,t4_lineptr)
150:
151: bit_string * lineptr; /* input line */
152: bit_string * t4_lineptr; /* output line */
153:
154: {
155: char colour = WHITE; /* the colour of the current bit */
156: full_code code; /* the code for the characters run_length */
157: int old_pos = 1; /* the number of bits of the same colur read in */
158:
159:
160: do {
161: /* get code for next run = pos of current change - pos of last change */
162: code = get_code (*++lineptr->run_pos - old_pos,colour);
163:
164: if (code.make.length != 0)
165: put_code (t4_lineptr,code.make); /* the make code */
166: put_code (t4_lineptr, code.term); /* the terminal code */
167: colour = 1 - colour;
168: old_pos = *lineptr->run_pos;
169:
170: } while (*lineptr->run_pos <= PIC_LINESIZE);
171: }
172:
173:
174:
175:
176:
177:
178: /* ROUTINE: code_two
179: /*
180: /* SYNOPSIS: Codes one line of a bit map two dimensionally as
181: /* described by CCITT T.4.
182: /*
183: /* DESCRIPTION: Two lines are compared by looking at the list of run changes.
184: /* In order to do this, this list has to be created for the line we are about
185: /* to encode. The encoding procedure then follows the flow chart in the CCITT
186: /* recommendation.
187: /* That is summarised as follows, find the positions a0,a1,b1,b2, the compare
188: /* the to see which mode is required. The positions of a1,b1,b2 are found from
189: /* the run change list. a0 is known in advance.
190: */
191:
192: code_two (ref_lineptr,code_lineptr,t4_lineptr)
193:
194: bit_string * ref_lineptr; /* reference line */
195: bit_string * code_lineptr; /* line to encode */
196: bit_string * t4_lineptr; /* output line */
197:
198: {
199: char colour = WHITE;
200: char ref_colour = WHITE;
201:
202: a0 = 0;
203: code_lineptr->run_pos = code_lineptr->run_top;
204:
205: do {
206: /* move all pointers to be level with a0 to start keeping colour */
207: /* variables up to date. Move past a0, then move back, this ensures*/
208: /* we are at the change immediately before a0 */
209:
210: if ( *(code_lineptr->run_pos) > a0)
211: while ( *(--code_lineptr->run_pos) > a0 )
212: ;
213:
214: if ( *ref_lineptr->run_pos < a0 )
215: do
216: ref_colour = 1 - ref_colour;
217: while (*++ref_lineptr->run_pos < a0) ;
218:
219: if ( *(ref_lineptr->run_pos) > a0)
220: do
221: ref_colour = 1-ref_colour;
222: while ( *(--ref_lineptr->run_pos) > a0 ) ;
223:
224: /* find a1 */
225: a1 = *(++code_lineptr->run_pos);
226: if (a1 >= STOP)
227: code_lineptr->run_pos--;
228:
229: if (ref_colour != colour) {
230: ref_lineptr->run_pos++;
231: ref_colour = 1 - ref_colour;
232: }
233:
234: /* find b1 */
235: b1 = *(++ref_lineptr->run_pos);
236: if (b1 >= STOP) {
237: ref_lineptr->run_pos--;
238: ref_colour = 1 - ref_colour;
239: b2 = STOP;
240:
241: } else {
242: /* find b2 */
243: b2 = *(++ref_lineptr->run_pos);
244: if (b2 >= STOP) {
245: ref_lineptr->run_pos--;
246: ref_colour = 1 - ref_colour;
247: }
248: }
249:
250: /* select mode and code it */
251: if (a1 >= STOP) {
252: a0=STOP; /* to stop loop */
253: }
254: else {
255: if (a1 > b2)
256: pass_mode (t4_lineptr);
257:
258: else {
259: if (abs (a1-b1) <= 3) {
260: vertical_mode (t4_lineptr);
261: colour = 1 - colour;
262:
263: } else
264: horizontal_mode (code_lineptr,t4_lineptr,colour);
265: }
266: }
267: } while (a0 < STOP );
268:
269: }
270:
271:
272: /* ROUTINE: Pass_mode
273: /*
274: /* SYNOPSIS: Encodes pass_mode
275: /*
276: /* DESCRIPTION: When pass mode is detected, the pass mode code is written to
277: /* the output, and a0 is moved to underneath b2.
278: */
279:
280: pass_mode (t4_lineptr)
281: bit_string * t4_lineptr;
282:
283: {
284: static code_word code = {4,0x0200};
285: put_code (t4_lineptr,code);
286: a0 = b2;
287: }
288:
289:
290: /* ROUTINE: Vertical_mode
291: /*
292: /* SYNOPSIS: Encodes vertical mode.
293: /*
294: /* DESCRIPTION: Vertical mode is encoded by writing a particualr code
295: /* depending on the offset between a1 and b1.
296: /* a0 is moved to a1
297: */
298:
299: vertical_mode (t4_lineptr)
300:
301: bit_string * t4_lineptr;
302:
303: {
304: static code_word code [7] = {
305: {7,0x080 }, /* -3 */
306: {6,0x100 }, /* -2 */
307: {3,0x800 }, /* -1 */
308: {1,0x1000 }, /* 0 */
309: {3,0xc00 }, /* 1 */
310: {6,0x180 }, /* 2 */
311: {7,0xc0 }, /* 3 */
312: };
313: put_code (t4_lineptr, code [a1-b1+3]);
314:
315: a0 = a1;
316: }
317:
318:
319:
320:
321: /* ROUTINE: Horizontal_mode
322: /*
323: /* SYNOPSIS: Encodes horizontal mode
324: /*
325: /* DESCRIPTION: When horizontal mode is detected no further compaction can
326: /* can take place, so the next two run lengths are written to the output.
327: /* a0 is moved to after these runs.
328: */
329:
330: horizontal_mode (code_lineptr,t4_lineptr,colour)
331:
332: bit_string * t4_lineptr;
333: bit_string * code_lineptr;
334: char colour;
335:
336: {
337: int a2;
338: static code_word h_code = {3,0x0400};
339: full_code code;
340:
341: if (a0 == 0) /* special case at start of line */
342: a0 = 1;
343:
344: /* find a2 */
345: a2 = *(++code_lineptr->run_pos);
346: if (a2 >= STOP)
347: code_lineptr->run_pos--;
348:
349: put_code (t4_lineptr,h_code); /* code for horiz mode */
350:
351: /* get & put first run */
352: code = get_code (a1-a0,colour);
353: if (code.make.length != 0)
354: put_code (t4_lineptr,code.make);
355: put_code (t4_lineptr,code.term);
356:
357: /* get & put second run */
358: code = get_code (a2-a1,1-colour);
359: if (code.make.length != 0)
360: put_code (t4_lineptr,code.make);
361: put_code (t4_lineptr,code.term);
362:
363: a0=a2;
364: }
365:
366:
367: /* ROUTINE: Put_code () */
368: /* */
369: /* SYNOPSIS: appends the code word to the 'line'. */
370: /* */
371:
372: put_code (lineptr,code)
373:
374: bit_string * lineptr;
375: code_word code;
376: {
377:
378: int i;
379: short mask;
380:
381: mask = MSB_MASK; /* set mask to first bit of pattern */
382:
383: for (i=0; i< code.length ; i++) {
384: if ((code.pattern & mask) == WHITE)
385: clr_bit (lineptr);
386: else
387: set_bit (lineptr);
388:
389: mask >>= 1;
390: }
391: }
392:
393:
394:
395:
396: /* ROUTINE: put_eoln */
397: /* */
398: /* SYNOPSIS: Puts an end of line marker at the end of a t4 line. */
399: /* An end of line (eoln) marker is 11 (or more) zero's */
400: /* followed by a 1. */
401:
402: put_eoln (lineptr)
403:
404: bit_string * lineptr;
405:
406: {
407: int i;
408:
409: for (i=0 ; i< 11; i++)
410: clr_bit (lineptr);
411:
412: set_bit (lineptr);
413:
414: }
415:
416:
417:
418: /* ROUTINE: get_runs
419: *
420: * SYNOPSIS: set the runs change buffer fo the next input line
421: *
422: * DESCRIPTION: To optimise the input process, sequences of all 1's or 0's
423: * - the most likely combinations are looked for as special cases, if not
424: * found the runs are counted as bits.
425: *
426: */
427:
428: get_runs (lineptr)
429: bit_string * lineptr;
430:
431: {
432: register i,j;
433: char colour = WHITE;
434:
435: *lineptr->run_pos++ = 0;
436:
437: for (i=1; i <= PIC_LINESIZE; i++)
438: if (get_bit (lineptr) != colour) {
439: *(lineptr->run_pos++) = i;
440: colour = 1 - colour;
441: }
442:
443: *lineptr->run_pos++ = STOP;
444: *lineptr->run_pos = STOP;
445:
446: }
447:
448: /* ROUTINE: set_output;
449: *
450: * SYNOPSIS: Initialises the output buffers, writes the ENODE id, and
451: * leaves room for the length (to be filled in later);
452: */
453:
454: set_output (lineptr)
455: bit_string * lineptr;
456: {
457: lineptr->dbuf_top += 5; /* leave room for length and id char*/
458: lineptr->dbuf = lineptr->dbuf_top;
459:
460: lineptr->mask = BIT_MASK;
461: }
462:
463:
464:
465: /* ROUTINE: flush_output;
466: /*
467: /* SYNOPSIS: flush the output buffer, and set file length;
468: */
469:
470: flush_output (lineptr)
471: bit_string * lineptr;
472: {
473: long length, len;
474: int count = 0,i;
475:
476: if ( lineptr->mask != BIT_MASK ) /* writes last char if necessary */
477: lineptr->dbuf++;
478:
479: /* find and write length */
480: len = length = lineptr->dbuf - lineptr->dbuf_top;
481:
482: if (length <= 127) { /* short form length */
483: *(--lineptr->dbuf_top) = length;
484: *(--lineptr->dbuf_top) = 0x03; /* bit map id */
485: optlen = length + 2;
486: }
487: else {
488: /* see how many bytes needed for length */
489: while (len != 0)
490: {
491: len >>= 8;
492: count++;
493: }
494:
495: /* go back and write this info */
496:
497:
498: for (i=0;i<count;i++)
499: *(--lineptr->dbuf_top) = (length >> (8 * i));
500:
501: *(--lineptr->dbuf_top) = 0x80 + count; /* length marker*/
502: *(--lineptr->dbuf_top) = 0x03; /* bit map id */
503:
504: optlen = length + count + 1;
505: }
506: }
507:
508:
509: /* ROUTINE: set_input;
510: /*
511: /* SYNOPSIS: Initialises the input buffers
512: */
513:
514: set_input (lineptr)
515: bit_string * lineptr;
516: {
517: lineptr->mask = BIT_MASK;
518: lineptr->dbuf = lineptr->dbuf_top;
519: lineptr->pos = *lineptr->dbuf++;
520: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.