|
|
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.