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