aboutsummaryrefslogtreecommitdiff
path: root/src/outgif.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/outgif.c')
-rw-r--r--src/outgif.c587
1 files changed, 587 insertions, 0 deletions
diff --git a/src/outgif.c b/src/outgif.c
new file mode 100644
index 00000000..4a8e9a62
--- /dev/null
+++ b/src/outgif.c
@@ -0,0 +1,587 @@
1/*
2 * Luis Figueiredo - why remake the wheel, this functions feets perfectly
3 * and the credits still here :)
4 */
5
6
7/*
8 * xvgifwr.c - handles writing of GIF files. based on flgife.c and
9 * flgifc.c from the FBM Library, by Michael Maudlin
10 *
11 * Contains:
12 * WriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
13 * comment)
14 *
15 * Note: slightly brain-damaged, in that it'll only write non-interlaced
16 * GIF files (in the interests of speed, or something)
17 *
18 */
19
20
21
22/*****************************************************************
23 * Portions of this code Copyright (C) 1989 by Michael Mauldin.
24 * Permission is granted to use this file in whole or in
25 * part for any purpose, educational, recreational or commercial,
26 * provided that this copyright notice is retained unchanged.
27 * This software is available to all free of charge by anonymous
28 * FTP and in the UUNET archives.
29 *
30 *
31 * Authors: Michael Mauldin (mlm@cs.cmu.edu)
32 * David Rowley (mgardi@watdcsu.waterloo.edu)
33 *
34 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
35 *
36 * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
37 * Jim McKie (decvax!mcvax!jim)
38 * Steve Davies (decvax!vax135!petsd!peora!srd)
39 * Ken Turkowski (decvax!decwrl!turtlevax!ken)
40 * James A. Woods (decvax!ihnp4!ames!jaw)
41 * Joe Orost (decvax!vax135!petsd!joe)
42 *****************************************************************/
43
44
45#include "outgif.h"
46
47static int __ILWS_Width, __ILWS_Height;
48static int __ILWS_curx, __ILWS_cury;
49static long __ILWS_CountDown;
50static int __ILWS_Interlace;
51//static unsigned char bw[2] = {0, 0xff};
52
53static void __ILWS_putword PARM((int, FILE *));
54static void __ILWS_compress PARM((int, FILE *, unsigned char *, int));
55static void __ILWS_output PARM((int));
56static void __ILWS_cl_block PARM((void));
57static void __ILWS_cl_hash PARM((count_int));
58static void __ILWS_char_init PARM((void));
59static void __ILWS_char_out PARM((int));
60static void __ILWS_flush_char PARM((void));
61
62
63static unsigned char pc2nc[256],r1[256],g1[256],b1[256];
64
65
66/*************************************************************/
67int __ILWS_WriteGIF(FILE *fp, unsigned char *pic, int w, int h, unsigned char *rmap, unsigned char *gmap, unsigned char *bmap, int numcols, int colorstyle,int transparency,
68 char *comment)
69{
70 int RWidth, RHeight;
71 int LeftOfs, TopOfs;
72 int ColorMapSize, InitCodeSize, Background, BitsPerPixel;
73 int i,j,nc;
74 unsigned char *pic8;
75 //unsigned char rtemp[256],gtemp[256],btemp[256];
76
77 pic8 = pic;
78
79
80
81 __ILWS_Interlace = 0;
82 Background = 0;
83
84
85 for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; }
86
87 /* compute number of unique colors */
88 nc = 0;
89
90 for (i=0; i<numcols; i++) {
91 /* see if color #i is already used */
92 for (j=0; j<i; j++) {
93 if (rmap[i] == rmap[j] && gmap[i] == gmap[j] &&
94 bmap[i] == bmap[j]) break;
95 }
96
97 if (j==i) { /* wasn't found */
98 pc2nc[i] = nc;
99 r1[nc] = rmap[i];
100 g1[nc] = gmap[i];
101 b1[nc] = bmap[i];
102 nc++;
103 }
104 else pc2nc[i] = pc2nc[j];
105 }
106
107
108 /* figure out 'BitsPerPixel' */
109 for (i=1; i<8; i++)
110 if ( (1<<i) >= nc) break;
111
112 BitsPerPixel = i;
113
114 ColorMapSize = 1 << BitsPerPixel;
115
116 RWidth = __ILWS_Width = w;
117 RHeight = __ILWS_Height = h;
118 LeftOfs = TopOfs = 0;
119
120 __ILWS_CountDown = w * h; /* # of pixels we'll be doing */
121
122 if (BitsPerPixel <= 1) InitCodeSize = 2;
123 else InitCodeSize = BitsPerPixel;
124
125 __ILWS_curx = __ILWS_cury = 0;
126
127 if (!fp) {
128 fprintf(stderr, "WriteGIF: file not open for writing\n" );
129 return (1);
130 }
131
132
133 if (comment && strlen(comment) > (size_t) 0)
134 fwrite("GIF89a", (size_t) 1, (size_t) 6, fp); /* the GIF magic number */
135 else
136 fwrite("GIF87a", (size_t) 1, (size_t) 6, fp); /* the GIF magic number */
137
138 __ILWS_putword(RWidth, fp); /* screen descriptor */
139 __ILWS_putword(RHeight, fp);
140
141 i = 0x80; /* Yes, there is a color map */
142 i |= (8-1)<<4; /* OR in the color resolution (hardwired 8) */
143 i |= (BitsPerPixel - 1); /* OR in the # of bits per pixel */
144 fputc(i,fp);
145
146 fputc(Background, fp); /* background color */
147
148 fputc(0, fp); /* future expansion unsigned char */
149
150
151 if (colorstyle == 1) { /* greyscale */
152 for (i=0; i<ColorMapSize; i++) {
153 j = MONO(r1[i], g1[i], b1[i]);
154 fputc(j, fp);
155 fputc(j, fp);
156 fputc(j, fp);
157 }
158 }
159 else {
160 for (i=0; i<ColorMapSize; i++) { /* write out Global colormap */
161 fputc(r1[i], fp);
162 fputc(g1[i], fp);
163 fputc(b1[i], fp);
164 }
165 }
166
167 if (comment && strlen(comment) > (size_t) 0) { /* write comment blocks */
168 char *sp;
169 int i, blen;
170
171 fputc(0x21, fp); /* EXTENSION block */
172 fputc(0xF9,fp); // graphic control extension// Luis Figueiredo
173 fputc(4,fp); // blocksize
174 fputc(0x1,fp); // transparency flag
175 fputc(100,fp);// delay (unsigned?)
176 fputc(100,fp);// delay (unsigned?)
177 fputc(transparency,fp); // Luis figueiredo
178 fputc(0, fp); /* zero-length data subblock to end extension */
179 fputc(0x21, fp); /* EXTENSION block */
180 fputc(0xFE, fp); /* comment extension */
181 sp = comment;
182 while ( (blen=strlen(sp)) > 0) {
183 if (blen>255) blen = 255;
184 fputc(blen, fp);
185 for (i=0; i<blen; i++, sp++) fputc(*sp, fp);
186 }
187 fputc(0, fp); /* zero-length data subblock to end extension */
188 }
189
190
191 fputc( ',', fp ); /* image separator */
192
193 /* Write the Image header */
194 __ILWS_putword(LeftOfs, fp);
195 __ILWS_putword(TopOfs, fp);
196 __ILWS_putword(__ILWS_Width, fp);
197 __ILWS_putword(__ILWS_Height, fp);
198 if (__ILWS_Interlace) fputc(0x40, fp); /* Use Global Colormap, maybe Interlace */
199 else fputc(0x00, fp);
200
201 fputc(InitCodeSize, fp);
202 __ILWS_compress(InitCodeSize+1, fp, pic8, w*h);
203
204 fputc(0,fp); /* Write out a Zero-length packet (EOF) */
205 fputc(';',fp); /* Write GIF file terminator */
206
207
208 if (ferror(fp)) return -1;
209 return (0);
210}
211
212
213
214
215/******************************/
216static void __ILWS_putword(int w, FILE *fp)
217{
218 /* writes a 16-bit integer in GIF order (LSB first) */
219 fputc(w & 0xff, fp);
220 fputc((w>>8)&0xff, fp);
221}
222
223
224
225
226/***********************************************************************/
227
228
229static unsigned long __ILWS_cur_accum = 0;
230static int __ILWS_cur_bits = 0;
231
232
233
234
235#define min(a,b) ((a>b) ? b : a)
236
237#define XV_BITS 12 /* BITS was already defined on some systems */
238#define MSDOS 1
239
240#define HSIZE 5003 /* 80% occupancy */
241
242typedef unsigned char char_type;
243
244
245static int __ILWS_n_bits; /* number of bits/code */
246static int __ILWS_maxbits = XV_BITS; /* user settable max # bits/code */
247static int __ILWS_maxcode; /* maximum code, given n_bits */
248static int __ILWS_maxmaxcode = 1 << XV_BITS; /* NEVER generate this */
249
250#define MAXCODE(n_bits) ( (1 << (n_bits)) - 1)
251
252static count_int __ILWS_htab [HSIZE];
253static unsigned short __ILWS_codetab [HSIZE];
254#define HashTabOf(i) __ILWS_htab[i]
255#define CodeTabOf(i) __ILWS_codetab[i]
256
257static int __ILWS_hsize = HSIZE; /* for dynamic table sizing */
258
259/*
260 * To save much memory, we overlay the table used by compress() with those
261 * used by decompress(). The tab_prefix table is the same size and type
262 * as the codetab. The tab_suffix table needs 2**BITS characters. We
263 * get this from the beginning of htab. The output stack uses the rest
264 * of htab, and contains characters. There is plenty of room for any
265 * possible stack (stack used to be 8000 characters).
266 */
267
268#define tab_prefixof(i) CodeTabOf(i)
269#define tab_suffixof(i) ((char_type *)(htab))[i]
270#define de_stack ((char_type *)&tab_suffixof(1<<XV_BITS))
271
272static int __ILWS_free_ent = 0; /* first unused entry */
273
274/*
275 * block compression parameters -- after all codes are used up,
276 * and compression rate changes, start over.
277 */
278static int __ILWS_clear_flg = 0;
279
280static long int __ILWS_in_count = 1; /* length of input */
281static long int __ILWS_out_count = 0; /* # of codes output (for debugging) */
282
283/*
284 * compress stdin to stdout
285 *
286 * Algorithm: use open addressing double hashing (no chaining) on the
287 * prefix code / next character combination. We do a variant of Knuth's
288 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
289 * secondary probe. Here, the modular division first probe is gives way
290 * to a faster exclusive-or manipulation. Also do block compression with
291 * an adaptive reset, whereby the code table is cleared when the compression
292 * ratio decreases, but after the table fills. The variable-length output
293 * codes are re-sized at this point, and a special CLEAR code is generated
294 * for the decompressor. Late addition: construct the table according to
295 * file size for noticeable speed improvement on small files. Please direct
296 * questions about this implementation to ames!jaw.
297 */
298
299static int __ILWS_g_init_bits;
300static FILE *__ILWS_g_outfile;
301
302static int __ILWS_ClearCode;
303static int __ILWS_EOFCode;
304
305
306/********************************************************/
307static void __ILWS_compress(int init_bits, FILE *outfile, unsigned char *data, int len)
308
309{
310 register long fcode;
311 register int i = 0;
312 register int c;
313 register int ent;
314 register int disp;
315 register int hsize_reg;
316 register int hshift;
317
318 /*
319 * Set up the globals: g_init_bits - initial number of bits
320 * g_outfile - pointer to output file
321 */
322 __ILWS_g_init_bits = init_bits;
323 __ILWS_g_outfile = outfile;
324
325 /* initialize 'compress' globals */
326 __ILWS_maxbits = XV_BITS;
327 __ILWS_maxmaxcode = 1<<XV_BITS;
328 memset((char *) __ILWS_htab,0, sizeof(__ILWS_htab));
329 memset((char *) __ILWS_codetab,0, sizeof(__ILWS_codetab));
330 __ILWS_hsize = HSIZE;
331 __ILWS_free_ent = 0;
332 __ILWS_clear_flg = 0;
333 __ILWS_in_count = 1;
334 __ILWS_out_count = 0;
335 __ILWS_cur_accum = 0;
336 __ILWS_cur_bits = 0;
337
338
339 /*
340 * Set up the necessary values
341 */
342 __ILWS_out_count = 0;
343 __ILWS_clear_flg = 0;
344 __ILWS_in_count = 1;
345 __ILWS_maxcode = MAXCODE(__ILWS_n_bits = __ILWS_g_init_bits);
346
347 __ILWS_ClearCode = (1 << (init_bits - 1));
348 __ILWS_EOFCode = __ILWS_ClearCode + 1;
349 __ILWS_free_ent = __ILWS_ClearCode + 2;
350
351 __ILWS_char_init();
352 ent = pc2nc[*data++];
353 len--;
354
355 hshift = 0;
356 for ( fcode = (long) __ILWS_hsize; fcode < 65536L; fcode *= 2L )
357 hshift++;
358 hshift = 8 - hshift; /* set hash code range bound */
359
360 hsize_reg = __ILWS_hsize;
361 __ILWS_cl_hash( (count_int) hsize_reg); /* clear hash table */
362
363 __ILWS_output(__ILWS_ClearCode);
364
365 while (len) {
366 c = pc2nc[*data++]; len--;
367 __ILWS_in_count++;
368
369 fcode = (long) ( ( (long) c << __ILWS_maxbits) + ent);
370 i = (((int) c << hshift) ^ ent); /* xor hashing */
371
372 if ( HashTabOf (i) == fcode ) {
373 ent = CodeTabOf (i);
374 continue;
375 }
376
377 else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
378 goto nomatch;
379
380 disp = hsize_reg - i; /* secondary hash (after G. Knott) */
381 if ( i == 0 )
382 disp = 1;
383
384probe:
385 if ( (i -= disp) < 0 )
386 i += hsize_reg;
387
388 if ( HashTabOf (i) == fcode ) {
389 ent = CodeTabOf (i);
390 continue;
391 }
392
393 if ( (long)HashTabOf (i) >= 0 )
394 goto probe;
395
396nomatch:
397 __ILWS_output(ent);
398 __ILWS_out_count++;
399 ent = c;
400
401 if ( __ILWS_free_ent < __ILWS_maxmaxcode ) {
402 CodeTabOf (i) = __ILWS_free_ent++; /* code -> hashtable */
403 HashTabOf (i) = fcode;
404 }
405 else
406 __ILWS_cl_block();
407 }
408
409 /* Put out the final code */
410 __ILWS_output(ent);
411 __ILWS_out_count++;
412 __ILWS_output(__ILWS_EOFCode);
413}
414
415
416/*****************************************************************
417 * TAG( output )
418 *
419 * Output the given code.
420 * Inputs:
421 * code: A n_bits-bit integer. If == -1, then EOF. This assumes
422 * that n_bits =< (long)wordsize - 1.
423 * Outputs:
424 * Outputs code to the file.
425 * Assumptions:
426 * Chars are 8 bits long.
427 * Algorithm:
428 * Maintain a BITS character long buffer (so that 8 codes will
429 * fit in it exactly). Use the VAX insv instruction to insert each
430 * code in turn. When the buffer fills up empty it and start over.
431 */
432
433static
434unsigned long __ILWS_masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
435 0x001F, 0x003F, 0x007F, 0x00FF,
436 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
437 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
438
439static void __ILWS_output(int code)
440{
441 __ILWS_cur_accum &= __ILWS_masks[__ILWS_cur_bits];
442
443 if (__ILWS_cur_bits > 0)
444 __ILWS_cur_accum |= ((long)code << __ILWS_cur_bits);
445 else
446 __ILWS_cur_accum = code;
447
448 __ILWS_cur_bits += __ILWS_n_bits;
449
450 while( __ILWS_cur_bits >= 8 ) {
451 __ILWS_char_out( (int) (__ILWS_cur_accum & 0xff) );
452 __ILWS_cur_accum >>= 8;
453 __ILWS_cur_bits -= 8;
454 }
455
456 /*
457 * If the next entry is going to be too big for the code size,
458 * then increase it, if possible.
459 */
460
461 if (__ILWS_free_ent > __ILWS_maxcode || __ILWS_clear_flg) {
462
463 if( __ILWS_clear_flg ) {
464 __ILWS_maxcode = MAXCODE (__ILWS_n_bits = __ILWS_g_init_bits);
465 __ILWS_clear_flg = 0;
466 }
467 else {
468 __ILWS_n_bits++;
469 if ( __ILWS_n_bits == __ILWS_maxbits )
470 __ILWS_maxcode = __ILWS_maxmaxcode;
471 else
472 __ILWS_maxcode = MAXCODE(__ILWS_n_bits);
473 }
474 }
475
476 if( code == __ILWS_EOFCode ) {
477 /* At EOF, write the rest of the buffer */
478 while( __ILWS_cur_bits > 0 ) {
479 __ILWS_char_out( (int)(__ILWS_cur_accum & 0xff) );
480 __ILWS_cur_accum >>= 8;
481 __ILWS_cur_bits -= 8;
482 }
483
484 __ILWS_flush_char();
485
486 fflush( __ILWS_g_outfile );
487
488#ifdef FOO
489 if( ferror( g_outfile ) )
490 FatalError("unable to write GIF file");
491#endif
492 }
493}
494
495
496/********************************/
497static void __ILWS_cl_block () /* table clear for block compress */
498{
499 /* Clear out the hash table */
500
501 __ILWS_cl_hash ( (count_int) __ILWS_hsize );
502 __ILWS_free_ent = __ILWS_ClearCode + 2;
503 __ILWS_clear_flg = 1;
504
505 __ILWS_output(__ILWS_ClearCode);
506}
507
508
509/********************************/
510static void __ILWS_cl_hash(register count_int hsize) /* reset code table */
511{
512 register count_int *htab_p = __ILWS_htab+hsize;
513 register long i;
514 register long m1 = -1;
515
516 i = hsize - 16;
517 do { /* might use Sys V memset(3) here */
518 *(htab_p-16) = m1;
519 *(htab_p-15) = m1;
520 *(htab_p-14) = m1;
521 *(htab_p-13) = m1;
522 *(htab_p-12) = m1;
523 *(htab_p-11) = m1;
524 *(htab_p-10) = m1;
525 *(htab_p-9) = m1;
526 *(htab_p-8) = m1;
527 *(htab_p-7) = m1;
528 *(htab_p-6) = m1;
529 *(htab_p-5) = m1;
530 *(htab_p-4) = m1;
531 *(htab_p-3) = m1;
532 *(htab_p-2) = m1;
533 *(htab_p-1) = m1;
534 htab_p -= 16;
535 } while ((i -= 16) >= 0);
536
537 for ( i += 16; i > 0; i-- )
538 *--htab_p = m1;
539}
540
541
542/******************************************************************************
543 *
544 * GIF Specific routines
545 *
546 ******************************************************************************/
547
548/*
549 * Number of characters so far in this 'packet'
550 */
551static int __ILWS_a_count;
552
553/*
554 * Set up the 'unsigned char output' routine
555 */
556static void __ILWS_char_init()
557{
558 __ILWS_a_count = 0;
559}
560
561/*
562 * Define the storage for the packet accumulator
563 */
564static char __ILWS_accum[ 256 ];
565
566/*
567 * Add a character to the end of the current packet, and if it is 254
568 * characters, flush the packet to disk.
569 */
570static void __ILWS_char_out(int c)
571{
572 __ILWS_accum[ __ILWS_a_count++ ] = c;
573 if( __ILWS_a_count >= 254 )
574 __ILWS_flush_char();
575}
576
577/*
578 * Flush the packet to disk, and reset the accumulator
579 */
580static void __ILWS_flush_char()
581{
582 if( __ILWS_a_count > 0 ) {
583 fputc(__ILWS_a_count, __ILWS_g_outfile );
584 fwrite(__ILWS_accum, (size_t) 1, (size_t) __ILWS_a_count, __ILWS_g_outfile );
585 __ILWS_a_count = 0;
586 }
587}