source: trunk/tools/database/gd/gd.c@ 10367

Last change on this file since 10367 was 829, checked in by bird, 26 years ago

gifdraw (gd) v1.2 - initial checkin.

File size: 58.7 KB
Line 
1#include <malloc.h>
2#include <stdio.h>
3#include <math.h>
4#include <string.h>
5#include <stdlib.h>
6#include "gd.h"
7#include "mtables.c"
8
9static void gdImageBrushApply(gdImagePtr im, int x, int y);
10static void gdImageTileApply(gdImagePtr im, int x, int y);
11
12gdImagePtr gdImageCreate(int sx, int sy)
13{
14 int i;
15 gdImagePtr im;
16 im = (gdImage *) malloc(sizeof(gdImage));
17 im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx);
18 im->polyInts = 0;
19 im->polyAllocated = 0;
20 im->brush = 0;
21 im->tile = 0;
22 im->style = 0;
23 for (i=0; (i<sx); i++) {
24 im->pixels[i] = (unsigned char *) calloc(
25 sy, sizeof(unsigned char));
26 }
27 im->sx = sx;
28 im->sy = sy;
29 im->colorsTotal = 0;
30 im->transparent = (-1);
31 im->interlace = 0;
32 return im;
33}
34
35void gdImageDestroy(gdImagePtr im)
36{
37 int i;
38 for (i=0; (i<im->sx); i++) {
39 free(im->pixels[i]);
40 }
41 free(im->pixels);
42 if (im->polyInts) {
43 free(im->polyInts);
44 }
45 if (im->style) {
46 free(im->style);
47 }
48 free(im);
49}
50
51int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
52{
53 int i;
54 long rd, gd, bd;
55 int ct = (-1);
56 long mindist = 0;
57 for (i=0; (i<(im->colorsTotal)); i++) {
58 long dist;
59 if (im->open[i]) {
60 continue;
61 }
62 rd = (im->red[i] - r);
63 gd = (im->green[i] - g);
64 bd = (im->blue[i] - b);
65 dist = rd * rd + gd * gd + bd * bd;
66 if ((i == 0) || (dist < mindist)) {
67 mindist = dist;
68 ct = i;
69 }
70 }
71 return ct;
72}
73
74int gdImageColorExact(gdImagePtr im, int r, int g, int b)
75{
76 int i;
77 for (i=0; (i<(im->colorsTotal)); i++) {
78 if (im->open[i]) {
79 continue;
80 }
81 if ((im->red[i] == r) &&
82 (im->green[i] == g) &&
83 (im->blue[i] == b)) {
84 return i;
85 }
86 }
87 return -1;
88}
89
90int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
91{
92 int i;
93 int ct = (-1);
94 for (i=0; (i<(im->colorsTotal)); i++) {
95 if (im->open[i]) {
96 ct = i;
97 break;
98 }
99 }
100 if (ct == (-1)) {
101 ct = im->colorsTotal;
102 if (ct == gdMaxColors) {
103 return -1;
104 }
105 im->colorsTotal++;
106 }
107 im->red[ct] = r;
108 im->green[ct] = g;
109 im->blue[ct] = b;
110 im->open[ct] = 0;
111 return ct;
112}
113
114void gdImageColorDeallocate(gdImagePtr im, int color)
115{
116 /* Mark it open. */
117 im->open[color] = 1;
118}
119
120void gdImageColorTransparent(gdImagePtr im, int color)
121{
122 im->transparent = color;
123}
124
125void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
126{
127 int p;
128 switch(color) {
129 case gdStyled:
130 if (!im->style) {
131 /* Refuse to draw if no style is set. */
132 return;
133 } else {
134 p = im->style[im->stylePos++];
135 }
136 if (p != (gdTransparent)) {
137 gdImageSetPixel(im, x, y, p);
138 }
139 im->stylePos = im->stylePos % im->styleLength;
140 break;
141 case gdStyledBrushed:
142 if (!im->style) {
143 /* Refuse to draw if no style is set. */
144 return;
145 }
146 p = im->style[im->stylePos++];
147 if ((p != gdTransparent) && (p != 0)) {
148 gdImageSetPixel(im, x, y, gdBrushed);
149 }
150 im->stylePos = im->stylePos % im->styleLength;
151 break;
152 case gdBrushed:
153 gdImageBrushApply(im, x, y);
154 break;
155 case gdTiled:
156 gdImageTileApply(im, x, y);
157 break;
158 default:
159 if (gdImageBoundsSafe(im, x, y)) {
160 im->pixels[x][y] = color;
161 }
162 break;
163 }
164}
165
166static void gdImageBrushApply(gdImagePtr im, int x, int y)
167{
168 int lx, ly;
169 int hy;
170 int hx;
171 int x1, y1, x2, y2;
172 int srcx, srcy;
173 if (!im->brush) {
174 return;
175 }
176 hy = gdImageSY(im->brush)/2;
177 y1 = y - hy;
178 y2 = y1 + gdImageSY(im->brush);
179 hx = gdImageSX(im->brush)/2;
180 x1 = x - hx;
181 x2 = x1 + gdImageSX(im->brush);
182 srcy = 0;
183 for (ly = y1; (ly < y2); ly++) {
184 srcx = 0;
185 for (lx = x1; (lx < x2); lx++) {
186 int p;
187 p = gdImageGetPixel(im->brush, srcx, srcy);
188 /* Allow for non-square brushes! */
189 if (p != gdImageGetTransparent(im->brush)) {
190 gdImageSetPixel(im, lx, ly,
191 im->brushColorMap[p]);
192 }
193 srcx++;
194 }
195 srcy++;
196 }
197}
198
199static void gdImageTileApply(gdImagePtr im, int x, int y)
200{
201 int srcx, srcy;
202 int p;
203 if (!im->tile) {
204 return;
205 }
206 srcx = x % gdImageSX(im->tile);
207 srcy = y % gdImageSY(im->tile);
208 p = gdImageGetPixel(im->tile, srcx, srcy);
209 /* Allow for transparency */
210 if (p != gdImageGetTransparent(im->tile)) {
211 gdImageSetPixel(im, x, y,
212 im->tileColorMap[p]);
213 }
214}
215
216int gdImageGetPixel(gdImagePtr im, int x, int y)
217{
218 if (gdImageBoundsSafe(im, x, y)) {
219 return im->pixels[x][y];
220 } else {
221 return 0;
222 }
223}
224
225/* Bresenham as presented in Foley & Van Dam */
226
227void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
228{
229 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
230 dx = abs(x2-x1);
231 dy = abs(y2-y1);
232 if (dy <= dx) {
233 d = 2*dy - dx;
234 incr1 = 2*dy;
235 incr2 = 2 * (dy - dx);
236 if (x1 > x2) {
237 x = x2;
238 y = y2;
239 ydirflag = (-1);
240 xend = x1;
241 } else {
242 x = x1;
243 y = y1;
244 ydirflag = 1;
245 xend = x2;
246 }
247 gdImageSetPixel(im, x, y, color);
248 if (((y2 - y1) * ydirflag) > 0) {
249 while (x < xend) {
250 x++;
251 if (d <0) {
252 d+=incr1;
253 } else {
254 y++;
255 d+=incr2;
256 }
257 gdImageSetPixel(im, x, y, color);
258 }
259 } else {
260 while (x < xend) {
261 x++;
262 if (d <0) {
263 d+=incr1;
264 } else {
265 y--;
266 d+=incr2;
267 }
268 gdImageSetPixel(im, x, y, color);
269 }
270 }
271 } else {
272 d = 2*dx - dy;
273 incr1 = 2*dx;
274 incr2 = 2 * (dx - dy);
275 if (y1 > y2) {
276 y = y2;
277 x = x2;
278 yend = y1;
279 xdirflag = (-1);
280 } else {
281 y = y1;
282 x = x1;
283 yend = y2;
284 xdirflag = 1;
285 }
286 gdImageSetPixel(im, x, y, color);
287 if (((x2 - x1) * xdirflag) > 0) {
288 while (y < yend) {
289 y++;
290 if (d <0) {
291 d+=incr1;
292 } else {
293 x++;
294 d+=incr2;
295 }
296 gdImageSetPixel(im, x, y, color);
297 }
298 } else {
299 while (y < yend) {
300 y++;
301 if (d <0) {
302 d+=incr1;
303 } else {
304 x--;
305 d+=incr2;
306 }
307 gdImageSetPixel(im, x, y, color);
308 }
309 }
310 }
311}
312
313/* As above, plus dashing */
314
315#define dashedSet \
316 { \
317 dashStep++; \
318 if (dashStep == gdDashSize) { \
319 dashStep = 0; \
320 on = !on; \
321 } \
322 if (on) { \
323 gdImageSetPixel(im, x, y, color); \
324 } \
325 }
326
327void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
328{
329 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
330 int dashStep = 0;
331 int on = 1;
332 dx = abs(x2-x1);
333 dy = abs(y2-y1);
334 if (dy <= dx) {
335 d = 2*dy - dx;
336 incr1 = 2*dy;
337 incr2 = 2 * (dy - dx);
338 if (x1 > x2) {
339 x = x2;
340 y = y2;
341 ydirflag = (-1);
342 xend = x1;
343 } else {
344 x = x1;
345 y = y1;
346 ydirflag = 1;
347 xend = x2;
348 }
349 dashedSet;
350 if (((y2 - y1) * ydirflag) > 0) {
351 while (x < xend) {
352 x++;
353 if (d <0) {
354 d+=incr1;
355 } else {
356 y++;
357 d+=incr2;
358 }
359 dashedSet;
360 }
361 } else {
362 while (x < xend) {
363 x++;
364 if (d <0) {
365 d+=incr1;
366 } else {
367 y--;
368 d+=incr2;
369 }
370 dashedSet;
371 }
372 }
373 } else {
374 d = 2*dx - dy;
375 incr1 = 2*dx;
376 incr2 = 2 * (dx - dy);
377 if (y1 > y2) {
378 y = y2;
379 x = x2;
380 yend = y1;
381 xdirflag = (-1);
382 } else {
383 y = y1;
384 x = x1;
385 yend = y2;
386 xdirflag = 1;
387 }
388 dashedSet;
389 if (((x2 - x1) * xdirflag) > 0) {
390 while (y < yend) {
391 y++;
392 if (d <0) {
393 d+=incr1;
394 } else {
395 x++;
396 d+=incr2;
397 }
398 dashedSet;
399 }
400 } else {
401 while (y < yend) {
402 y++;
403 if (d <0) {
404 d+=incr1;
405 } else {
406 x--;
407 d+=incr2;
408 }
409 dashedSet;
410 }
411 }
412 }
413}
414
415int gdImageBoundsSafe(gdImagePtr im, int x, int y)
416{
417 return (!(((y < 0) || (y >= im->sy)) ||
418 ((x < 0) || (x >= im->sx))));
419}
420
421void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
422{
423 int cx, cy;
424 int px, py;
425 int fline;
426 cx = 0;
427 cy = 0;
428 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
429 return;
430 }
431 fline = (c - f->offset) * f->h * f->w;
432 for (py = y; (py < (y + f->h)); py++) {
433 for (px = x; (px < (x + f->w)); px++) {
434 if (f->data[fline + cy * f->w + cx]) {
435 gdImageSetPixel(im, px, py, color);
436 }
437 cx++;
438 }
439 cx = 0;
440 cy++;
441 }
442}
443
444void gdImageCharUp(gdImagePtr im, gdFontPtr f, int x, int y, char c, int color)
445{
446 int cx, cy;
447 int px, py;
448 int fline;
449 cx = 0;
450 cy = 0;
451 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
452 return;
453 }
454 fline = (c - f->offset) * f->h * f->w;
455 for (py = y; (py > (y - f->w)); py--) {
456 for (px = x; (px < (x + f->h)); px++) {
457 if (f->data[fline + cy * f->w + cx]) {
458 gdImageSetPixel(im, px, py, color);
459 }
460 cy++;
461 }
462 cy = 0;
463 cx++;
464 }
465}
466
467void gdImageString(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color)
468{
469 int i;
470 int l;
471 l = strlen(s);
472 for (i=0; (i<l); i++) {
473 gdImageChar(im, f, x, y, s[i], color);
474 x += f->w;
475 }
476}
477
478void gdImageStringUp(gdImagePtr im, gdFontPtr f, int x, int y, char *s, int color)
479{
480 int i;
481 int l;
482 l = strlen(s);
483 for (i=0; (i<l); i++) {
484 gdImageCharUp(im, f, x, y, s[i], color);
485 y -= f->w;
486 }
487}
488
489/* s and e are integers modulo 360 (degrees), with 0 degrees
490 being the rightmost extreme and degrees changing clockwise.
491 cx and cy are the center in pixels; w and h are the horizontal
492 and vertical diameter in pixels. Nice interface, but slow, since
493 I don't yet use Bresenham (I'm using an inefficient but
494 simple solution with too much work going on in it; generalizing
495 Bresenham to ellipses and partial arcs of ellipses is non-trivial,
496 at least for me) and there are other inefficiencies (small circles
497 do far too much work). */
498
499void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
500{
501 int i;
502 int lx = 0, ly = 0;
503 int w2, h2;
504 w2 = w/2;
505 h2 = h/2;
506 while (e < s) {
507 e += 360;
508 }
509 for (i=s; (i <= e); i++) {
510 int x, y;
511 x = ((long)cost[i % 360] * (long)w2 / costScale) + cx;
512 y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
513 if (i != s) {
514 gdImageLine(im, lx, ly, x, y, color);
515 }
516 lx = x;
517 ly = y;
518 }
519}
520
521
522#if 0
523 /* Bresenham octant code, which I should use eventually */
524 int x, y, d;
525 x = 0;
526 y = w;
527 d = 3-2*w;
528 while (x < y) {
529 gdImageSetPixel(im, cx+x, cy+y, color);
530 if (d < 0) {
531 d += 4 * x + 6;
532 } else {
533 d += 4 * (x - y) + 10;
534 y--;
535 }
536 x++;
537 }
538 if (x == y) {
539 gdImageSetPixel(im, cx+x, cy+y, color);
540 }
541#endif
542
543void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
544{
545 int lastBorder;
546 /* Seek left */
547 int leftLimit, rightLimit;
548 int i;
549 leftLimit = (-1);
550 if (border < 0) {
551 /* Refuse to fill to a non-solid border */
552 return;
553 }
554 for (i = x; (i >= 0); i--) {
555 if (gdImageGetPixel(im, i, y) == border) {
556 break;
557 }
558 gdImageSetPixel(im, i, y, color);
559 leftLimit = i;
560 }
561 if (leftLimit == (-1)) {
562 return;
563 }
564 /* Seek right */
565 rightLimit = x;
566 for (i = (x+1); (i < im->sx); i++) {
567 if (gdImageGetPixel(im, i, y) == border) {
568 break;
569 }
570 gdImageSetPixel(im, i, y, color);
571 rightLimit = i;
572 }
573 /* Look at lines above and below and start paints */
574 /* Above */
575 if (y > 0) {
576 lastBorder = 1;
577 for (i = leftLimit; (i <= rightLimit); i++) {
578 int c;
579 c = gdImageGetPixel(im, i, y-1);
580 if (lastBorder) {
581 if ((c != border) && (c != color)) {
582 gdImageFillToBorder(im, i, y-1,
583 border, color);
584 lastBorder = 0;
585 }
586 } else if ((c == border) || (c == color)) {
587 lastBorder = 1;
588 }
589 }
590 }
591 /* Below */
592 if (y < ((im->sy) - 1)) {
593 lastBorder = 1;
594 for (i = leftLimit; (i <= rightLimit); i++) {
595 int c;
596 c = gdImageGetPixel(im, i, y+1);
597 if (lastBorder) {
598 if ((c != border) && (c != color)) {
599 gdImageFillToBorder(im, i, y+1,
600 border, color);
601 lastBorder = 0;
602 }
603 } else if ((c == border) || (c == color)) {
604 lastBorder = 1;
605 }
606 }
607 }
608}
609
610void gdImageFill(gdImagePtr im, int x, int y, int color)
611{
612 int lastBorder;
613 int old;
614 int leftLimit, rightLimit;
615 int i;
616 old = gdImageGetPixel(im, x, y);
617 if (color == gdTiled) {
618 /* Tile fill -- got to watch out! */
619 int p, tileColor;
620 int srcx, srcy;
621 if (!im->tile) {
622 return;
623 }
624 /* Refuse to flood-fill with a transparent pattern --
625 I can't do it without allocating another image */
626 if (gdImageGetTransparent(im->tile) != (-1)) {
627 return;
628 }
629 srcx = x % gdImageSX(im->tile);
630 srcy = y % gdImageSY(im->tile);
631 p = gdImageGetPixel(im->tile, srcx, srcy);
632 tileColor = im->tileColorMap[p];
633 if (old == tileColor) {
634 /* Nothing to be done */
635 return;
636 }
637 } else {
638 if (old == color) {
639 /* Nothing to be done */
640 return;
641 }
642 }
643 /* Seek left */
644 leftLimit = (-1);
645 for (i = x; (i >= 0); i--) {
646 if (gdImageGetPixel(im, i, y) != old) {
647 break;
648 }
649 gdImageSetPixel(im, i, y, color);
650 leftLimit = i;
651 }
652 if (leftLimit == (-1)) {
653 return;
654 }
655 /* Seek right */
656 rightLimit = x;
657 for (i = (x+1); (i < im->sx); i++) {
658 if (gdImageGetPixel(im, i, y) != old) {
659 break;
660 }
661 gdImageSetPixel(im, i, y, color);
662 rightLimit = i;
663 }
664 /* Look at lines above and below and start paints */
665 /* Above */
666 if (y > 0) {
667 lastBorder = 1;
668 for (i = leftLimit; (i <= rightLimit); i++) {
669 int c;
670 c = gdImageGetPixel(im, i, y-1);
671 if (lastBorder) {
672 if (c == old) {
673 gdImageFill(im, i, y-1, color);
674 lastBorder = 0;
675 }
676 } else if (c != old) {
677 lastBorder = 1;
678 }
679 }
680 }
681 /* Below */
682 if (y < ((im->sy) - 1)) {
683 lastBorder = 1;
684 for (i = leftLimit; (i <= rightLimit); i++) {
685 int c;
686 c = gdImageGetPixel(im, i, y+1);
687 if (lastBorder) {
688 if (c == old) {
689 gdImageFill(im, i, y+1, color);
690 lastBorder = 0;
691 }
692 } else if (c != old) {
693 lastBorder = 1;
694 }
695 }
696 }
697}
698
699#ifdef TEST_CODE
700void gdImageDump(gdImagePtr im)
701{
702 int i, j;
703 for (i=0; (i < im->sy); i++) {
704 for (j=0; (j < im->sx); j++) {
705 printf("%d", im->pixels[j][i]);
706 }
707 printf("\n");
708 }
709}
710#endif
711
712/* Code drawn from ppmtogif.c, from the pbmplus package
713**
714** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
715** Lempel-Zim compression based on "compress".
716**
717** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
718**
719** Copyright (C) 1989 by Jef Poskanzer.
720**
721** Permission to use, copy, modify, and distribute this software and its
722** documentation for any purpose and without fee is hereby granted, provided
723** that the above copyright notice appear in all copies and that both that
724** copyright notice and this permission notice appear in supporting
725** documentation. This software is provided "as is" without express or
726** implied warranty.
727**
728** The Graphics Interchange Format(c) is the Copyright property of
729** CompuServe Incorporated. GIF(sm) is a Service Mark property of
730** CompuServe Incorporated.
731*/
732
733/*
734 * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
735 */
736typedef int code_int;
737
738#ifdef SIGNED_COMPARE_SLOW
739typedef unsigned long int count_int;
740typedef unsigned short int count_short;
741#else /*SIGNED_COMPARE_SLOW*/
742typedef long int count_int;
743#endif /*SIGNED_COMPARE_SLOW*/
744
745static int colorstobpp(int colors);
746static void BumpPixel (void);
747static int GIFNextPixel (gdImagePtr im);
748static void GIFEncode (FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im);
749static void Putword (int w, FILE *fp);
750static void compress (int init_bits, FILE *outfile, gdImagePtr im);
751static void output (code_int code);
752static void cl_block (void);
753static void cl_hash (register count_int hsize);
754static void char_init (void);
755static void char_out (int c);
756static void flush_char (void);
757/* Allows for reuse */
758static void init_statics(void);
759
760void gdImageGif(gdImagePtr im, FILE *out)
761{
762 int interlace, transparent, BitsPerPixel;
763 interlace = im->interlace;
764 transparent = im->transparent;
765
766 BitsPerPixel = colorstobpp(im->colorsTotal);
767 /* Clear any old values in statics strewn through the GIF code */
768 init_statics();
769 /* All set, let's do it. */
770 GIFEncode(
771 out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
772 im->red, im->green, im->blue, im);
773}
774
775static int
776colorstobpp(int colors)
777{
778 int bpp = 0;
779
780 if ( colors <= 2 )
781 bpp = 1;
782 else if ( colors <= 4 )
783 bpp = 2;
784 else if ( colors <= 8 )
785 bpp = 3;
786 else if ( colors <= 16 )
787 bpp = 4;
788 else if ( colors <= 32 )
789 bpp = 5;
790 else if ( colors <= 64 )
791 bpp = 6;
792 else if ( colors <= 128 )
793 bpp = 7;
794 else if ( colors <= 256 )
795 bpp = 8;
796 return bpp;
797 }
798
799/*****************************************************************************
800 *
801 * GIFENCODE.C - GIF Image compression interface
802 *
803 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
804 * BitsPerPixel, Red, Green, Blue, gdImagePtr )
805 *
806 *****************************************************************************/
807
808#define TRUE 1
809#define FALSE 0
810
811static int Width, Height;
812static int curx, cury;
813static long CountDown;
814static int Pass = 0;
815static int Interlace;
816
817/*
818 * Bump the 'curx' and 'cury' to point to the next pixel
819 */
820static void
821BumpPixel(void)
822{
823 /*
824 * Bump the current X position
825 */
826 ++curx;
827
828 /*
829 * If we are at the end of a scan line, set curx back to the beginning
830 * If we are interlaced, bump the cury to the appropriate spot,
831 * otherwise, just increment it.
832 */
833 if( curx == Width ) {
834 curx = 0;
835
836 if( !Interlace )
837 ++cury;
838 else {
839 switch( Pass ) {
840
841 case 0:
842 cury += 8;
843 if( cury >= Height ) {
844 ++Pass;
845 cury = 4;
846 }
847 break;
848
849 case 1:
850 cury += 8;
851 if( cury >= Height ) {
852 ++Pass;
853 cury = 2;
854 }
855 break;
856
857 case 2:
858 cury += 4;
859 if( cury >= Height ) {
860 ++Pass;
861 cury = 1;
862 }
863 break;
864
865 case 3:
866 cury += 2;
867 break;
868 }
869 }
870 }
871}
872
873/*
874 * Return the next pixel from the image
875 */
876static int
877GIFNextPixel(gdImagePtr im)
878{
879 int r;
880
881 if( CountDown == 0 )
882 return EOF;
883
884 --CountDown;
885
886 r = gdImageGetPixel(im, curx, cury);
887
888 BumpPixel();
889
890 return r;
891}
892
893/* public */
894
895static void
896GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
897{
898 int B;
899 int RWidth, RHeight;
900 int LeftOfs, TopOfs;
901 int Resolution;
902 int ColorMapSize;
903 int InitCodeSize;
904 int i;
905
906 Interlace = GInterlace;
907
908 ColorMapSize = 1 << BitsPerPixel;
909
910 RWidth = Width = GWidth;
911 RHeight = Height = GHeight;
912 LeftOfs = TopOfs = 0;
913
914 Resolution = BitsPerPixel;
915
916 /*
917 * Calculate number of bits we are expecting
918 */
919 CountDown = (long)Width * (long)Height;
920
921 /*
922 * Indicate which pass we are on (if interlace)
923 */
924 Pass = 0;
925
926 /*
927 * The initial code size
928 */
929 if( BitsPerPixel <= 1 )
930 InitCodeSize = 2;
931 else
932 InitCodeSize = BitsPerPixel;
933
934 /*
935 * Set up the current x and y position
936 */
937 curx = cury = 0;
938
939 /*
940 * Write the Magic header
941 */
942 fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
943
944 /*
945 * Write out the screen width and height
946 */
947 Putword( RWidth, fp );
948 Putword( RHeight, fp );
949
950 /*
951 * Indicate that there is a global colour map
952 */
953 B = 0x80; /* Yes, there is a color map */
954
955 /*
956 * OR in the resolution
957 */
958 B |= (Resolution - 1) << 5;
959
960 /*
961 * OR in the Bits per Pixel
962 */
963 B |= (BitsPerPixel - 1);
964
965 /*
966 * Write it out
967 */
968 fputc( B, fp );
969
970 /*
971 * Write out the Background colour
972 */
973 fputc( Background, fp );
974
975 /*
976 * Byte of 0's (future expansion)
977 */
978 fputc( 0, fp );
979
980 /*
981 * Write out the Global Colour Map
982 */
983 for( i=0; i<ColorMapSize; ++i ) {
984 fputc( Red[i], fp );
985 fputc( Green[i], fp );
986 fputc( Blue[i], fp );
987 }
988
989 /*
990 * Write out extension for transparent colour index, if necessary.
991 */
992 if ( Transparent >= 0 ) {
993 fputc( '!', fp );
994 fputc( 0xf9, fp );
995 fputc( 4, fp );
996 fputc( 1, fp );
997 fputc( 0, fp );
998 fputc( 0, fp );
999 fputc( (unsigned char) Transparent, fp );
1000 fputc( 0, fp );
1001 }
1002
1003 /*
1004 * Write an Image separator
1005 */
1006 fputc( ',', fp );
1007
1008 /*
1009 * Write the Image header
1010 */
1011
1012 Putword( LeftOfs, fp );
1013 Putword( TopOfs, fp );
1014 Putword( Width, fp );
1015 Putword( Height, fp );
1016
1017 /*
1018 * Write out whether or not the image is interlaced
1019 */
1020 if( Interlace )
1021 fputc( 0x40, fp );
1022 else
1023 fputc( 0x00, fp );
1024
1025 /*
1026 * Write out the initial code size
1027 */
1028 fputc( InitCodeSize, fp );
1029
1030 /*
1031 * Go and actually compress the data
1032 */
1033 compress( InitCodeSize+1, fp, im );
1034
1035 /*
1036 * Write out a Zero-length packet (to end the series)
1037 */
1038 fputc( 0, fp );
1039
1040 /*
1041 * Write the GIF file terminator
1042 */
1043 fputc( ';', fp );
1044}
1045
1046/*
1047 * Write out a word to the GIF file
1048 */
1049static void
1050Putword(int w, FILE *fp)
1051{
1052 fputc( w & 0xff, fp );
1053 fputc( (w / 256) & 0xff, fp );
1054}
1055
1056
1057/***************************************************************************
1058 *
1059 * GIFCOMPR.C - GIF Image compression routines
1060 *
1061 * Lempel-Ziv compression based on 'compress'. GIF modifications by
1062 * David Rowley (mgardi@watdcsu.waterloo.edu)
1063 *
1064 ***************************************************************************/
1065
1066/*
1067 * General DEFINEs
1068 */
1069
1070#define GIFBITS 12
1071
1072#define HSIZE 5003 /* 80% occupancy */
1073
1074#ifdef NO_UCHAR
1075 typedef char char_type;
1076#else /*NO_UCHAR*/
1077 typedef unsigned char char_type;
1078#endif /*NO_UCHAR*/
1079
1080/*
1081 *
1082 * GIF Image compression - modified 'compress'
1083 *
1084 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
1085 *
1086 * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
1087 * Jim McKie (decvax!mcvax!jim)
1088 * Steve Davies (decvax!vax135!petsd!peora!srd)
1089 * Ken Turkowski (decvax!decwrl!turtlevax!ken)
1090 * James A. Woods (decvax!ihnp4!ames!jaw)
1091 * Joe Orost (decvax!vax135!petsd!joe)
1092 *
1093 */
1094#include <ctype.h>
1095
1096#define ARGVAL() (*++(*argv) || (--argc && *++argv))
1097
1098static int n_bits; /* number of bits/code */
1099static int maxbits = GIFBITS; /* user settable max # bits/code */
1100static code_int maxcode; /* maximum code, given n_bits */
1101static code_int maxmaxcode = (code_int)1 << GIFBITS; /* should NEVER generate this code */
1102#ifdef COMPATIBLE /* But wrong! */
1103# define MAXCODE(n_bits) ((code_int) 1 << (n_bits) - 1)
1104#else /*COMPATIBLE*/
1105# define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
1106#endif /*COMPATIBLE*/
1107
1108static count_int htab [HSIZE];
1109static unsigned short codetab [HSIZE];
1110#define HashTabOf(i) htab[i]
1111#define CodeTabOf(i) codetab[i]
1112
1113static code_int hsize = HSIZE; /* for dynamic table sizing */
1114
1115/*
1116 * To save much memory, we overlay the table used by compress() with those
1117 * used by decompress(). The tab_prefix table is the same size and type
1118 * as the codetab. The tab_suffix table needs 2**GIFBITS characters. We
1119 * get this from the beginning of htab. The output stack uses the rest
1120 * of htab, and contains characters. There is plenty of room for any
1121 * possible stack (stack used to be 8000 characters).
1122 */
1123
1124#define tab_prefixof(i) CodeTabOf(i)
1125#define tab_suffixof(i) ((char_type*)(htab))[i]
1126#define de_stack ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
1127
1128static code_int free_ent = 0; /* first unused entry */
1129
1130/*
1131 * block compression parameters -- after all codes are used up,
1132 * and compression rate changes, start over.
1133 */
1134static int clear_flg = 0;
1135
1136static int offset;
1137static long int in_count = 1; /* length of input */
1138static long int out_count = 0; /* # of codes output (for debugging) */
1139
1140/*
1141 * compress stdin to stdout
1142 *
1143 * Algorithm: use open addressing double hashing (no chaining) on the
1144 * prefix code / next character combination. We do a variant of Knuth's
1145 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
1146 * secondary probe. Here, the modular division first probe is gives way
1147 * to a faster exclusive-or manipulation. Also do block compression with
1148 * an adaptive reset, whereby the code table is cleared when the compression
1149 * ratio decreases, but after the table fills. The variable-length output
1150 * codes are re-sized at this point, and a special CLEAR code is generated
1151 * for the decompressor. Late addition: construct the table according to
1152 * file size for noticeable speed improvement on small files. Please direct
1153 * questions about this implementation to ames!jaw.
1154 */
1155
1156static int g_init_bits;
1157static FILE* g_outfile;
1158
1159static int ClearCode;
1160static int EOFCode;
1161
1162static void
1163compress(int init_bits, FILE *outfile, gdImagePtr im)
1164{
1165 register long fcode;
1166 register code_int i /* = 0 */;
1167 register int c;
1168 register code_int ent;
1169 register code_int disp;
1170 register code_int hsize_reg;
1171 register int hshift;
1172
1173 /*
1174 * Set up the globals: g_init_bits - initial number of bits
1175 * g_outfile - pointer to output file
1176 */
1177 g_init_bits = init_bits;
1178 g_outfile = outfile;
1179
1180 /*
1181 * Set up the necessary values
1182 */
1183 offset = 0;
1184 out_count = 0;
1185 clear_flg = 0;
1186 in_count = 1;
1187 maxcode = MAXCODE(n_bits = g_init_bits);
1188
1189 ClearCode = (1 << (init_bits - 1));
1190 EOFCode = ClearCode + 1;
1191 free_ent = ClearCode + 2;
1192
1193 char_init();
1194
1195 ent = GIFNextPixel( im );
1196
1197 hshift = 0;
1198 for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
1199 ++hshift;
1200 hshift = 8 - hshift; /* set hash code range bound */
1201
1202 hsize_reg = hsize;
1203 cl_hash( (count_int) hsize_reg); /* clear hash table */
1204
1205 output( (code_int)ClearCode );
1206
1207#ifdef SIGNED_COMPARE_SLOW
1208 while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
1209#else /*SIGNED_COMPARE_SLOW*/
1210 while ( (c = GIFNextPixel( im )) != EOF ) { /* } */
1211#endif /*SIGNED_COMPARE_SLOW*/
1212
1213 ++in_count;
1214
1215 fcode = (long) (((long) c << maxbits) + ent);
1216 i = (((code_int)c << hshift) ^ ent); /* xor hashing */
1217
1218 if ( HashTabOf (i) == fcode ) {
1219 ent = CodeTabOf (i);
1220 continue;
1221 } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
1222 goto nomatch;
1223 disp = hsize_reg - i; /* secondary hash (after G. Knott) */
1224 if ( i == 0 )
1225 disp = 1;
1226probe:
1227 if ( (i -= disp) < 0 )
1228 i += hsize_reg;
1229
1230 if ( HashTabOf (i) == fcode ) {
1231 ent = CodeTabOf (i);
1232 continue;
1233 }
1234 if ( (long)HashTabOf (i) > 0 )
1235 goto probe;
1236nomatch:
1237 output ( (code_int) ent );
1238 ++out_count;
1239 ent = c;
1240#ifdef SIGNED_COMPARE_SLOW
1241 if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
1242#else /*SIGNED_COMPARE_SLOW*/
1243 if ( free_ent < maxmaxcode ) { /* } */
1244#endif /*SIGNED_COMPARE_SLOW*/
1245 CodeTabOf (i) = free_ent++; /* code -> hashtable */
1246 HashTabOf (i) = fcode;
1247 } else
1248 cl_block();
1249 }
1250 /*
1251 * Put out the final code.
1252 */
1253 output( (code_int)ent );
1254 ++out_count;
1255 output( (code_int) EOFCode );
1256}
1257
1258/*****************************************************************
1259 * TAG( output )
1260 *
1261 * Output the given code.
1262 * Inputs:
1263 * code: A n_bits-bit integer. If == -1, then EOF. This assumes
1264 * that n_bits =< (long)wordsize - 1.
1265 * Outputs:
1266 * Outputs code to the file.
1267 * Assumptions:
1268 * Chars are 8 bits long.
1269 * Algorithm:
1270 * Maintain a GIFBITS character long buffer (so that 8 codes will
1271 * fit in it exactly). Use the VAX insv instruction to insert each
1272 * code in turn. When the buffer fills up empty it and start over.
1273 */
1274
1275static unsigned long cur_accum = 0;
1276static int cur_bits = 0;
1277
1278static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
1279 0x001F, 0x003F, 0x007F, 0x00FF,
1280 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
1281 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
1282
1283static void
1284output(code_int code)
1285{
1286 cur_accum &= masks[ cur_bits ];
1287
1288 if( cur_bits > 0 )
1289 cur_accum |= ((long)code << cur_bits);
1290 else
1291 cur_accum = code;
1292
1293 cur_bits += n_bits;
1294
1295 while( cur_bits >= 8 ) {
1296 char_out( (unsigned int)(cur_accum & 0xff) );
1297 cur_accum >>= 8;
1298 cur_bits -= 8;
1299 }
1300
1301 /*
1302 * If the next entry is going to be too big for the code size,
1303 * then increase it, if possible.
1304 */
1305 if ( free_ent > maxcode || clear_flg ) {
1306
1307 if( clear_flg ) {
1308
1309 maxcode = MAXCODE (n_bits = g_init_bits);
1310 clear_flg = 0;
1311
1312 } else {
1313
1314 ++n_bits;
1315 if ( n_bits == maxbits )
1316 maxcode = maxmaxcode;
1317 else
1318 maxcode = MAXCODE(n_bits);
1319 }
1320 }
1321
1322 if( code == EOFCode ) {
1323 /*
1324 * At EOF, write the rest of the buffer.
1325 */
1326 while( cur_bits > 0 ) {
1327 char_out( (unsigned int)(cur_accum & 0xff) );
1328 cur_accum >>= 8;
1329 cur_bits -= 8;
1330 }
1331
1332 flush_char();
1333
1334 fflush( g_outfile );
1335
1336 if( ferror( g_outfile ) )
1337 return;
1338 }
1339}
1340
1341/*
1342 * Clear out the hash table
1343 */
1344static void
1345cl_block (void) /* table clear for block compress */
1346{
1347
1348 cl_hash ( (count_int) hsize );
1349 free_ent = ClearCode + 2;
1350 clear_flg = 1;
1351
1352 output( (code_int)ClearCode );
1353}
1354
1355static void
1356cl_hash(register count_int hsize) /* reset code table */
1357
1358{
1359
1360 register count_int *htab_p = htab+hsize;
1361
1362 register long i;
1363 register long m1 = -1;
1364
1365 i = hsize - 16;
1366 do { /* might use Sys V memset(3) here */
1367 *(htab_p-16) = m1;
1368 *(htab_p-15) = m1;
1369 *(htab_p-14) = m1;
1370 *(htab_p-13) = m1;
1371 *(htab_p-12) = m1;
1372 *(htab_p-11) = m1;
1373 *(htab_p-10) = m1;
1374 *(htab_p-9) = m1;
1375 *(htab_p-8) = m1;
1376 *(htab_p-7) = m1;
1377 *(htab_p-6) = m1;
1378 *(htab_p-5) = m1;
1379 *(htab_p-4) = m1;
1380 *(htab_p-3) = m1;
1381 *(htab_p-2) = m1;
1382 *(htab_p-1) = m1;
1383 htab_p -= 16;
1384 } while ((i -= 16) >= 0);
1385
1386 for ( i += 16; i > 0; --i )
1387 *--htab_p = m1;
1388}
1389
1390/******************************************************************************
1391 *
1392 * GIF Specific routines
1393 *
1394 ******************************************************************************/
1395
1396/*
1397 * Number of characters so far in this 'packet'
1398 */
1399static int a_count;
1400
1401/*
1402 * Set up the 'byte output' routine
1403 */
1404static void
1405char_init(void)
1406{
1407 a_count = 0;
1408}
1409
1410/*
1411 * Define the storage for the packet accumulator
1412 */
1413static char accum[ 256 ];
1414
1415/*
1416 * Add a character to the end of the current packet, and if it is 254
1417 * characters, flush the packet to disk.
1418 */
1419static void
1420char_out(int c)
1421{
1422 accum[ a_count++ ] = c;
1423 if( a_count >= 254 )
1424 flush_char();
1425}
1426
1427/*
1428 * Flush the packet to disk, and reset the accumulator
1429 */
1430static void
1431flush_char(void)
1432{
1433 if( a_count > 0 ) {
1434 fputc( a_count, g_outfile );
1435 fwrite( accum, 1, a_count, g_outfile );
1436 a_count = 0;
1437 }
1438}
1439
1440static void init_statics(void) {
1441 /* Some of these are properly initialized later. What I'm doing
1442 here is making sure code that depends on C's initialization
1443 of statics doesn't break when the code gets called more
1444 than once. */
1445 Width = 0;
1446 Height = 0;
1447 curx = 0;
1448 cury = 0;
1449 CountDown = 0;
1450 Pass = 0;
1451 Interlace = 0;
1452 a_count = 0;
1453 cur_accum = 0;
1454 cur_bits = 0;
1455 g_init_bits = 0;
1456 g_outfile = 0;
1457 ClearCode = 0;
1458 EOFCode = 0;
1459 free_ent = 0;
1460 clear_flg = 0;
1461 offset = 0;
1462 in_count = 1;
1463 out_count = 0;
1464 hsize = HSIZE;
1465 n_bits = 0;
1466 maxbits = GIFBITS;
1467 maxcode = 0;
1468 maxmaxcode = (code_int)1 << GIFBITS;
1469}
1470
1471
1472/* +-------------------------------------------------------------------+ */
1473/* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */
1474/* | Permission to use, copy, modify, and distribute this software | */
1475/* | and its documentation for any purpose and without fee is hereby | */
1476/* | granted, provided that the above copyright notice appear in all | */
1477/* | copies and that both that copyright notice and this permission | */
1478/* | notice appear in supporting documentation. This software is | */
1479/* | provided "as is" without express or implied warranty. | */
1480/* +-------------------------------------------------------------------+ */
1481
1482
1483#define MAXCOLORMAPSIZE 256
1484
1485#define TRUE 1
1486#define FALSE 0
1487
1488#define CM_RED 0
1489#define CM_GREEN 1
1490#define CM_BLUE 2
1491
1492#define MAX_LWZ_BITS 12
1493
1494#define INTERLACE 0x40
1495#define LOCALCOLORMAP 0x80
1496#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
1497
1498#define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
1499
1500#define LM_to_uint(a,b) (((b)<<8)|(a))
1501
1502/* We may eventually want to use this information, but def it out for now */
1503#if 0
1504static struct {
1505 unsigned int Width;
1506 unsigned int Height;
1507 unsigned char ColorMap[3][MAXCOLORMAPSIZE];
1508 unsigned int BitPixel;
1509 unsigned int ColorResolution;
1510 unsigned int Background;
1511 unsigned int AspectRatio;
1512} GifScreen;
1513#endif
1514
1515static struct {
1516 int transparent;
1517 int delayTime;
1518 int inputFlag;
1519 int disposal;
1520} Gif89 = { -1, -1, -1, 0 };
1521
1522static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
1523static int DoExtension (FILE *fd, int label, int *Transparent);
1524static int GetDataBlock (FILE *fd, unsigned char *buf);
1525static int GetCode (FILE *fd, int code_size, int flag);
1526static int LWZReadByte (FILE *fd, int flag, int input_code_size);
1527static void ReadImage (gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore);
1528
1529int ZeroDataBlock;
1530
1531gdImagePtr
1532gdImageCreateFromGif(FILE *fd)
1533{
1534 int imageNumber;
1535 int BitPixel;
1536 int ColorResolution;
1537 int Background;
1538 int AspectRatio;
1539 int Transparent = (-1);
1540 unsigned char buf[16];
1541 unsigned char c;
1542 unsigned char ColorMap[3][MAXCOLORMAPSIZE];
1543 unsigned char localColorMap[3][MAXCOLORMAPSIZE];
1544 int imw, imh;
1545 int useGlobalColormap;
1546 int bitPixel;
1547 int imageCount = 0;
1548 char version[4];
1549 gdImagePtr im = 0;
1550 ZeroDataBlock = FALSE;
1551
1552 imageNumber = 1;
1553 if (! ReadOK(fd,buf,6)) {
1554 return 0;
1555 }
1556 if (strncmp((char *)buf,"GIF",3) != 0) {
1557 return 0;
1558 }
1559 strncpy(version, (char *)buf + 3, 3);
1560 version[3] = '\0';
1561
1562 if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
1563 return 0;
1564 }
1565 if (! ReadOK(fd,buf,7)) {
1566 return 0;
1567 }
1568 BitPixel = 2<<(buf[4]&0x07);
1569 ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
1570 Background = buf[5];
1571 AspectRatio = buf[6];
1572
1573 if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
1574 if (ReadColorMap(fd, BitPixel, ColorMap)) {
1575 return 0;
1576 }
1577 }
1578 for (;;) {
1579 if (! ReadOK(fd,&c,1)) {
1580 return 0;
1581 }
1582 if (c == ';') { /* GIF terminator */
1583 int i;
1584 if (imageCount < imageNumber) {
1585 return 0;
1586 }
1587 /* Terminator before any image was declared! */
1588 if (!im) {
1589 return 0;
1590 }
1591 /* Check for open colors at the end, so
1592 we can reduce colorsTotal and ultimately
1593 BitsPerPixel */
1594 for (i=((im->colorsTotal-1)); (i>=0); i--) {
1595 if (im->open[i]) {
1596 im->colorsTotal--;
1597 } else {
1598 break;
1599 }
1600 }
1601 return im;
1602 }
1603
1604 if (c == '!') { /* Extension */
1605 if (! ReadOK(fd,&c,1)) {
1606 return 0;
1607 }
1608 DoExtension(fd, c, &Transparent);
1609 continue;
1610 }
1611
1612 if (c != ',') { /* Not a valid start character */
1613 continue;
1614 }
1615
1616 ++imageCount;
1617
1618 if (! ReadOK(fd,buf,9)) {
1619 return 0;
1620 }
1621
1622 useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
1623
1624 bitPixel = 1<<((buf[8]&0x07)+1);
1625
1626 imw = LM_to_uint(buf[4],buf[5]);
1627 imh = LM_to_uint(buf[6],buf[7]);
1628 if (!(im = gdImageCreate(imw, imh))) {
1629 return 0;
1630 }
1631 im->interlace = BitSet(buf[8], INTERLACE);
1632 if (! useGlobalColormap) {
1633 if (ReadColorMap(fd, bitPixel, localColorMap)) {
1634 return 0;
1635 }
1636 ReadImage(im, fd, imw, imh, localColorMap,
1637 BitSet(buf[8], INTERLACE),
1638 imageCount != imageNumber);
1639 } else {
1640 ReadImage(im, fd, imw, imh,
1641 ColorMap,
1642 BitSet(buf[8], INTERLACE),
1643 imageCount != imageNumber);
1644 }
1645 if (Transparent != (-1)) {
1646 gdImageColorTransparent(im, Transparent);
1647 }
1648 }
1649}
1650
1651static int
1652ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
1653{
1654 int i;
1655 unsigned char rgb[3];
1656
1657
1658 for (i = 0; i < number; ++i) {
1659 if (! ReadOK(fd, rgb, sizeof(rgb))) {
1660 return TRUE;
1661 }
1662 buffer[CM_RED][i] = rgb[0] ;
1663 buffer[CM_GREEN][i] = rgb[1] ;
1664 buffer[CM_BLUE][i] = rgb[2] ;
1665 }
1666
1667
1668 return FALSE;
1669}
1670
1671static int
1672DoExtension(FILE *fd, int label, int *Transparent)
1673{
1674 static unsigned char buf[256];
1675
1676 switch (label) {
1677 case 0xf9: /* Graphic Control Extension */
1678 (void) GetDataBlock(fd, (unsigned char*) buf);
1679 Gif89.disposal = (buf[0] >> 2) & 0x7;
1680 Gif89.inputFlag = (buf[0] >> 1) & 0x1;
1681 Gif89.delayTime = LM_to_uint(buf[1],buf[2]);
1682 if ((buf[0] & 0x1) != 0)
1683 *Transparent = buf[3];
1684
1685 while (GetDataBlock(fd, (unsigned char*) buf) != 0)
1686 ;
1687 return FALSE;
1688 default:
1689 break;
1690 }
1691 while (GetDataBlock(fd, (unsigned char*) buf) != 0)
1692 ;
1693
1694 return FALSE;
1695}
1696
1697static int
1698GetDataBlock(FILE *fd, unsigned char *buf)
1699{
1700 unsigned char count;
1701
1702 if (! ReadOK(fd,&count,1)) {
1703 return -1;
1704 }
1705
1706 ZeroDataBlock = count == 0;
1707
1708 if ((count != 0) && (! ReadOK(fd, buf, count))) {
1709 return -1;
1710 }
1711
1712 return count;
1713}
1714
1715static int
1716GetCode(FILE *fd, int code_size, int flag)
1717{
1718 static unsigned char buf[280];
1719 static int curbit, lastbit, done, last_byte;
1720 int i, j, ret;
1721 unsigned char count;
1722
1723 if (flag) {
1724 curbit = 0;
1725 lastbit = 0;
1726 done = FALSE;
1727 return 0;
1728 }
1729
1730 if ( (curbit+code_size) >= lastbit) {
1731 if (done) {
1732 if (curbit >= lastbit) {
1733 /* Oh well */
1734 }
1735 return -1;
1736 }
1737 buf[0] = buf[last_byte-2];
1738 buf[1] = buf[last_byte-1];
1739
1740 if ((count = GetDataBlock(fd, &buf[2])) == 0)
1741 done = TRUE;
1742
1743 last_byte = 2 + count;
1744 curbit = (curbit - lastbit) + 16;
1745 lastbit = (2+count)*8 ;
1746 }
1747
1748 ret = 0;
1749 for (i = curbit, j = 0; j < code_size; ++i, ++j)
1750 ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
1751
1752 curbit += code_size;
1753
1754 return ret;
1755}
1756
1757static int
1758LWZReadByte(FILE *fd, int flag, int input_code_size)
1759{
1760 static int fresh = FALSE;
1761 int code, incode;
1762 static int code_size, set_code_size;
1763 static int max_code, max_code_size;
1764 static int firstcode, oldcode;
1765 static int clear_code, end_code;
1766 static int table[2][(1<< MAX_LWZ_BITS)];
1767 static int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
1768 register int i;
1769
1770 if (flag) {
1771 set_code_size = input_code_size;
1772 code_size = set_code_size+1;
1773 clear_code = 1 << set_code_size ;
1774 end_code = clear_code + 1;
1775 max_code_size = 2*clear_code;
1776 max_code = clear_code+2;
1777
1778 GetCode(fd, 0, TRUE);
1779
1780 fresh = TRUE;
1781
1782 for (i = 0; i < clear_code; ++i) {
1783 table[0][i] = 0;
1784 table[1][i] = i;
1785 }
1786 for (; i < (1<<MAX_LWZ_BITS); ++i)
1787 table[0][i] = table[1][0] = 0;
1788
1789 sp = stack;
1790
1791 return 0;
1792 } else if (fresh) {
1793 fresh = FALSE;
1794 do {
1795 firstcode = oldcode =
1796 GetCode(fd, code_size, FALSE);
1797 } while (firstcode == clear_code);
1798 return firstcode;
1799 }
1800
1801 if (sp > stack)
1802 return *--sp;
1803
1804 while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
1805 if (code == clear_code) {
1806 for (i = 0; i < clear_code; ++i) {
1807 table[0][i] = 0;
1808 table[1][i] = i;
1809 }
1810 for (; i < (1<<MAX_LWZ_BITS); ++i)
1811 table[0][i] = table[1][i] = 0;
1812 code_size = set_code_size+1;
1813 max_code_size = 2*clear_code;
1814 max_code = clear_code+2;
1815 sp = stack;
1816 firstcode = oldcode =
1817 GetCode(fd, code_size, FALSE);
1818 return firstcode;
1819 } else if (code == end_code) {
1820 int count;
1821 unsigned char buf[260];
1822
1823 if (ZeroDataBlock)
1824 return -2;
1825
1826 while ((count = GetDataBlock(fd, buf)) > 0)
1827 ;
1828
1829 if (count != 0)
1830 return -2;
1831 }
1832
1833 incode = code;
1834
1835 if (code >= max_code) {
1836 *sp++ = firstcode;
1837 code = oldcode;
1838 }
1839
1840 while (code >= clear_code) {
1841 *sp++ = table[1][code];
1842 if (code == table[0][code]) {
1843 /* Oh well */
1844 }
1845 code = table[0][code];
1846 }
1847
1848 *sp++ = firstcode = table[1][code];
1849
1850 if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
1851 table[0][code] = oldcode;
1852 table[1][code] = firstcode;
1853 ++max_code;
1854 if ((max_code >= max_code_size) &&
1855 (max_code_size < (1<<MAX_LWZ_BITS))) {
1856 max_code_size *= 2;
1857 ++code_size;
1858 }
1859 }
1860
1861 oldcode = incode;
1862
1863 if (sp > stack)
1864 return *--sp;
1865 }
1866 return code;
1867}
1868
1869static void
1870ReadImage(gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore)
1871{
1872 unsigned char c;
1873 int v;
1874 int xpos = 0, ypos = 0, pass = 0;
1875 int i;
1876 /* Stash the color map into the image */
1877 for (i=0; (i<gdMaxColors); i++) {
1878 im->red[i] = cmap[CM_RED][i];
1879 im->green[i] = cmap[CM_GREEN][i];
1880 im->blue[i] = cmap[CM_BLUE][i];
1881 im->open[i] = 1;
1882 }
1883 /* Many (perhaps most) of these colors will remain marked open. */
1884 im->colorsTotal = gdMaxColors;
1885 /*
1886 ** Initialize the Compression routines
1887 */
1888 if (! ReadOK(fd,&c,1)) {
1889 return;
1890 }
1891 if (LWZReadByte(fd, TRUE, c) < 0) {
1892 return;
1893 }
1894
1895 /*
1896 ** If this is an "uninteresting picture" ignore it.
1897 */
1898 if (ignore) {
1899 while (LWZReadByte(fd, FALSE, c) >= 0)
1900 ;
1901 return;
1902 }
1903
1904 while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
1905 /* This how we recognize which colors are actually used. */
1906 if (im->open[v]) {
1907 im->open[v] = 0;
1908 }
1909 gdImageSetPixel(im, xpos, ypos, v);
1910 ++xpos;
1911 if (xpos == len) {
1912 xpos = 0;
1913 if (interlace) {
1914 switch (pass) {
1915 case 0:
1916 case 1:
1917 ypos += 8; break;
1918 case 2:
1919 ypos += 4; break;
1920 case 3:
1921 ypos += 2; break;
1922 }
1923
1924 if (ypos >= height) {
1925 ++pass;
1926 switch (pass) {
1927 case 1:
1928 ypos = 4; break;
1929 case 2:
1930 ypos = 2; break;
1931 case 3:
1932 ypos = 1; break;
1933 default:
1934 goto fini;
1935 }
1936 }
1937 } else {
1938 ++ypos;
1939 }
1940 }
1941 if (ypos >= height)
1942 break;
1943 }
1944
1945fini:
1946 if (LWZReadByte(fd,FALSE,c)>=0) {
1947 /* Ignore extra */
1948 }
1949}
1950
1951void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1952{
1953 gdImageLine(im, x1, y1, x2, y1, color);
1954 gdImageLine(im, x1, y2, x2, y2, color);
1955 gdImageLine(im, x1, y1, x1, y2, color);
1956 gdImageLine(im, x2, y1, x2, y2, color);
1957}
1958
1959void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1960{
1961 int x, y;
1962 for (y=y1; (y<=y2); y++) {
1963 for (x=x1; (x<=x2); x++) {
1964 gdImageSetPixel(im, x, y, color);
1965 }
1966 }
1967}
1968
1969void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
1970{
1971 int c;
1972 int x, y;
1973 int tox, toy;
1974 int i;
1975 int colorMap[gdMaxColors];
1976 for (i=0; (i<gdMaxColors); i++) {
1977 colorMap[i] = (-1);
1978 }
1979 toy = dstY;
1980 for (y=srcY; (y < (srcY + h)); y++) {
1981 tox = dstX;
1982 for (x=srcX; (x < (srcX + w)); x++) {
1983 int nc;
1984 c = gdImageGetPixel(src, x, y);
1985 /* Added 7/24/95: support transparent copies */
1986 if (gdImageGetTransparent(src) == c) {
1987 tox++;
1988 continue;
1989 }
1990 /* Have we established a mapping for this color? */
1991 if (colorMap[c] == (-1)) {
1992 /* If it's the same image, mapping is trivial */
1993 if (dst == src) {
1994 nc = c;
1995 } else {
1996 /* First look for an exact match */
1997 nc = gdImageColorExact(dst,
1998 src->red[c], src->green[c],
1999 src->blue[c]);
2000 }
2001 if (nc == (-1)) {
2002 /* No, so try to allocate it */
2003 nc = gdImageColorAllocate(dst,
2004 src->red[c], src->green[c],
2005 src->blue[c]);
2006 /* If we're out of colors, go for the
2007 closest color */
2008 if (nc == (-1)) {
2009 nc = gdImageColorClosest(dst,
2010 src->red[c], src->green[c],
2011 src->blue[c]);
2012 }
2013 }
2014 colorMap[c] = nc;
2015 }
2016 gdImageSetPixel(dst, tox, toy, colorMap[c]);
2017 tox++;
2018 }
2019 toy++;
2020 }
2021}
2022
2023void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
2024{
2025 int c;
2026 int x, y;
2027 int tox, toy;
2028 int ydest;
2029 int i;
2030 int colorMap[gdMaxColors];
2031 /* Stretch vectors */
2032 int *stx;
2033 int *sty;
2034 /* We only need to use floating point to determine the correct
2035 stretch vector for one line's worth. */
2036 double accum;
2037 stx = (int *) malloc(sizeof(int) * srcW);
2038 sty = (int *) malloc(sizeof(int) * srcH);
2039 accum = 0;
2040 for (i=0; (i < srcW); i++) {
2041 int got;
2042 accum += (double)dstW/(double)srcW;
2043 got = floor(accum);
2044 stx[i] = got;
2045 accum -= got;
2046 }
2047 accum = 0;
2048 for (i=0; (i < srcH); i++) {
2049 int got;
2050 accum += (double)dstH/(double)srcH;
2051 got = floor(accum);
2052 sty[i] = got;
2053 accum -= got;
2054 }
2055 for (i=0; (i<gdMaxColors); i++) {
2056 colorMap[i] = (-1);
2057 }
2058 toy = dstY;
2059 for (y=srcY; (y < (srcY + srcH)); y++) {
2060 for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
2061 tox = dstX;
2062 for (x=srcX; (x < (srcX + srcW)); x++) {
2063 int nc;
2064 if (!stx[x - srcX]) {
2065 continue;
2066 }
2067 c = gdImageGetPixel(src, x, y);
2068 /* Added 7/24/95: support transparent copies */
2069 if (gdImageGetTransparent(src) == c) {
2070 tox += stx[x-srcX];
2071 continue;
2072 }
2073 /* Have we established a mapping for this color? */
2074 if (colorMap[c] == (-1)) {
2075 /* If it's the same image, mapping is trivial */
2076 if (dst == src) {
2077 nc = c;
2078 } else {
2079 /* First look for an exact match */
2080 nc = gdImageColorExact(dst,
2081 src->red[c], src->green[c],
2082 src->blue[c]);
2083 }
2084 if (nc == (-1)) {
2085 /* No, so try to allocate it */
2086 nc = gdImageColorAllocate(dst,
2087 src->red[c], src->green[c],
2088 src->blue[c]);
2089 /* If we're out of colors, go for the
2090 closest color */
2091 if (nc == (-1)) {
2092 nc = gdImageColorClosest(dst,
2093 src->red[c], src->green[c],
2094 src->blue[c]);
2095 }
2096 }
2097 colorMap[c] = nc;
2098 }
2099 for (i=0; (i < stx[x - srcX]); i++) {
2100 gdImageSetPixel(dst, tox, toy, colorMap[c]);
2101 tox++;
2102 }
2103 }
2104 toy++;
2105 }
2106 }
2107 free(stx);
2108 free(sty);
2109}
2110
2111int gdGetWord(int *result, FILE *in)
2112{
2113 int r;
2114 r = getc(in);
2115 if (r == EOF) {
2116 return 0;
2117 }
2118 *result = r << 8;
2119 r = getc(in);
2120 if (r == EOF) {
2121 return 0;
2122 }
2123 *result += r;
2124 return 1;
2125}
2126
2127void gdPutWord(int w, FILE *out)
2128{
2129 putc((unsigned char)(w >> 8), out);
2130 putc((unsigned char)(w & 0xFF), out);
2131}
2132
2133int gdGetByte(int *result, FILE *in)
2134{
2135 int r;
2136 r = getc(in);
2137 if (r == EOF) {
2138 return 0;
2139 }
2140 *result = r;
2141 return 1;
2142}
2143
2144gdImagePtr gdImageCreateFromGd(FILE *in)
2145{
2146 int sx, sy;
2147 int x, y;
2148 int i;
2149 gdImagePtr im;
2150 if (!gdGetWord(&sx, in)) {
2151 goto fail1;
2152 }
2153 if (!gdGetWord(&sy, in)) {
2154 goto fail1;
2155 }
2156 im = gdImageCreate(sx, sy);
2157 if (!gdGetByte(&im->colorsTotal, in)) {
2158 goto fail2;
2159 }
2160 if (!gdGetWord(&im->transparent, in)) {
2161 goto fail2;
2162 }
2163 if (im->transparent == 257) {
2164 im->transparent = (-1);
2165 }
2166 for (i=0; (i<gdMaxColors); i++) {
2167 if (!gdGetByte(&im->red[i], in)) {
2168 goto fail2;
2169 }
2170 if (!gdGetByte(&im->green[i], in)) {
2171 goto fail2;
2172 }
2173 if (!gdGetByte(&im->blue[i], in)) {
2174 goto fail2;
2175 }
2176 }
2177 for (y=0; (y<sy); y++) {
2178 for (x=0; (x<sx); x++) {
2179 int ch;
2180 ch = getc(in);
2181 if (ch == EOF) {
2182 gdImageDestroy(im);
2183 return 0;
2184 }
2185 im->pixels[x][y] = ch;
2186 }
2187 }
2188 return im;
2189fail2:
2190 gdImageDestroy(im);
2191fail1:
2192 return 0;
2193}
2194
2195void gdImageGd(gdImagePtr im, FILE *out)
2196{
2197 int x, y;
2198 int i;
2199 int trans;
2200 gdPutWord(im->sx, out);
2201 gdPutWord(im->sy, out);
2202 putc((unsigned char)im->colorsTotal, out);
2203 trans = im->transparent;
2204 if (trans == (-1)) {
2205 trans = 257;
2206 }
2207 gdPutWord(trans, out);
2208 for (i=0; (i<gdMaxColors); i++) {
2209 putc((unsigned char)im->red[i], out);
2210 putc((unsigned char)im->green[i], out);
2211 putc((unsigned char)im->blue[i], out);
2212 }
2213 for (y=0; (y < im->sy); y++) {
2214 for (x=0; (x < im->sx); x++) {
2215 putc((unsigned char)im->pixels[x][y], out);
2216 }
2217 }
2218}
2219
2220gdImagePtr
2221gdImageCreateFromXbm(FILE *fd)
2222{
2223 gdImagePtr im;
2224 int bit;
2225 int w, h;
2226 int bytes;
2227 int ch;
2228 int i, x, y;
2229 char *sp;
2230 char s[161];
2231 if (!fgets(s, 160, fd)) {
2232 return 0;
2233 }
2234 sp = &s[0];
2235 /* Skip #define */
2236 sp = strchr(sp, ' ');
2237 if (!sp) {
2238 return 0;
2239 }
2240 /* Skip width label */
2241 sp++;
2242 sp = strchr(sp, ' ');
2243 if (!sp) {
2244 return 0;
2245 }
2246 /* Get width */
2247 w = atoi(sp + 1);
2248 if (!w) {
2249 return 0;
2250 }
2251 if (!fgets(s, 160, fd)) {
2252 return 0;
2253 }
2254 sp = s;
2255 /* Skip #define */
2256 sp = strchr(sp, ' ');
2257 if (!sp) {
2258 return 0;
2259 }
2260 /* Skip height label */
2261 sp++;
2262 sp = strchr(sp, ' ');
2263 if (!sp) {
2264 return 0;
2265 }
2266 /* Get height */
2267 h = atoi(sp + 1);
2268 if (!h) {
2269 return 0;
2270 }
2271 /* Skip declaration line */
2272 if (!fgets(s, 160, fd)) {
2273 return 0;
2274 }
2275 bytes = (w * h / 8) + 1;
2276 im = gdImageCreate(w, h);
2277 gdImageColorAllocate(im, 255, 255, 255);
2278 gdImageColorAllocate(im, 0, 0, 0);
2279 x = 0;
2280 y = 0;
2281 for (i=0; (i < bytes); i++) {
2282 char h[3];
2283 int b;
2284 /* Skip spaces, commas, CRs, 0x */
2285 while(1) {
2286 ch = getc(fd);
2287 if (ch == EOF) {
2288 goto fail;
2289 }
2290 if (ch == 'x') {
2291 break;
2292 }
2293 }
2294 /* Get hex value */
2295 ch = getc(fd);
2296 if (ch == EOF) {
2297 goto fail;
2298 }
2299 h[0] = ch;
2300 ch = getc(fd);
2301 if (ch == EOF) {
2302 goto fail;
2303 }
2304 h[1] = ch;
2305 h[2] = '\0';
2306 sscanf(h, "%x", &b);
2307 for (bit = 1; (bit <= 128); (bit = bit << 1)) {
2308 gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
2309 if (x == im->sx) {
2310 x = 0;
2311 y++;
2312 if (y == im->sy) {
2313 return im;
2314 }
2315 /* Fix 8/8/95 */
2316 break;
2317 }
2318 }
2319 }
2320 /* Shouldn't happen */
2321 fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
2322 return 0;
2323fail:
2324 gdImageDestroy(im);
2325 return 0;
2326}
2327
2328void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
2329{
2330 int i;
2331 int lx, ly;
2332 if (!n) {
2333 return;
2334 }
2335 lx = p->x;
2336 ly = p->y;
2337 gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
2338 for (i=1; (i < n); i++) {
2339 p++;
2340 gdImageLine(im, lx, ly, p->x, p->y, c);
2341 lx = p->x;
2342 ly = p->y;
2343 }
2344}
2345
2346int gdCompareInt(const void *a, const void *b);
2347
2348void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
2349{
2350 int i;
2351 int y;
2352 int y1, y2;
2353 int ints;
2354 if (!n) {
2355 return;
2356 }
2357 if (!im->polyAllocated) {
2358 im->polyInts = (int *) malloc(sizeof(int) * n);
2359 im->polyAllocated = n;
2360 }
2361 if (im->polyAllocated < n) {
2362 while (im->polyAllocated < n) {
2363 im->polyAllocated *= 2;
2364 }
2365 im->polyInts = (int *) realloc(im->polyInts,
2366 sizeof(int) * im->polyAllocated);
2367 }
2368 y1 = p[0].y;
2369 y2 = p[0].y;
2370 for (i=1; (i < n); i++) {
2371 if (p[i].y < y1) {
2372 y1 = p[i].y;
2373 }
2374 if (p[i].y > y2) {
2375 y2 = p[i].y;
2376 }
2377 }
2378 for (y=y1; (y <= y2); y++) {
2379 int interLast = 0;
2380 int dirLast = 0;
2381 int interFirst = 1;
2382 ints = 0;
2383 for (i=0; (i <= n); i++) {
2384 int x1, x2;
2385 int y1, y2;
2386 int dir;
2387 int ind1, ind2;
2388 int lastInd1 = 0;
2389 if ((i == n) || (!i)) {
2390 ind1 = n-1;
2391 ind2 = 0;
2392 } else {
2393 ind1 = i-1;
2394 ind2 = i;
2395 }
2396 y1 = p[ind1].y;
2397 y2 = p[ind2].y;
2398 if (y1 < y2) {
2399 y1 = p[ind1].y;
2400 y2 = p[ind2].y;
2401 x1 = p[ind1].x;
2402 x2 = p[ind2].x;
2403 dir = -1;
2404 } else if (y1 > y2) {
2405 y2 = p[ind1].y;
2406 y1 = p[ind2].y;
2407 x2 = p[ind1].x;
2408 x1 = p[ind2].x;
2409 dir = 1;
2410 } else {
2411 /* Horizontal; just draw it */
2412 gdImageLine(im,
2413 p[ind1].x, y1,
2414 p[ind2].x, y1,
2415 c);
2416 continue;
2417 }
2418 if ((y >= y1) && (y <= y2)) {
2419 int inter =
2420 (y-y1) * (x2-x1) / (y2-y1) + x1;
2421 /* Only count intersections once
2422 except at maxima and minima. Also,
2423 if two consecutive intersections are
2424 endpoints of the same horizontal line
2425 that is not at a maxima or minima,
2426 discard the leftmost of the two. */
2427 if (!interFirst) {
2428 if ((p[ind1].y == p[lastInd1].y) &&
2429 (p[ind1].x != p[lastInd1].x)) {
2430 if (dir == dirLast) {
2431 if (inter > interLast) {
2432 /* Replace the old one */
2433 im->polyInts[ints] = inter;
2434 } else {
2435 /* Discard this one */
2436 }
2437 continue;
2438 }
2439 }
2440 if (inter == interLast) {
2441 if (dir == dirLast) {
2442 continue;
2443 }
2444 }
2445 }
2446 if (i > 0) {
2447 im->polyInts[ints++] = inter;
2448 }
2449 lastInd1 = i;
2450 dirLast = dir;
2451 interLast = inter;
2452 interFirst = 0;
2453 }
2454 }
2455 qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2456 for (i=0; (i < (ints-1)); i+=2) {
2457 gdImageLine(im, im->polyInts[i], y,
2458 im->polyInts[i+1], y, c);
2459 }
2460 }
2461}
2462
2463int gdCompareInt(const void *a, const void *b)
2464{
2465 return (*(const int *)a) - (*(const int *)b);
2466}
2467
2468void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
2469{
2470 if (im->style) {
2471 free(im->style);
2472 }
2473 im->style = (int *)
2474 malloc(sizeof(int) * noOfPixels);
2475 memcpy(im->style, style, sizeof(int) * noOfPixels);
2476 im->styleLength = noOfPixels;
2477 im->stylePos = 0;
2478}
2479
2480void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
2481{
2482 int i;
2483 im->brush = brush;
2484 for (i=0; (i < gdImageColorsTotal(brush)); i++) {
2485 int index;
2486 index = gdImageColorExact(im,
2487 gdImageRed(brush, i),
2488 gdImageGreen(brush, i),
2489 gdImageBlue(brush, i));
2490 if (index == (-1)) {
2491 index = gdImageColorAllocate(im,
2492 gdImageRed(brush, i),
2493 gdImageGreen(brush, i),
2494 gdImageBlue(brush, i));
2495 if (index == (-1)) {
2496 index = gdImageColorClosest(im,
2497 gdImageRed(brush, i),
2498 gdImageGreen(brush, i),
2499 gdImageBlue(brush, i));
2500 }
2501 }
2502 im->brushColorMap[i] = index;
2503 }
2504}
2505
2506void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
2507{
2508 int i;
2509 im->tile = tile;
2510 for (i=0; (i < gdImageColorsTotal(tile)); i++) {
2511 int index;
2512 index = gdImageColorExact(im,
2513 gdImageRed(tile, i),
2514 gdImageGreen(tile, i),
2515 gdImageBlue(tile, i));
2516 if (index == (-1)) {
2517 index = gdImageColorAllocate(im,
2518 gdImageRed(tile, i),
2519 gdImageGreen(tile, i),
2520 gdImageBlue(tile, i));
2521 if (index == (-1)) {
2522 index = gdImageColorClosest(im,
2523 gdImageRed(tile, i),
2524 gdImageGreen(tile, i),
2525 gdImageBlue(tile, i));
2526 }
2527 }
2528 im->tileColorMap[i] = index;
2529 }
2530}
2531
2532void gdImageInterlace(gdImagePtr im, int interlaceArg)
2533{
2534 im->interlace = interlaceArg;
2535}
2536
Note: See TracBrowser for help on using the repository browser.