home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / mandsteg.zip / gif_comp.c < prev    next >
C/C++ Source or Header  |  1994-03-12  |  5KB  |  266 lines

  1.  
  2. /*
  3.  * gif_compress.c : (C) Copyright 1994 Henry Hastur
  4.  *
  5.  * This program is copyright Henry Hastur 1994, but may be freely distributed,
  6.  * modified, incorporated into other programs and used, as long as the
  7.  * copyright stays attached and you obey any relevant import or export
  8.  * restrictions on the code. No warranty is offered, and no responsibility
  9.  * is taken for any damage use of this program may cause. In other words,
  10.  * do what you want with it, but don't expect me to pay up if anything
  11.  * unexpected goes wrong - you're using it at your own risk...
  12.  */
  13.  
  14. #include <stdio.h>
  15.  
  16. #include "ext.h"
  17. #include "gif.h"
  18.  
  19. typedef struct {
  20.  
  21.     word    pred;
  22.     byte    code;
  23.     word    next;
  24.     
  25. } ENTRY;
  26.  
  27. #define INIT_CODE_SIZE  9
  28. #define BAD_CODE        0x4000
  29. #define FIRST_CODE      0x4fff
  30. #define CLEAR_CODE      256
  31. #define EOF_CODE        257
  32. #define HASH_SIZE       300
  33.  
  34. static  char    gif_head[] = "GIF87a";
  35. static  ENTRY   code_table[MAX_CODES];
  36. static  int16   code_size;
  37. static  byte    out_buff[256];
  38. static  lword   data_bit_offset = 0;
  39. static  lword   in_offset = 0;
  40. static  lword   in_size = 0;
  41. static  word    max_code = 0;
  42. static  word    size_max = 512;
  43. static  word    hash[HASH_SIZE];
  44.  
  45. static void write_output(f)
  46.  
  47. FILE    *f;
  48.  
  49. {
  50.     int16   i;
  51.  
  52.     fputc ((int)(data_bit_offset/8), f);
  53.  
  54.     for (i=0; i<data_bit_offset/8; i++) 
  55.         fputc (out_buff[i], f);
  56.  
  57.     out_buff[0] = out_buff[i];
  58.  
  59.     data_bit_offset %= 8;
  60. }
  61.  
  62. static void output_code(c,f)
  63.  
  64. word    c;
  65. FILE    *f;
  66.  
  67. {
  68.     int     data_byte_offset;
  69.     lword   code;
  70.  
  71.     code = c;
  72.     code <<= (data_bit_offset%8);
  73.  
  74.     data_byte_offset = data_bit_offset/8;
  75.  
  76.     out_buff[data_byte_offset++]|=(code&0xff);
  77.     out_buff[data_byte_offset++]=((code>>8)&0xff);
  78.     out_buff[data_byte_offset++]=((code>>16)&0xff);
  79.  
  80.     data_bit_offset += code_size;
  81.  
  82.     if (data_byte_offset > 250)
  83.         write_output (f);
  84. }
  85.  
  86. static do_clear()
  87.  
  88. {
  89.     int     i;
  90.  
  91.     for (i=0; i<256; i++) {
  92.         code_table[i].pred = FIRST_CODE;
  93.         code_table[i].code = i;
  94.         code_table[i].next = BAD_CODE;
  95.     }
  96.  
  97.     code_table[CLEAR_CODE].pred = BAD_CODE;
  98.     code_table[EOF_CODE].pred = BAD_CODE;
  99.  
  100.     for (i=0; i<HASH_SIZE; i++)
  101.         hash[i] = BAD_CODE;
  102.  
  103.     code_size = INIT_CODE_SIZE;
  104.     max_code = EOF_CODE+1;
  105.     size_max = 512;
  106. }
  107.  
  108. static word hash_val(p,c)
  109.  
  110. word    p;
  111. byte    c;
  112.  
  113. {
  114.     return ((p+c) % HASH_SIZE);
  115. }
  116.  
  117. static file_word(w,fp)
  118.  
  119. word    w;
  120. FILE    *fp;
  121.  
  122. {
  123.     fputc (w&0xff, fp);
  124.     fputc ((((int)(w&0xff00))>>8), fp);
  125. }
  126.  
  127. void    save_gif_image(width,height,depth,d,gif_name,r,g,b)
  128.  
  129. int32    width;
  130. int32    height;
  131. int     depth;
  132. byte    *d,*r,*g,*b;
  133. char    *gif_name;
  134.  
  135. {
  136.     int16   i,c;
  137.     int16   code;
  138.     word    current;
  139.     FILE    *gif_file;
  140.  
  141.     if (gif_name)
  142.         gif_file=fopen(gif_name,"wb");
  143.     else
  144.         gif_file = stdout;
  145.  
  146.     if (!gif_file) {
  147.         fprintf(stderr,"Cannot open file %s\n",gif_name);
  148.         return;
  149.     }
  150.  
  151.     memset(hash, 0, sizeof(hash));
  152.     memset(out_buff, 0, sizeof(out_buff));
  153.  
  154.     data_bit_offset = 0;
  155.  
  156.     /* Write 'magic string' to gif file */
  157.  
  158.     fwrite (gif_head, 6, 1, gif_file);
  159.  
  160.     /* Write header */
  161.  
  162.     file_word((word)width, gif_file);
  163.     file_word((word)height, gif_file);
  164.     fputc(0x80+0x70+8-1, gif_file);
  165.     fputc(0, gif_file);
  166.     fputc(0, gif_file);
  167.  
  168.     for (i=0;i<256;i++) {
  169.         fputc(r[i], gif_file);
  170.         fputc(g[i], gif_file);
  171.         fputc(b[i], gif_file);
  172.     }
  173.  
  174.     fputc(0x2C, gif_file);
  175.     file_word(0, gif_file);
  176.     file_word(0, gif_file);
  177.     file_word((word)width, gif_file);
  178.     file_word((word)height, gif_file);
  179.     
  180.     fputc(0, gif_file);
  181.     fputc(INIT_CODE_SIZE-1, gif_file);
  182.  
  183.     /* Header finished */
  184.  
  185.     do_clear ();
  186.     output_code (CLEAR_CODE, gif_file);
  187.  
  188.     current=FIRST_CODE;
  189.  
  190.     in_size = (width*height);
  191.     in_offset = 0;
  192.  
  193.     do {
  194.         if (in_offset < in_size) {
  195. #ifdef LOW_MEM
  196.             code = calc_pixel (in_offset++);
  197. #else
  198.             code = d[in_offset++];
  199. #endif
  200.             if (current == FIRST_CODE)
  201.                 current = code;
  202.             else {
  203.                 word new;
  204.                 word hash_no;
  205.                 word prev;
  206.  
  207.                 hash_no = hash_val(current,code);
  208.                 new = hash[hash_no];
  209.                 prev = BAD_CODE;
  210.  
  211.                 while(new < max_code) {
  212.                     if (code_table[new].pred==current&&
  213.                         code_table[new].code==code) 
  214.                         break;
  215.                     prev=new;
  216.                     new=code_table[new].next;
  217.                 }
  218.  
  219.                 if (new<max_code) {
  220.                     current=new;
  221.                 }
  222.                 else {
  223.                     output_code(current,gif_file);
  224.  
  225.                     code_table[max_code].pred=current;
  226.                     code_table[max_code].code=code;
  227.                     code_table[max_code].next=BAD_CODE;
  228.  
  229.                     if (hash[hash_no]==BAD_CODE) {
  230.                         hash[hash_no]=max_code;
  231.                     }
  232.                     else {
  233.                         if (prev!=BAD_CODE)
  234.                             code_table[prev].next=
  235.                                 max_code;
  236.                     }
  237.  
  238.                     max_code++;
  239.                     if (max_code>size_max) {
  240.                         size_max*=2;
  241.                         code_size++;
  242.                     }
  243.                     if (max_code >= (word)(MAX_CODES - 2)) {
  244.                         output_code(CLEAR_CODE,
  245.                             gif_file);
  246.                         do_clear();
  247.                     }
  248.                     current=code;
  249.                 }
  250.             }
  251.         }
  252.  
  253.     } while(in_offset<in_size);
  254.  
  255.     output_code(current,gif_file);
  256.     output_code(EOF_CODE,gif_file);
  257.  
  258.     data_bit_offset += 8;
  259.  
  260.     write_output(gif_file);
  261.  
  262.     putc(0, gif_file);
  263.     putc(0x3B, gif_file);
  264.     fclose(gif_file);
  265. }
  266.