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