Line 0
Link Here
|
|
|
1 |
#include <stdio.h> |
2 |
#include <math.h> |
3 |
#include <string.h> |
4 |
#include <stdlib.h> |
5 |
#include "gd.h" |
6 |
|
7 |
/* |
8 |
** Wrapper functions for this module. |
9 |
*/ |
10 |
|
11 |
void gdImageBigGif(gdImagePtr im, FILE *outFile) |
12 |
{ |
13 |
gdIOCtx *out = gdNewFileCtx(outFile); |
14 |
gdImageBigGifCtx(im, out); |
15 |
out->gd_free(out); |
16 |
} |
17 |
|
18 |
void* gdImageBigGifPtr(gdImagePtr im, int *size) |
19 |
{ |
20 |
void *rv; |
21 |
gdIOCtx *out = gdNewDynamicCtx(2048, NULL); |
22 |
gdImageBigGifCtx(im, out); |
23 |
rv = gdDPExtractData(out,size); |
24 |
out->gd_free(out); |
25 |
return rv; |
26 |
} |
27 |
|
28 |
/* Code drawn from ppmtogif.c, from the pbmplus package |
29 |
** |
30 |
** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A |
31 |
** Lempel-Zim compression based on "compress". |
32 |
** |
33 |
** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl> |
34 |
** |
35 |
** Copyright (C) 1989 by Jef Poskanzer. |
36 |
** |
37 |
** Permission to use, copy, modify, and distribute this software and its |
38 |
** documentation for any purpose and without fee is hereby granted, provided |
39 |
** that the above copyright notice appear in all copies and that both that |
40 |
** copyright notice and this permission notice appear in supporting |
41 |
** documentation. This software is provided "as is" without express or |
42 |
** implied warranty. |
43 |
** |
44 |
** The Graphics Interchange Format(c) is the Copyright property of |
45 |
** CompuServe Incorporated. GIF(sm) is a Service Mark property of |
46 |
** CompuServe Incorporated. |
47 |
* |
48 |
* Heavily modified by Mouse, 1998-02-12. |
49 |
* Remove LZW compression. |
50 |
* Added miGIF run length compression. |
51 |
* |
52 |
*/ |
53 |
|
54 |
/* |
55 |
* a code_int must be able to hold 2**GIFBITS values of type int, and also -1 |
56 |
*/ |
57 |
typedef int code_int; |
58 |
|
59 |
static int colorstobpp(int colors); |
60 |
static void BumpPixel (void); |
61 |
static int GIFNextPixel (gdImagePtr im); |
62 |
static void GIFEncode (gdIOCtx *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im); |
63 |
/*static void Putword (int w, gdIOCtx *fp); */ |
64 |
static void GIFcompress (int, gdIOCtx *, gdImagePtr, int); |
65 |
static void output (code_int code); |
66 |
|
67 |
/* UNUSED |
68 |
* static void char_init (void); |
69 |
* static void char_out (int c); |
70 |
*/ |
71 |
|
72 |
/* Allows for reuse */ |
73 |
static void init_statics(void); |
74 |
|
75 |
void gdImageBigGifCtx(gdImagePtr im, gdIOCtx *out) |
76 |
{ |
77 |
int interlace, transparent, BitsPerPixel; |
78 |
|
79 |
interlace = im->interlace; |
80 |
transparent = im->transparent; |
81 |
|
82 |
BitsPerPixel = colorstobpp(im->colorsTotal); |
83 |
/* Clear any old values in statics strewn through the GIF code */ |
84 |
init_statics(); |
85 |
/* All set, let's do it. */ |
86 |
GIFEncode( |
87 |
out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel, |
88 |
im->red, im->green, im->blue, im); |
89 |
} |
90 |
|
91 |
static int |
92 |
colorstobpp(int colors) |
93 |
{ |
94 |
int bpp = 0; |
95 |
|
96 |
if ( colors <= 2 ) |
97 |
bpp = 1; |
98 |
else if ( colors <= 4 ) |
99 |
bpp = 2; |
100 |
else if ( colors <= 8 ) |
101 |
bpp = 3; |
102 |
else if ( colors <= 16 ) |
103 |
bpp = 4; |
104 |
else if ( colors <= 32 ) |
105 |
bpp = 5; |
106 |
else if ( colors <= 64 ) |
107 |
bpp = 6; |
108 |
else if ( colors <= 128 ) |
109 |
bpp = 7; |
110 |
else if ( colors <= 256 ) |
111 |
bpp = 8; |
112 |
return bpp; |
113 |
} |
114 |
|
115 |
/***************************************************************************** |
116 |
* |
117 |
* GIFENCODE.C - GIF Image compression interface |
118 |
* |
119 |
* GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent, |
120 |
* BitsPerPixel, Red, Green, Blue, gdImagePtr ) |
121 |
* |
122 |
*****************************************************************************/ |
123 |
|
124 |
#define TRUE 1 |
125 |
#define FALSE 0 |
126 |
|
127 |
static int Width, Height; |
128 |
static int curx, cury; |
129 |
static long CountDown; |
130 |
static int Pass = 0; |
131 |
static int Interlace; |
132 |
|
133 |
/* |
134 |
* Bump the 'curx' and 'cury' to point to the next pixel |
135 |
*/ |
136 |
static void |
137 |
BumpPixel(void) |
138 |
{ |
139 |
/* |
140 |
* Bump the current X position |
141 |
*/ |
142 |
++curx; |
143 |
|
144 |
/* |
145 |
* If we are at the end of a scan line, set curx back to the beginning |
146 |
* If we are interlaced, bump the cury to the appropriate spot, |
147 |
* otherwise, just increment it. |
148 |
*/ |
149 |
if( curx == Width ) { |
150 |
curx = 0; |
151 |
|
152 |
if( !Interlace ) |
153 |
++cury; |
154 |
else { |
155 |
switch( Pass ) { |
156 |
|
157 |
case 0: |
158 |
cury += 8; |
159 |
if( cury >= Height ) { |
160 |
++Pass; |
161 |
cury = 4; |
162 |
} |
163 |
break; |
164 |
|
165 |
case 1: |
166 |
cury += 8; |
167 |
if( cury >= Height ) { |
168 |
++Pass; |
169 |
cury = 2; |
170 |
} |
171 |
break; |
172 |
|
173 |
case 2: |
174 |
cury += 4; |
175 |
if( cury >= Height ) { |
176 |
++Pass; |
177 |
cury = 1; |
178 |
} |
179 |
break; |
180 |
|
181 |
case 3: |
182 |
cury += 2; |
183 |
break; |
184 |
} |
185 |
} |
186 |
} |
187 |
} |
188 |
|
189 |
/* |
190 |
* Return the next pixel from the image |
191 |
*/ |
192 |
static int |
193 |
GIFNextPixel(gdImagePtr im) |
194 |
{ |
195 |
int r; |
196 |
|
197 |
if( CountDown == 0 ) |
198 |
return EOF; |
199 |
|
200 |
--CountDown; |
201 |
|
202 |
r = gdImageGetPixel(im, curx, cury); |
203 |
|
204 |
BumpPixel(); |
205 |
|
206 |
return r; |
207 |
} |
208 |
|
209 |
/* public */ |
210 |
|
211 |
static void |
212 |
GIFEncode(gdIOCtx *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im) |
213 |
{ |
214 |
int B; |
215 |
int RWidth, RHeight; |
216 |
int LeftOfs, TopOfs; |
217 |
int Resolution; |
218 |
int ColorMapSize; |
219 |
int InitCodeSize; |
220 |
int i; |
221 |
|
222 |
Interlace = GInterlace; |
223 |
|
224 |
ColorMapSize = 1 << BitsPerPixel; |
225 |
|
226 |
RWidth = Width = GWidth; |
227 |
RHeight = Height = GHeight; |
228 |
LeftOfs = TopOfs = 0; |
229 |
|
230 |
Resolution = BitsPerPixel; |
231 |
|
232 |
/* |
233 |
* Calculate number of bits we are expecting |
234 |
*/ |
235 |
CountDown = (long)Width * (long)Height; |
236 |
|
237 |
/* |
238 |
* Indicate which pass we are on (if interlace) |
239 |
*/ |
240 |
Pass = 0; |
241 |
|
242 |
/* |
243 |
* The initial code size |
244 |
*/ |
245 |
if( BitsPerPixel <= 1 ) |
246 |
InitCodeSize = 2; |
247 |
else |
248 |
InitCodeSize = BitsPerPixel; |
249 |
|
250 |
/* |
251 |
* Set up the current x and y position |
252 |
*/ |
253 |
curx = cury = 0; |
254 |
|
255 |
/* |
256 |
* Write the Magic header |
257 |
*/ |
258 |
gdPutBuf( Transparent < 0 ? "GIF87a" : "GIF89a", 6, fp ); |
259 |
|
260 |
/* |
261 |
* Write out the screen width and height |
262 |
*/ |
263 |
Putword( RWidth, fp ); |
264 |
Putword( RHeight, fp ); |
265 |
|
266 |
/* |
267 |
* Indicate that there is a global colour map |
268 |
*/ |
269 |
B = 0x80; /* Yes, there is a color map */ |
270 |
|
271 |
/* |
272 |
* OR in the resolution |
273 |
*/ |
274 |
B |= (Resolution - 1) << 4; |
275 |
|
276 |
/* |
277 |
* OR in the Bits per Pixel |
278 |
*/ |
279 |
B |= (BitsPerPixel - 1); |
280 |
|
281 |
/* |
282 |
* Write it out |
283 |
*/ |
284 |
gdPutC( B, fp ); |
285 |
|
286 |
/* |
287 |
* Write out the Background colour |
288 |
*/ |
289 |
gdPutC( Background, fp ); |
290 |
|
291 |
/* |
292 |
* Byte of 0's (future expansion) |
293 |
*/ |
294 |
gdPutC( 0, fp ); |
295 |
|
296 |
/* |
297 |
* Write out the Global Colour Map |
298 |
*/ |
299 |
for( i=0; i<ColorMapSize; ++i ) { |
300 |
gdPutC( Red[i], fp ); |
301 |
gdPutC( Green[i], fp ); |
302 |
gdPutC( Blue[i], fp ); |
303 |
} |
304 |
|
305 |
/* |
306 |
* Write out extension for transparent colour index, if necessary. |
307 |
*/ |
308 |
if ( Transparent >= 0 ) { |
309 |
gdPutC( '!', fp ); |
310 |
gdPutC( 0xf9, fp ); |
311 |
gdPutC( 4, fp ); |
312 |
gdPutC( 1, fp ); |
313 |
gdPutC( 0, fp ); |
314 |
gdPutC( 0, fp ); |
315 |
gdPutC( (unsigned char) Transparent, fp ); |
316 |
gdPutC( 0, fp ); |
317 |
} |
318 |
|
319 |
/* |
320 |
* Write an Image separator |
321 |
*/ |
322 |
gdPutC( ',', fp ); |
323 |
|
324 |
/* |
325 |
* Write the Image header |
326 |
*/ |
327 |
|
328 |
Putword( LeftOfs, fp ); |
329 |
Putword( TopOfs, fp ); |
330 |
Putword( Width, fp ); |
331 |
Putword( Height, fp ); |
332 |
|
333 |
/* |
334 |
* Write out whether or not the image is interlaced |
335 |
*/ |
336 |
if( Interlace ) |
337 |
gdPutC( 0x40, fp ); |
338 |
else |
339 |
gdPutC( 0x00, fp ); |
340 |
|
341 |
/* |
342 |
* Write out the initial code size |
343 |
*/ |
344 |
gdPutC( InitCodeSize, fp ); |
345 |
|
346 |
/* |
347 |
* Go and actually compress the data |
348 |
*/ |
349 |
GIFcompress( InitCodeSize+1, fp, im, Background ); |
350 |
|
351 |
/* |
352 |
* Write out a Zero-length packet (to end the series) |
353 |
*/ |
354 |
gdPutC( 0, fp ); |
355 |
|
356 |
/* |
357 |
* Write the GIF file terminator |
358 |
*/ |
359 |
gdPutC( ';', fp ); |
360 |
} |
361 |
|
362 |
/* Write out a word to the GIF file */ |
363 |
/*static void */ |
364 |
/*Putword(int w, gdIOCtx *fp) */ |
365 |
/*{ */ |
366 |
/* fputc( w & 0xff, fp ); */ |
367 |
/* fputc( (w / 256) & 0xff, fp ); */ |
368 |
/*} */ |
369 |
|
370 |
#define GIFBITS 12 |
371 |
|
372 |
/*----------------------------------------------------------------------- |
373 |
* |
374 |
* miGIF Compression - mouse and ivo's GIF-compatible compression |
375 |
* |
376 |
* -run length encoding compression routines- |
377 |
* |
378 |
* Copyright (C) 1998 Hutchison Avenue Software Corporation |
379 |
* http://www.hasc.com |
380 |
* info@hasc.com |
381 |
* |
382 |
* Permission to use, copy, modify, and distribute this software and its |
383 |
* documentation for any purpose and without fee is hereby granted, provided |
384 |
* that the above copyright notice appear in all copies and that both that |
385 |
* copyright notice and this permission notice appear in supporting |
386 |
* documentation. This software is provided "AS IS." The Hutchison Avenue |
387 |
* Software Corporation disclaims all warranties, either express or implied, |
388 |
* including but not limited to implied warranties of merchantability and |
389 |
* fitness for a particular purpose, with respect to this code and accompanying |
390 |
* documentation. |
391 |
* |
392 |
* The miGIF compression routines do not, strictly speaking, generate files |
393 |
* conforming to the GIF spec, since the image data is not LZW-compressed |
394 |
* (this is the point: in order to avoid transgression of the Unisys patent |
395 |
* on the LZW algorithm.) However, miGIF generates data streams that any |
396 |
* reasonably sane LZW decompresser will decompress to what we want. |
397 |
* |
398 |
* miGIF compression uses run length encoding. It compresses horizontal runs |
399 |
* of pixels of the same color. This type of compression gives good results |
400 |
* on images with many runs, for example images with lines, text and solid |
401 |
* shapes on a solid-colored background. It gives little or no compression |
402 |
* on images with few runs, for example digital or scanned photos. |
403 |
* |
404 |
* der Mouse |
405 |
* mouse@rodents.montreal.qc.ca |
406 |
* 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B |
407 |
* |
408 |
* ivo@hasc.com |
409 |
* |
410 |
* The Graphics Interchange Format(c) is the Copyright property of |
411 |
* CompuServe Incorporated. GIF(sm) is a Service Mark property of |
412 |
* CompuServe Incorporated. |
413 |
* |
414 |
*/ |
415 |
|
416 |
static int rl_pixel; |
417 |
static int rl_basecode; |
418 |
static int rl_count; |
419 |
static int rl_table_pixel; |
420 |
static int rl_table_max; |
421 |
static int just_cleared; |
422 |
static int out_bits; |
423 |
static int out_bits_init; |
424 |
static int out_count; |
425 |
static int out_bump; |
426 |
static int out_bump_init; |
427 |
static int out_clear; |
428 |
static int out_clear_init; |
429 |
static int max_ocodes; |
430 |
static int code_clear; |
431 |
static int code_eof; |
432 |
static unsigned int obuf; |
433 |
static int obits; |
434 |
static gdIOCtx *ofile; |
435 |
static unsigned char oblock[256]; |
436 |
static int oblen; |
437 |
|
438 |
/* Used only when debugging GIF compression code */ |
439 |
/* #define DEBUGGING_ENVARS */ |
440 |
|
441 |
#ifdef DEBUGGING_ENVARS |
442 |
|
443 |
static int verbose_set = 0; |
444 |
static int verbose; |
445 |
#define VERBOSE (verbose_set?verbose:set_verbose()) |
446 |
|
447 |
static int set_verbose(void) |
448 |
{ |
449 |
verbose = !!getenv("GIF_VERBOSE"); |
450 |
verbose_set = 1; |
451 |
return(verbose); |
452 |
} |
453 |
|
454 |
#else |
455 |
|
456 |
#define VERBOSE 0 |
457 |
|
458 |
#endif |
459 |
|
460 |
|
461 |
static const char *binformat(unsigned int v, int nbits) |
462 |
{ |
463 |
static char bufs[8][64]; |
464 |
static int bhand = 0; |
465 |
unsigned int bit; |
466 |
int bno; |
467 |
char *bp; |
468 |
|
469 |
bhand --; |
470 |
if (bhand < 0) bhand = (sizeof(bufs)/sizeof(bufs[0]))-1; |
471 |
bp = &bufs[bhand][0]; |
472 |
for (bno=nbits-1,bit=1U<<bno;bno>=0;bno--,bit>>=1) |
473 |
{ *bp++ = (v & bit) ? '1' : '0'; |
474 |
if (((bno&3) == 0) && (bno != 0)) *bp++ = '.'; |
475 |
} |
476 |
*bp = '\0'; |
477 |
return(&bufs[bhand][0]); |
478 |
} |
479 |
|
480 |
static void write_block(void) |
481 |
{ |
482 |
int i; |
483 |
|
484 |
if (VERBOSE) |
485 |
{ printf("write_block %d:",oblen); |
486 |
for (i=0;i<oblen;i++) printf(" %02x",oblock[i]); |
487 |
printf("\n"); |
488 |
} |
489 |
gdPutC(oblen,ofile); |
490 |
gdPutBuf(&oblock[0],oblen,ofile); |
491 |
oblen = 0; |
492 |
} |
493 |
|
494 |
static void block_out(unsigned char c) |
495 |
{ |
496 |
if (VERBOSE) printf("block_out %s\n",binformat(c,8)); |
497 |
oblock[oblen++] = c; |
498 |
if (oblen >= 255) write_block(); |
499 |
} |
500 |
|
501 |
static void block_flush(void) |
502 |
{ |
503 |
if (VERBOSE) printf("block_flush\n"); |
504 |
if (oblen > 0) write_block(); |
505 |
} |
506 |
|
507 |
static void output(int val) |
508 |
{ |
509 |
if (VERBOSE) printf("output %s [%s %d %d]\n",binformat(val,out_bits),binformat(obuf,obits),obits,out_bits); |
510 |
obuf |= val << obits; |
511 |
obits += out_bits; |
512 |
while (obits >= 8) |
513 |
{ block_out(obuf&0xff); |
514 |
obuf >>= 8; |
515 |
obits -= 8; |
516 |
} |
517 |
if (VERBOSE) printf("output leaving [%s %d]\n",binformat(obuf,obits),obits); |
518 |
} |
519 |
|
520 |
static void output_flush(void) |
521 |
{ |
522 |
if (VERBOSE) printf("output_flush\n"); |
523 |
if (obits > 0) block_out(obuf); |
524 |
block_flush(); |
525 |
} |
526 |
|
527 |
static void did_clear(void) |
528 |
{ |
529 |
if (VERBOSE) printf("did_clear\n"); |
530 |
out_bits = out_bits_init; |
531 |
out_bump = out_bump_init; |
532 |
out_clear = out_clear_init; |
533 |
out_count = 0; |
534 |
rl_table_max = 0; |
535 |
just_cleared = 1; |
536 |
} |
537 |
|
538 |
static void output_plain(int c) |
539 |
{ |
540 |
if (VERBOSE) printf("output_plain %s\n",binformat(c,out_bits)); |
541 |
just_cleared = 0; |
542 |
output(c); |
543 |
out_count ++; |
544 |
if (out_count >= out_bump) |
545 |
{ out_bits ++; |
546 |
out_bump += 1 << (out_bits - 1); |
547 |
} |
548 |
if (out_count >= out_clear) |
549 |
{ output(code_clear); |
550 |
did_clear(); |
551 |
} |
552 |
} |
553 |
|
554 |
static unsigned int isqrt(unsigned int x) |
555 |
{ |
556 |
unsigned int r; |
557 |
unsigned int v; |
558 |
|
559 |
if (x < 2) return(x); |
560 |
for (v=x,r=1;v;v>>=2,r<<=1) ; |
561 |
while (1) |
562 |
{ v = ((x / r) + r) / 2; |
563 |
if ((v == r) || (v == r+1)) return(r); |
564 |
r = v; |
565 |
} |
566 |
} |
567 |
|
568 |
static unsigned int compute_triangle_count(unsigned int count, unsigned int nrepcodes) |
569 |
{ |
570 |
unsigned int perrep; |
571 |
unsigned int cost; |
572 |
|
573 |
cost = 0; |
574 |
perrep = (nrepcodes * (nrepcodes+1)) / 2; |
575 |
while (count >= perrep) |
576 |
{ cost += nrepcodes; |
577 |
count -= perrep; |
578 |
} |
579 |
if (count > 0) |
580 |
{ unsigned int n; |
581 |
n = isqrt(count); |
582 |
while ((n*(n+1)) >= 2*count) n --; |
583 |
while ((n*(n+1)) < 2*count) n ++; |
584 |
cost += n; |
585 |
} |
586 |
return(cost); |
587 |
} |
588 |
|
589 |
static void max_out_clear(void) |
590 |
{ |
591 |
out_clear = max_ocodes; |
592 |
} |
593 |
|
594 |
static void reset_out_clear(void) |
595 |
{ |
596 |
out_clear = out_clear_init; |
597 |
if (out_count >= out_clear) |
598 |
{ output(code_clear); |
599 |
did_clear(); |
600 |
} |
601 |
} |
602 |
|
603 |
static void rl_flush_fromclear(int count) |
604 |
{ |
605 |
int n; |
606 |
|
607 |
if (VERBOSE) printf("rl_flush_fromclear %d\n",count); |
608 |
max_out_clear(); |
609 |
rl_table_pixel = rl_pixel; |
610 |
n = 1; |
611 |
while (count > 0) |
612 |
{ if (n == 1) |
613 |
{ rl_table_max = 1; |
614 |
output_plain(rl_pixel); |
615 |
count --; |
616 |
} |
617 |
else if (count >= n) |
618 |
{ rl_table_max = n; |
619 |
output_plain(rl_basecode+n-2); |
620 |
count -= n; |
621 |
} |
622 |
else if (count == 1) |
623 |
{ rl_table_max ++; |
624 |
output_plain(rl_pixel); |
625 |
count = 0; |
626 |
} |
627 |
else |
628 |
{ rl_table_max ++; |
629 |
output_plain(rl_basecode+count-2); |
630 |
count = 0; |
631 |
} |
632 |
if (out_count == 0) n = 1; else n ++; |
633 |
} |
634 |
reset_out_clear(); |
635 |
if (VERBOSE) printf("rl_flush_fromclear leaving table_max=%d\n",rl_table_max); |
636 |
} |
637 |
|
638 |
static void rl_flush_clearorrep(int count) |
639 |
{ |
640 |
int withclr; |
641 |
|
642 |
if (VERBOSE) printf("rl_flush_clearorrep %d\n",count); |
643 |
withclr = 1 + compute_triangle_count(count,max_ocodes); |
644 |
if (withclr < count) |
645 |
{ output(code_clear); |
646 |
did_clear(); |
647 |
rl_flush_fromclear(count); |
648 |
} |
649 |
else |
650 |
{ for (;count>0;count--) output_plain(rl_pixel); |
651 |
} |
652 |
} |
653 |
|
654 |
static void rl_flush_withtable(int count) |
655 |
{ |
656 |
int repmax; |
657 |
int repleft; |
658 |
int leftover; |
659 |
|
660 |
if (VERBOSE) printf("rl_flush_withtable %d\n",count); |
661 |
repmax = count / rl_table_max; |
662 |
leftover = count % rl_table_max; |
663 |
repleft = (leftover ? 1 : 0); |
664 |
if (out_count+repmax+repleft > max_ocodes) |
665 |
{ repmax = max_ocodes - out_count; |
666 |
leftover = count - (repmax * rl_table_max); |
667 |
repleft = 1 + compute_triangle_count(leftover,max_ocodes); |
668 |
} |
669 |
if (VERBOSE) printf("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",repmax,leftover,repleft); |
670 |
if (1+compute_triangle_count(count,max_ocodes) < repmax+repleft) |
671 |
{ output(code_clear); |
672 |
did_clear(); |
673 |
rl_flush_fromclear(count); |
674 |
return; |
675 |
} |
676 |
max_out_clear(); |
677 |
for (;repmax>0;repmax--) output_plain(rl_basecode+rl_table_max-2); |
678 |
if (leftover) |
679 |
{ if (just_cleared) |
680 |
{ rl_flush_fromclear(leftover); |
681 |
} |
682 |
else if (leftover == 1) |
683 |
{ output_plain(rl_pixel); |
684 |
} |
685 |
else |
686 |
{ output_plain(rl_basecode+leftover-2); |
687 |
} |
688 |
} |
689 |
reset_out_clear(); |
690 |
} |
691 |
|
692 |
static void rl_flush(void) |
693 |
{ |
694 |
/* UNUSED int table_reps; */ |
695 |
/* UNUSED int table_extra; */ |
696 |
|
697 |
if (VERBOSE) printf("rl_flush [ %d %d\n",rl_count,rl_pixel); |
698 |
if (rl_count == 1) |
699 |
{ output_plain(rl_pixel); |
700 |
rl_count = 0; |
701 |
if (VERBOSE) printf("rl_flush ]\n"); |
702 |
return; |
703 |
} |
704 |
if (just_cleared) |
705 |
{ rl_flush_fromclear(rl_count); |
706 |
} |
707 |
else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel)) |
708 |
{ rl_flush_clearorrep(rl_count); |
709 |
} |
710 |
else |
711 |
{ rl_flush_withtable(rl_count); |
712 |
} |
713 |
if (VERBOSE) printf("rl_flush ]\n"); |
714 |
rl_count = 0; |
715 |
} |
716 |
|
717 |
static void GIFcompress(int init_bits, gdIOCtx *outfile, gdImagePtr im, int background) |
718 |
{ |
719 |
int c; |
720 |
|
721 |
ofile = outfile; |
722 |
obuf = 0; |
723 |
obits = 0; |
724 |
oblen = 0; |
725 |
code_clear = 1 << (init_bits - 1); |
726 |
code_eof = code_clear + 1; |
727 |
rl_basecode = code_eof + 1; |
728 |
out_bump_init = (1 << (init_bits - 1)) - 1; |
729 |
/* for images with a lot of runs, making out_clear_init larger will |
730 |
give better compression. */ |
731 |
out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1); |
732 |
#ifdef DEBUGGING_ENVARS |
733 |
{ const char *ocienv; |
734 |
ocienv = getenv("GIF_OUT_CLEAR_INIT"); |
735 |
if (ocienv) |
736 |
{ out_clear_init = atoi(ocienv); |
737 |
if (VERBOSE) printf("[overriding out_clear_init to %d]\n",out_clear_init); |
738 |
} |
739 |
} |
740 |
#endif |
741 |
out_bits_init = init_bits; |
742 |
max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3); |
743 |
did_clear(); |
744 |
output(code_clear); |
745 |
rl_count = 0; |
746 |
while (1) |
747 |
{ c = GIFNextPixel(im); |
748 |
if ((rl_count > 0) && (c != rl_pixel)) rl_flush(); |
749 |
if (c == EOF) break; |
750 |
if (rl_pixel == c) |
751 |
{ rl_count ++; |
752 |
} |
753 |
else |
754 |
{ rl_pixel = c; |
755 |
rl_count = 1; |
756 |
} |
757 |
} |
758 |
output(code_eof); |
759 |
output_flush(); |
760 |
} |
761 |
|
762 |
/*----------------------------------------------------------------------- |
763 |
* |
764 |
* End of miGIF section - See copyright notice at start of section. |
765 |
* |
766 |
*----------------------------------------------------------------------- |
767 |
*/ |
768 |
|
769 |
/****************************************************************************** |
770 |
* |
771 |
* GIF Specific routines |
772 |
* |
773 |
******************************************************************************/ |
774 |
|
775 |
/* |
776 |
* Number of characters so far in this 'packet' |
777 |
*/ |
778 |
static int a_count; |
779 |
|
780 |
/* |
781 |
* Set up the 'byte output' routine |
782 |
*/ |
783 |
|
784 |
/* UNUSED |
785 |
* static void |
786 |
* char_init(void) |
787 |
* { |
788 |
* a_count = 0; |
789 |
* } |
790 |
*/ |
791 |
|
792 |
/* |
793 |
* Define the storage for the packet accumulator |
794 |
*/ |
795 |
|
796 |
/* UNUSED static char accum[ 256 ]; */ |
797 |
|
798 |
static void init_statics(void) { |
799 |
/* Some of these are properly initialized later. What I'm doing |
800 |
here is making sure code that depends on C's initialization |
801 |
of statics doesn't break when the code gets called more |
802 |
than once. */ |
803 |
Width = 0; |
804 |
Height = 0; |
805 |
curx = 0; |
806 |
cury = 0; |
807 |
CountDown = 0; |
808 |
Pass = 0; |
809 |
Interlace = 0; |
810 |
a_count = 0; |
811 |
} |
812 |
|
813 |
|
814 |
/* +-------------------------------------------------------------------+ */ |
815 |
/* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */ |
816 |
/* | Permission to use, copy, modify, and distribute this software | */ |
817 |
/* | and its documentation for any purpose and without fee is hereby | */ |
818 |
/* | granted, provided that the above copyright notice appear in all | */ |
819 |
/* | copies and that both that copyright notice and this permission | */ |
820 |
/* | notice appear in supporting documentation. This software is | */ |
821 |
/* | provided "as is" without express or implied warranty. | */ |
822 |
/* +-------------------------------------------------------------------+ */ |
823 |
|