1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include "gd.h"
6 #include "mtables.c"
8 static void gdImageBrushApply(gdImagePtr im, int x, int y);
9 static void gdImageTileApply(gdImagePtr im, int x, int y);
11 gdImagePtr gdImageCreate(int sx, int sy)
12 {
13 int i;
14 gdImagePtr im;
15 im = (gdImage *) calloc(1,sizeof(gdImage));
16 /* NOW ROW-MAJOR IN GD 1.3 */
17 im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sy);
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<sy); i++) {
24 /* NOW ROW-MAJOR IN GD 1.3 */
25 im->pixels[i] = (unsigned char *) calloc(
26 sx, sizeof(unsigned char));
27 }
28 im->sx = sx;
29 im->sy = sy;
30 im->colorsTotal = 0;
31 im->transparent = (-1);
32 im->interlace = 0;
33 return im;
34 }
36 void gdImageDestroy(gdImagePtr im)
37 {
38 int i;
39 for (i=0; (i<im->sy); i++) {
40 free(im->pixels[i]);
41 }
42 free(im->pixels);
43 if (im->polyInts) {
44 free(im->polyInts);
45 }
46 if (im->style) {
47 free(im->style);
48 }
49 free(im);
50 }
52 int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
53 {
54 int i;
55 long rd, gd, bd;
56 int ct = (-1);
57 long mindist = 0;
58 for (i=0; (i<(im->colorsTotal)); i++) {
59 long dist;
60 if (im->open[i]) {
61 continue;
62 }
63 rd = (im->red[i] - r);
64 gd = (im->green[i] - g);
65 bd = (im->blue[i] - b);
66 dist = rd * rd + gd * gd + bd * bd;
67 if ((i == 0) || (dist < mindist)) {
68 mindist = dist;
69 ct = i;
70 }
71 }
72 return ct;
73 }
75 int gdImageColorExact(gdImagePtr im, int r, int g, int b)
76 {
77 int i;
78 for (i=0; (i<(im->colorsTotal)); i++) {
79 if (im->open[i]) {
80 continue;
81 }
82 if ((im->red[i] == r) &&
83 (im->green[i] == g) &&
84 (im->blue[i] == b)) {
85 return i;
86 }
87 }
88 return -1;
89 }
91 int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
92 {
93 int i;
94 int ct = (-1);
95 for (i=0; (i<(im->colorsTotal)); i++) {
96 if (im->open[i]) {
97 ct = i;
98 break;
99 }
100 }
101 if (ct == (-1)) {
102 ct = im->colorsTotal;
103 if (ct == gdMaxColors) {
104 return -1;
105 }
106 im->colorsTotal++;
107 }
108 im->red[ct] = r;
109 im->green[ct] = g;
110 im->blue[ct] = b;
111 im->open[ct] = 0;
112 return ct;
113 }
115 void gdImageColorDeallocate(gdImagePtr im, int color)
116 {
117 /* Mark it open. */
118 im->open[color] = 1;
119 }
121 void gdImageColorTransparent(gdImagePtr im, int color)
122 {
123 im->transparent = color;
124 }
126 void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
127 {
128 int p;
129 switch(color) {
130 case gdStyled:
131 if (!im->style) {
132 /* Refuse to draw if no style is set. */
133 return;
134 } else {
135 p = im->style[im->stylePos++];
136 }
137 if (p != (gdTransparent)) {
138 gdImageSetPixel(im, x, y, p);
139 }
140 im->stylePos = im->stylePos % im->styleLength;
141 break;
142 case gdStyledBrushed:
143 if (!im->style) {
144 /* Refuse to draw if no style is set. */
145 return;
146 }
147 p = im->style[im->stylePos++];
148 if ((p != gdTransparent) && (p != 0)) {
149 gdImageSetPixel(im, x, y, gdBrushed);
150 }
151 im->stylePos = im->stylePos % im->styleLength;
152 break;
153 case gdBrushed:
154 gdImageBrushApply(im, x, y);
155 break;
156 case gdTiled:
157 gdImageTileApply(im, x, y);
158 break;
159 default:
160 if (gdImageBoundsSafe(im, x, y)) {
161 /* NOW ROW-MAJOR IN GD 1.3 */
162 im->pixels[y][x] = color;
163 }
164 break;
165 }
166 }
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 }
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 }
218 int gdImageGetPixel(gdImagePtr im, int x, int y)
219 {
220 if (gdImageBoundsSafe(im, x, y)) {
221 /* NOW ROW-MAJOR IN GD 1.3 */
222 return im->pixels[y][x];
223 } else {
224 return 0;
225 }
226 }
228 /* Bresenham as presented in Foley & Van Dam */
230 void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
231 {
232 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
233 dx = abs(x2-x1);
234 dy = abs(y2-y1);
235 if (dy <= dx) {
236 d = 2*dy - dx;
237 incr1 = 2*dy;
238 incr2 = 2 * (dy - dx);
239 if (x1 > x2) {
240 x = x2;
241 y = y2;
242 ydirflag = (-1);
243 xend = x1;
244 } else {
245 x = x1;
246 y = y1;
247 ydirflag = 1;
248 xend = x2;
249 }
250 gdImageSetPixel(im, x, y, color);
251 if (((y2 - y1) * ydirflag) > 0) {
252 while (x < xend) {
253 x++;
254 if (d <0) {
255 d+=incr1;
256 } else {
257 y++;
258 d+=incr2;
259 }
260 gdImageSetPixel(im, x, y, color);
261 }
262 } else {
263 while (x < xend) {
264 x++;
265 if (d <0) {
266 d+=incr1;
267 } else {
268 y--;
269 d+=incr2;
270 }
271 gdImageSetPixel(im, x, y, color);
272 }
273 }
274 } else {
275 d = 2*dx - dy;
276 incr1 = 2*dx;
277 incr2 = 2 * (dx - dy);
278 if (y1 > y2) {
279 y = y2;
280 x = x2;
281 yend = y1;
282 xdirflag = (-1);
283 } else {
284 y = y1;
285 x = x1;
286 yend = y2;
287 xdirflag = 1;
288 }
289 gdImageSetPixel(im, x, y, color);
290 if (((x2 - x1) * xdirflag) > 0) {
291 while (y < yend) {
292 y++;
293 if (d <0) {
294 d+=incr1;
295 } else {
296 x++;
297 d+=incr2;
298 }
299 gdImageSetPixel(im, x, y, color);
300 }
301 } else {
302 while (y < yend) {
303 y++;
304 if (d <0) {
305 d+=incr1;
306 } else {
307 x--;
308 d+=incr2;
309 }
310 gdImageSetPixel(im, x, y, color);
311 }
312 }
313 }
314 }
316 static void dashedSet(gdImagePtr im, int x, int y, int color,
317 int *onP, int *dashStepP);
319 void gdImageDashedLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
320 {
321 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
322 int dashStep = 0;
323 int on = 1;
324 dx = abs(x2-x1);
325 dy = abs(y2-y1);
326 if (dy <= dx) {
327 d = 2*dy - dx;
328 incr1 = 2*dy;
329 incr2 = 2 * (dy - dx);
330 if (x1 > x2) {
331 x = x2;
332 y = y2;
333 ydirflag = (-1);
334 xend = x1;
335 } else {
336 x = x1;
337 y = y1;
338 ydirflag = 1;
339 xend = x2;
340 }
341 dashedSet(im, x, y, color, &on, &dashStep);
342 if (((y2 - y1) * ydirflag) > 0) {
343 while (x < xend) {
344 x++;
345 if (d <0) {
346 d+=incr1;
347 } else {
348 y++;
349 d+=incr2;
350 }
351 dashedSet(im, x, y, color, &on, &dashStep);
352 }
353 } else {
354 while (x < xend) {
355 x++;
356 if (d <0) {
357 d+=incr1;
358 } else {
359 y--;
360 d+=incr2;
361 }
362 dashedSet(im, x, y, color, &on, &dashStep);
363 }
364 }
365 } else {
366 d = 2*dx - dy;
367 incr1 = 2*dx;
368 incr2 = 2 * (dx - dy);
369 if (y1 > y2) {
370 y = y2;
371 x = x2;
372 yend = y1;
373 xdirflag = (-1);
374 } else {
375 y = y1;
376 x = x1;
377 yend = y2;
378 xdirflag = 1;
379 }
380 dashedSet(im, x, y, color, &on, &dashStep);
381 if (((x2 - x1) * xdirflag) > 0) {
382 while (y < yend) {
383 y++;
384 if (d <0) {
385 d+=incr1;
386 } else {
387 x++;
388 d+=incr2;
389 }
390 dashedSet(im, x, y, color, &on, &dashStep);
391 }
392 } else {
393 while (y < yend) {
394 y++;
395 if (d <0) {
396 d+=incr1;
397 } else {
398 x--;
399 d+=incr2;
400 }
401 dashedSet(im, x, y, color, &on, &dashStep);
402 }
403 }
404 }
405 }
407 static void dashedSet(gdImagePtr im, int x, int y, int color,
408 int *onP, int *dashStepP)
409 {
410 int dashStep = *dashStepP;
411 int on = *onP;
412 dashStep++;
413 if (dashStep == gdDashSize) {
414 dashStep = 0;
415 on = !on;
416 }
417 if (on) {
418 gdImageSetPixel(im, x, y, color);
419 }
420 *dashStepP = dashStep;
421 *onP = on;
422 }
425 int gdImageBoundsSafe(gdImagePtr im, int x, int y)
426 {
427 return (!(((y < 0) || (y >= im->sy)) ||
428 ((x < 0) || (x >= im->sx))));
429 }
431 void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y,
432 int c, int color)
433 {
434 int cx, cy;
435 int px, py;
436 int fline;
437 cx = 0;
438 cy = 0;
439 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
440 return;
441 }
442 fline = (c - f->offset) * f->h * f->w;
443 for (py = y; (py < (y + f->h)); py++) {
444 for (px = x; (px < (x + f->w)); px++) {
445 if (f->data[fline + cy * f->w + cx]) {
446 gdImageSetPixel(im, px, py, color);
447 }
448 cx++;
449 }
450 cx = 0;
451 cy++;
452 }
453 }
455 void gdImageCharUp(gdImagePtr im, gdFontPtr f,
456 int x, int y, int c, int color)
457 {
458 int cx, cy;
459 int px, py;
460 int fline;
461 cx = 0;
462 cy = 0;
463 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
464 return;
465 }
466 fline = (c - f->offset) * f->h * f->w;
467 for (py = y; (py > (y - f->w)); py--) {
468 for (px = x; (px < (x + f->h)); px++) {
469 if (f->data[fline + cy * f->w + cx]) {
470 gdImageSetPixel(im, px, py, color);
471 }
472 cy++;
473 }
474 cy = 0;
475 cx++;
476 }
477 }
479 void gdImageString(gdImagePtr im, gdFontPtr f,
480 int x, int y, unsigned char *s, int color)
481 {
482 int i;
483 int l;
484 l = strlen(s);
485 for (i=0; (i<l); i++) {
486 gdImageChar(im, f, x, y, s[i], color);
487 x += f->w;
488 }
489 }
491 void gdImageStringUp(gdImagePtr im, gdFontPtr f,
492 int x, int y, unsigned char *s, int color)
493 {
494 int i;
495 int l;
496 l = strlen(s);
497 for (i=0; (i<l); i++) {
498 gdImageCharUp(im, f, x, y, s[i], color);
499 y -= f->w;
500 }
501 }
503 static int strlen16(unsigned short *s);
505 void gdImageString16(gdImagePtr im, gdFontPtr f,
506 int x, int y, unsigned short *s, int color)
507 {
508 int i;
509 int l;
510 l = strlen16(s);
511 for (i=0; (i<l); i++) {
512 gdImageChar(im, f, x, y, s[i], color);
513 x += f->w;
514 }
515 }
517 void gdImageStringUp16(gdImagePtr im, gdFontPtr f,
518 int x, int y, unsigned short *s, int color)
519 {
520 int i;
521 int l;
522 l = strlen16(s);
523 for (i=0; (i<l); i++) {
524 gdImageCharUp(im, f, x, y, s[i], color);
525 y -= f->w;
526 }
527 }
529 static int strlen16(unsigned short *s)
530 {
531 int len = 0;
532 while (*s) {
533 s++;
534 len++;
535 }
536 return len;
537 }
539 /* s and e are integers modulo 360 (degrees), with 0 degrees
540 being the rightmost extreme and degrees changing clockwise.
541 cx and cy are the center in pixels; w and h are the horizontal
542 and vertical diameter in pixels. Nice interface, but slow, since
543 I don't yet use Bresenham (I'm using an inefficient but
544 simple solution with too much work going on in it; generalizing
545 Bresenham to ellipses and partial arcs of ellipses is non-trivial,
546 at least for me) and there are other inefficiencies (small circles
547 do far too much work). */
549 void gdImageArc(gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
550 {
551 int i;
552 int lx = 0, ly = 0;
553 int w2, h2;
554 w2 = w/2;
555 h2 = h/2;
556 while (e < s) {
557 e += 360;
558 }
559 for (i=s; (i <= e); i++) {
560 int x, y;
561 x = ((long)cost[i % 360] * (long)w2 / costScale) + cx;
562 y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
563 if (i != s) {
564 gdImageLine(im, lx, ly, x, y, color);
565 }
566 lx = x;
567 ly = y;
568 }
569 }
572 #if 0
573 /* Bresenham octant code, which I should use eventually */
574 int x, y, d;
575 x = 0;
576 y = w;
577 d = 3-2*w;
578 while (x < y) {
579 gdImageSetPixel(im, cx+x, cy+y, color);
580 if (d < 0) {
581 d += 4 * x + 6;
582 } else {
583 d += 4 * (x - y) + 10;
584 y--;
585 }
586 x++;
587 }
588 if (x == y) {
589 gdImageSetPixel(im, cx+x, cy+y, color);
590 }
591 #endif
593 void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
594 {
595 int lastBorder;
596 /* Seek left */
597 int leftLimit, rightLimit;
598 int i;
599 leftLimit = (-1);
600 if (border < 0) {
601 /* Refuse to fill to a non-solid border */
602 return;
603 }
604 for (i = x; (i >= 0); i--) {
605 if (gdImageGetPixel(im, i, y) == border) {
606 break;
607 }
608 gdImageSetPixel(im, i, y, color);
609 leftLimit = i;
610 }
611 if (leftLimit == (-1)) {
612 return;
613 }
614 /* Seek right */
615 rightLimit = x;
616 for (i = (x+1); (i < im->sx); i++) {
617 if (gdImageGetPixel(im, i, y) == border) {
618 break;
619 }
620 gdImageSetPixel(im, i, y, color);
621 rightLimit = i;
622 }
623 /* Look at lines above and below and start paints */
624 /* Above */
625 if (y > 0) {
626 lastBorder = 1;
627 for (i = leftLimit; (i <= rightLimit); i++) {
628 int c;
629 c = gdImageGetPixel(im, i, y-1);
630 if (lastBorder) {
631 if ((c != border) && (c != color)) {
632 gdImageFillToBorder(im, i, y-1,
633 border, color);
634 lastBorder = 0;
635 }
636 } else if ((c == border) || (c == color)) {
637 lastBorder = 1;
638 }
639 }
640 }
641 /* Below */
642 if (y < ((im->sy) - 1)) {
643 lastBorder = 1;
644 for (i = leftLimit; (i <= rightLimit); i++) {
645 int c;
646 c = gdImageGetPixel(im, i, y+1);
647 if (lastBorder) {
648 if ((c != border) && (c != color)) {
649 gdImageFillToBorder(im, i, y+1,
650 border, color);
651 lastBorder = 0;
652 }
653 } else if ((c == border) || (c == color)) {
654 lastBorder = 1;
655 }
656 }
657 }
658 }
660 void gdImageFill(gdImagePtr im, int x, int y, int color)
661 {
662 int lastBorder;
663 int old;
664 int leftLimit, rightLimit;
665 int i;
666 old = gdImageGetPixel(im, x, y);
667 if (color == gdTiled) {
668 /* Tile fill -- got to watch out! */
669 int p, tileColor;
670 int srcx, srcy;
671 if (!im->tile) {
672 return;
673 }
674 /* Refuse to flood-fill with a transparent pattern --
675 I can't do it without allocating another image */
676 if (gdImageGetTransparent(im->tile) != (-1)) {
677 return;
678 }
679 srcx = x % gdImageSX(im->tile);
680 srcy = y % gdImageSY(im->tile);
681 p = gdImageGetPixel(im->tile, srcx, srcy);
682 tileColor = im->tileColorMap[p];
683 if (old == tileColor) {
684 /* Nothing to be done */
685 return;
686 }
687 } else {
688 if (old == color) {
689 /* Nothing to be done */
690 return;
691 }
692 }
693 /* Seek left */
694 leftLimit = (-1);
695 for (i = x; (i >= 0); i--) {
696 if (gdImageGetPixel(im, i, y) != old) {
697 break;
698 }
699 gdImageSetPixel(im, i, y, color);
700 leftLimit = i;
701 }
702 if (leftLimit == (-1)) {
703 return;
704 }
705 /* Seek right */
706 rightLimit = x;
707 for (i = (x+1); (i < im->sx); i++) {
708 if (gdImageGetPixel(im, i, y) != old) {
709 break;
710 }
711 gdImageSetPixel(im, i, y, color);
712 rightLimit = i;
713 }
714 /* Look at lines above and below and start paints */
715 /* Above */
716 if (y > 0) {
717 lastBorder = 1;
718 for (i = leftLimit; (i <= rightLimit); i++) {
719 int c;
720 c = gdImageGetPixel(im, i, y-1);
721 if (lastBorder) {
722 if (c == old) {
723 gdImageFill(im, i, y-1, color);
724 lastBorder = 0;
725 }
726 } else if (c != old) {
727 lastBorder = 1;
728 }
729 }
730 }
731 /* Below */
732 if (y < ((im->sy) - 1)) {
733 lastBorder = 1;
734 for (i = leftLimit; (i <= rightLimit); i++) {
735 int c;
736 c = gdImageGetPixel(im, i, y+1);
737 if (lastBorder) {
738 if (c == old) {
739 gdImageFill(im, i, y+1, color);
740 lastBorder = 0;
741 }
742 } else if (c != old) {
743 lastBorder = 1;
744 }
745 }
746 }
747 }
749 /* Code drawn from ppmtogif.c, from the pbmplus package
750 **
751 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
752 ** Lempel-Zim compression based on "compress".
753 **
754 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
755 **
756 ** Copyright (C) 1989 by Jef Poskanzer.
757 **
758 ** Permission to use, copy, modify, and distribute this software and its
759 ** documentation for any purpose and without fee is hereby granted, provided
760 ** that the above copyright notice appear in all copies and that both that
761 ** copyright notice and this permission notice appear in supporting
762 ** documentation. This software is provided "as is" without express or
763 ** implied warranty.
764 **
765 ** The Graphics Interchange Format(c) is the Copyright property of
766 ** CompuServe Incorporated. GIF(sm) is a Service Mark property of
767 ** CompuServe Incorporated.
768 *
769 * Heavily modified by Mouse, 1998-02-12.
770 * Remove LZW compression.
771 * Added miGIF run length compression.
772 *
773 */
775 /*
776 * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
777 */
778 typedef int code_int;
780 static int colorstobpp(int colors);
781 static void BumpPixel (void);
782 static int GIFNextPixel (gdImagePtr im);
783 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);
784 static void Putword (int w, FILE *fp);
785 static void compress (int, FILE *, gdImagePtr, int);
786 static void output (code_int code);
787 /* Allows for reuse */
788 static void init_statics(void);
790 void gdImageGif(gdImagePtr im, FILE *out)
791 {
792 int interlace, transparent, BitsPerPixel;
793 interlace = im->interlace;
794 transparent = im->transparent;
796 BitsPerPixel = colorstobpp(im->colorsTotal);
797 /* Clear any old values in statics strewn through the GIF code */
798 init_statics();
799 /* All set, let's do it. */
800 GIFEncode(
801 out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
802 im->red, im->green, im->blue, im);
803 }
805 static int
806 colorstobpp(int colors)
807 {
808 int bpp = 0;
810 if ( colors <= 2 )
811 bpp = 1;
812 else if ( colors <= 4 )
813 bpp = 2;
814 else if ( colors <= 8 )
815 bpp = 3;
816 else if ( colors <= 16 )
817 bpp = 4;
818 else if ( colors <= 32 )
819 bpp = 5;
820 else if ( colors <= 64 )
821 bpp = 6;
822 else if ( colors <= 128 )
823 bpp = 7;
824 else if ( colors <= 256 )
825 bpp = 8;
826 return bpp;
827 }
829 /*****************************************************************************
830 *
831 * GIFENCODE.C - GIF Image compression interface
832 *
833 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
834 * BitsPerPixel, Red, Green, Blue, gdImagePtr )
835 *
836 *****************************************************************************/
838 #define TRUE 1
839 #define FALSE 0
841 static int Width, Height;
842 static int curx, cury;
843 static long CountDown;
844 static int Pass = 0;
845 static int Interlace;
847 /*
848 * Bump the 'curx' and 'cury' to point to the next pixel
849 */
850 static void
851 BumpPixel(void)
852 {
853 /*
854 * Bump the current X position
855 */
856 ++curx;
858 /*
859 * If we are at the end of a scan line, set curx back to the beginning
860 * If we are interlaced, bump the cury to the appropriate spot,
861 * otherwise, just increment it.
862 */
863 if( curx == Width ) {
864 curx = 0;
866 if( !Interlace )
867 ++cury;
868 else {
869 switch( Pass ) {
871 case 0:
872 cury += 8;
873 if( cury >= Height ) {
874 ++Pass;
875 cury = 4;
876 }
877 break;
879 case 1:
880 cury += 8;
881 if( cury >= Height ) {
882 ++Pass;
883 cury = 2;
884 }
885 break;
887 case 2:
888 cury += 4;
889 if( cury >= Height ) {
890 ++Pass;
891 cury = 1;
892 }
893 break;
895 case 3:
896 cury += 2;
897 break;
898 }
899 }
900 }
901 }
903 /*
904 * Return the next pixel from the image
905 */
906 static int
907 GIFNextPixel(gdImagePtr im)
908 {
909 int r;
911 if( CountDown == 0 )
912 return EOF;
914 --CountDown;
916 r = gdImageGetPixel(im, curx, cury);
918 BumpPixel();
920 return r;
921 }
923 /* public */
925 static void
926 GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
927 {
928 int B;
929 int RWidth, RHeight;
930 int LeftOfs, TopOfs;
931 int Resolution;
932 int ColorMapSize;
933 int InitCodeSize;
934 int i;
936 Interlace = GInterlace;
938 ColorMapSize = 1 << BitsPerPixel;
940 RWidth = Width = GWidth;
941 RHeight = Height = GHeight;
942 LeftOfs = TopOfs = 0;
944 Resolution = BitsPerPixel;
946 /*
947 * Calculate number of bits we are expecting
948 */
949 CountDown = (long)Width * (long)Height;
951 /*
952 * Indicate which pass we are on (if interlace)
953 */
954 Pass = 0;
956 /*
957 * The initial code size
958 */
959 if( BitsPerPixel <= 1 )
960 InitCodeSize = 2;
961 else
962 InitCodeSize = BitsPerPixel;
964 /*
965 * Set up the current x and y position
966 */
967 curx = cury = 0;
969 /*
970 * Write the Magic header
971 */
972 fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
974 /*
975 * Write out the screen width and height
976 */
977 Putword( RWidth, fp );
978 Putword( RHeight, fp );
980 /*
981 * Indicate that there is a global colour map
982 */
983 B = 0x80; /* Yes, there is a color map */
985 /*
986 * OR in the resolution
987 */
988 B |= (Resolution - 1) << 4;
990 /*
991 * OR in the Bits per Pixel
992 */
993 B |= (BitsPerPixel - 1);
995 /*
996 * Write it out
997 */
998 fputc( B, fp );
1000 /*
1001 * Write out the Background colour
1002 */
1003 fputc( Background, fp );
1005 /*
1006 * Byte of 0's (future expansion)
1007 */
1008 fputc( 0, fp );
1010 /*
1011 * Write out the Global Colour Map
1012 */
1013 for( i=0; i<ColorMapSize; ++i ) {
1014 fputc( Red[i], fp );
1015 fputc( Green[i], fp );
1016 fputc( Blue[i], fp );
1017 }
1019 /*
1020 * Write out extension for transparent colour index, if necessary.
1021 */
1022 if ( Transparent >= 0 ) {
1023 fputc( '!', fp );
1024 fputc( 0xf9, fp );
1025 fputc( 4, fp );
1026 fputc( 1, fp );
1027 fputc( 0, fp );
1028 fputc( 0, fp );
1029 fputc( (unsigned char) Transparent, fp );
1030 fputc( 0, fp );
1031 }
1033 /*
1034 * Write an Image separator
1035 */
1036 fputc( ',', fp );
1038 /*
1039 * Write the Image header
1040 */
1042 Putword( LeftOfs, fp );
1043 Putword( TopOfs, fp );
1044 Putword( Width, fp );
1045 Putword( Height, fp );
1047 /*
1048 * Write out whether or not the image is interlaced
1049 */
1050 if( Interlace )
1051 fputc( 0x40, fp );
1052 else
1053 fputc( 0x00, fp );
1055 /*
1056 * Write out the initial code size
1057 */
1058 fputc( InitCodeSize, fp );
1060 /*
1061 * Go and actually compress the data
1062 */
1063 compress( InitCodeSize+1, fp, im, Background );
1065 /*
1066 * Write out a Zero-length packet (to end the series)
1067 */
1068 fputc( 0, fp );
1070 /*
1071 * Write the GIF file terminator
1072 */
1073 fputc( ';', fp );
1074 }
1076 /*
1077 * Write out a word to the GIF file
1078 */
1079 static void
1080 Putword(int w, FILE *fp)
1081 {
1082 fputc( w & 0xff, fp );
1083 fputc( (w / 256) & 0xff, fp );
1084 }
1086 #define GIFBITS 12
1088 /*-----------------------------------------------------------------------
1089 *
1090 * miGIF Compression - mouse and ivo's GIF-compatible compression
1091 *
1092 * -run length encoding compression routines-
1093 *
1094 * Copyright (C) 1998 Hutchison Avenue Software Corporation
1095 * http://www.hasc.com
1096 * info@hasc.com
1097 *
1098 * Permission to use, copy, modify, and distribute this software and its
1099 * documentation for any purpose and without fee is hereby granted, provided
1100 * that the above copyright notice appear in all copies and that both that
1101 * copyright notice and this permission notice appear in supporting
1102 * documentation. This software is provided "AS IS." The Hutchison Avenue
1103 * Software Corporation disclaims all warranties, either express or implied,
1104 * including but not limited to implied warranties of merchantability and
1105 * fitness for a particular purpose, with respect to this code and accompanying
1106 * documentation.
1107 *
1108 * The miGIF compression routines do not, strictly speaking, generate files
1109 * conforming to the GIF spec, since the image data is not LZW-compressed
1110 * (this is the point: in order to avoid transgression of the Unisys patent
1111 * on the LZW algorithm.) However, miGIF generates data streams that any
1112 * reasonably sane LZW decompresser will decompress to what we want.
1113 *
1114 * miGIF compression uses run length encoding. It compresses horizontal runs
1115 * of pixels of the same color. This type of compression gives good results
1116 * on images with many runs, for example images with lines, text and solid
1117 * shapes on a solid-colored background. It gives little or no compression
1118 * on images with few runs, for example digital or scanned photos.
1119 *
1120 * der Mouse
1121 * mouse@rodents.montreal.qc.ca
1122 * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
1123 *
1124 * ivo@hasc.com
1125 *
1126 * The Graphics Interchange Format(c) is the Copyright property of
1127 * CompuServe Incorporated. GIF(sm) is a Service Mark property of
1128 * CompuServe Incorporated.
1129 *
1130 */
1132 static int rl_pixel;
1133 static int rl_basecode;
1134 static int rl_count;
1135 static int rl_table_pixel;
1136 static int rl_table_max;
1137 static int just_cleared;
1138 static int out_bits;
1139 static int out_bits_init;
1140 static int out_count;
1141 static int out_bump;
1142 static int out_bump_init;
1143 static int out_clear;
1144 static int out_clear_init;
1145 static int max_ocodes;
1146 static int code_clear;
1147 static int code_eof;
1148 static unsigned int obuf;
1149 static int obits;
1150 static FILE *ofile;
1151 static unsigned char oblock[256];
1152 static int oblen;
1154 /* Used only when debugging GIF compression code */
1155 /* #define DEBUGGING_ENVARS */
1157 #ifdef DEBUGGING_ENVARS
1159 static int verbose_set = 0;
1160 static int verbose;
1161 #define VERBOSE (verbose_set?verbose:set_verbose())
1163 static int set_verbose(void)
1164 {
1165 verbose = !!getenv("GIF_VERBOSE");
1166 verbose_set = 1;
1167 return(verbose);
1168 }
1170 #else
1172 #define VERBOSE 0
1174 #endif
1177 static const char *binformat(unsigned int v, int nbits)
1178 {
1179 static char bufs[8][64];
1180 static int bhand = 0;
1181 unsigned int bit;
1182 int bno;
1183 char *bp;
1185 bhand --;
1186 if (bhand < 0) bhand = (sizeof(bufs)/sizeof(bufs[0]))-1;
1187 bp = &bufs[bhand][0];
1188 for (bno=nbits-1,bit=1U<<bno;bno>=0;bno--,bit>>=1)
1189 { *bp++ = (v & bit) ? '1' : '0';
1190 if (((bno&3) == 0) && (bno != 0)) *bp++ = '.';
1191 }
1192 *bp = '\0';
1193 return(&bufs[bhand][0]);
1194 }
1196 static void write_block(void)
1197 {
1198 int i;
1200 if (VERBOSE)
1201 { printf("write_block %d:",oblen);
1202 for (i=0;i<oblen;i++) printf(" %02x",oblock[i]);
1203 printf("\n");
1204 }
1205 fputc(oblen,ofile);
1206 fwrite(&oblock[0],1,oblen,ofile);
1207 oblen = 0;
1208 }
1210 static void block_out(unsigned char c)
1211 {
1212 if (VERBOSE) printf("block_out %s\n",binformat(c,8));
1213 oblock[oblen++] = c;
1214 if (oblen >= 255) write_block();
1215 }
1217 static void block_flush(void)
1218 {
1219 if (VERBOSE) printf("block_flush\n");
1220 if (oblen > 0) write_block();
1221 }
1223 static void output(int val)
1224 {
1225 if (VERBOSE) printf("output %s [%s %d %d]\n",binformat(val,out_bits),binformat(obuf,obits),obits,out_bits);
1226 obuf |= val << obits;
1227 obits += out_bits;
1228 while (obits >= 8)
1229 { block_out(obuf&0xff);
1230 obuf >>= 8;
1231 obits -= 8;
1232 }
1233 if (VERBOSE) printf("output leaving [%s %d]\n",binformat(obuf,obits),obits);
1234 }
1236 static void output_flush(void)
1237 {
1238 if (VERBOSE) printf("output_flush\n");
1239 if (obits > 0) block_out(obuf);
1240 block_flush();
1241 }
1243 static void did_clear(void)
1244 {
1245 if (VERBOSE) printf("did_clear\n");
1246 out_bits = out_bits_init;
1247 out_bump = out_bump_init;
1248 out_clear = out_clear_init;
1249 out_count = 0;
1250 rl_table_max = 0;
1251 just_cleared = 1;
1252 }
1254 static void output_plain(int c)
1255 {
1256 if (VERBOSE) printf("output_plain %s\n",binformat(c,out_bits));
1257 just_cleared = 0;
1258 output(c);
1259 out_count ++;
1260 if (out_count >= out_bump)
1261 { out_bits ++;
1262 out_bump += 1 << (out_bits - 1);
1263 }
1264 if (out_count >= out_clear)
1265 { output(code_clear);
1266 did_clear();
1267 }
1268 }
1270 static unsigned int isqrt(unsigned int x)
1271 {
1272 unsigned int r;
1273 unsigned int v;
1275 if (x < 2) return(x);
1276 for (v=x,r=1;v;v>>=2,r<<=1) ;
1277 while (1)
1278 { v = ((x / r) + r) / 2;
1279 if ((v == r) || (v == r+1)) return(r);
1280 r = v;
1281 }
1282 }
1284 static unsigned int compute_triangle_count(unsigned int count, unsigned int nrepcodes)
1285 {
1286 unsigned int perrep;
1287 unsigned int ncost;
1289 ncost = 0;
1290 perrep = (nrepcodes * (nrepcodes+1)) / 2;
1291 while (count >= perrep)
1292 { ncost += nrepcodes;
1293 count -= perrep;
1294 }
1295 if (count > 0)
1296 { unsigned int n;
1297 n = isqrt(count);
1298 while ((n*(n+1)) >= 2*count) n --;
1299 while ((n*(n+1)) < 2*count) n ++;
1300 ncost += n;
1301 }
1302 return(ncost);
1303 }
1305 static void max_out_clear(void)
1306 {
1307 out_clear = max_ocodes;
1308 }
1310 static void reset_out_clear(void)
1311 {
1312 out_clear = out_clear_init;
1313 if (out_count >= out_clear)
1314 { output(code_clear);
1315 did_clear();
1316 }
1317 }
1319 static void rl_flush_fromclear(int count)
1320 {
1321 int n;
1323 if (VERBOSE) printf("rl_flush_fromclear %d\n",count);
1324 max_out_clear();
1325 rl_table_pixel = rl_pixel;
1326 n = 1;
1327 while (count > 0)
1328 { if (n == 1)
1329 { rl_table_max = 1;
1330 output_plain(rl_pixel);
1331 count --;
1332 }
1333 else if (count >= n)
1334 { rl_table_max = n;
1335 output_plain(rl_basecode+n-2);
1336 count -= n;
1337 }
1338 else if (count == 1)
1339 { rl_table_max ++;
1340 output_plain(rl_pixel);
1341 count = 0;
1342 }
1343 else
1344 { rl_table_max ++;
1345 output_plain(rl_basecode+count-2);
1346 count = 0;
1347 }
1348 if (out_count == 0) n = 1; else n ++;
1349 }
1350 reset_out_clear();
1351 if (VERBOSE) printf("rl_flush_fromclear leaving table_max=%d\n",rl_table_max);
1352 }
1354 static void rl_flush_clearorrep(int count)
1355 {
1356 int withclr;
1358 if (VERBOSE) printf("rl_flush_clearorrep %d\n",count);
1359 withclr = 1 + compute_triangle_count(count,max_ocodes);
1360 if (withclr < count)
1361 { output(code_clear);
1362 did_clear();
1363 rl_flush_fromclear(count);
1364 }
1365 else
1366 { for (;count>0;count--) output_plain(rl_pixel);
1367 }
1368 }
1370 static void rl_flush_withtable(int count)
1371 {
1372 int repmax;
1373 int repleft;
1374 int leftover;
1376 if (VERBOSE) printf("rl_flush_withtable %d\n",count);
1377 repmax = count / rl_table_max;
1378 leftover = count % rl_table_max;
1379 repleft = (leftover ? 1 : 0);
1380 if (out_count+repmax+repleft > max_ocodes)
1381 { repmax = max_ocodes - out_count;
1382 leftover = count - (repmax * rl_table_max);
1383 repleft = 1 + compute_triangle_count(leftover,max_ocodes);
1384 }
1385 if (VERBOSE) printf("rl_flush_withtable repmax=%d leftover=%d repleft=%d\n",repmax,leftover,repleft);
1386 if (1+compute_triangle_count(count,max_ocodes) < repmax+repleft)
1387 { output(code_clear);
1388 did_clear();
1389 rl_flush_fromclear(count);
1390 return;
1391 }
1392 max_out_clear();
1393 for (;repmax>0;repmax--) output_plain(rl_basecode+rl_table_max-2);
1394 if (leftover)
1395 { if (just_cleared)
1396 { rl_flush_fromclear(leftover);
1397 }
1398 else if (leftover == 1)
1399 { output_plain(rl_pixel);
1400 }
1401 else
1402 { output_plain(rl_basecode+leftover-2);
1403 }
1404 }
1405 reset_out_clear();
1406 }
1408 static void rl_flush(void)
1409 {
1411 if (VERBOSE) printf("rl_flush [ %d %d\n",rl_count,rl_pixel);
1412 if (rl_count == 1)
1413 { output_plain(rl_pixel);
1414 rl_count = 0;
1415 if (VERBOSE) printf("rl_flush ]\n");
1416 return;
1417 }
1418 if (just_cleared)
1419 { rl_flush_fromclear(rl_count);
1420 }
1421 else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel))
1422 { rl_flush_clearorrep(rl_count);
1423 }
1424 else
1425 { rl_flush_withtable(rl_count);
1426 }
1427 if (VERBOSE) printf("rl_flush ]\n");
1428 rl_count = 0;
1429 }
1431 static void compress(int init_bits, FILE *outfile, gdImagePtr im, int background)
1432 {
1433 int c;
1435 ofile = outfile;
1436 obuf = 0;
1437 obits = 0;
1438 oblen = 0;
1439 code_clear = 1 << (init_bits - 1);
1440 code_eof = code_clear + 1;
1441 rl_basecode = code_eof + 1;
1442 out_bump_init = (1 << (init_bits - 1)) - 1;
1443 /* for images with a lot of runs, making out_clear_init larger will
1444 give better compression. */
1445 out_clear_init = (init_bits <= 3) ? 9 : (out_bump_init-1);
1446 #ifdef DEBUGGING_ENVARS
1447 { const char *ocienv;
1448 ocienv = getenv("GIF_OUT_CLEAR_INIT");
1449 if (ocienv)
1450 { out_clear_init = atoi(ocienv);
1451 if (VERBOSE) printf("[overriding out_clear_init to %d]\n",out_clear_init);
1452 }
1453 }
1454 #endif
1455 out_bits_init = init_bits;
1456 max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3);
1457 did_clear();
1458 output(code_clear);
1459 rl_count = 0;
1460 while (1)
1461 { c = GIFNextPixel(im);
1462 if ((rl_count > 0) && (c != rl_pixel)) rl_flush();
1463 if (c == EOF) break;
1464 if (rl_pixel == c)
1465 { rl_count ++;
1466 }
1467 else
1468 { rl_pixel = c;
1469 rl_count = 1;
1470 }
1471 }
1472 output(code_eof);
1473 output_flush();
1474 }
1476 /*-----------------------------------------------------------------------
1477 *
1478 * End of miGIF section - See copyright notice at start of section.
1479 *
1480 *-----------------------------------------------------------------------
1483 ******************************************************************************
1484 *
1485 * GIF Specific routines
1486 *
1487 ******************************************************************************/
1489 /*
1490 * Number of characters so far in this 'packet'
1491 */
1492 static int a_count;
1494 /*
1495 * Define the storage for the packet accumulator
1496 */
1498 static void init_statics(void) {
1499 /* Some of these are properly initialized later. What I'm doing
1500 here is making sure code that depends on C's initialization
1501 of statics doesn't break when the code gets called more
1502 than once. */
1503 Width = 0;
1504 Height = 0;
1505 curx = 0;
1506 cury = 0;
1507 CountDown = 0;
1508 Pass = 0;
1509 Interlace = 0;
1510 a_count = 0;
1511 }
1514 /* +-------------------------------------------------------------------+ */
1515 /* | Copyright 1990, 1991, 1993, David Koblas. (koblas@netcom.com) | */
1516 /* | Permission to use, copy, modify, and distribute this software | */
1517 /* | and its documentation for any purpose and without fee is hereby | */
1518 /* | granted, provided that the above copyright notice appear in all | */
1519 /* | copies and that both that copyright notice and this permission | */
1520 /* | notice appear in supporting documentation. This software is | */
1521 /* | provided "as is" without express or implied warranty. | */
1522 /* +-------------------------------------------------------------------+ */
1525 #define MAXCOLORMAPSIZE 256
1527 #define TRUE 1
1528 #define FALSE 0
1530 #define CM_RED 0
1531 #define CM_GREEN 1
1532 #define CM_BLUE 2
1534 #define MAX_LWZ_BITS 12
1536 #define INTERLACE 0x40
1537 #define LOCALCOLORMAP 0x80
1538 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
1540 #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
1542 #define LM_to_uint(a,b) (((b)<<8)|(a))
1544 /* We may eventually want to use this information, but def it out for now */
1545 #if 0
1546 static struct {
1547 unsigned int Width;
1548 unsigned int Height;
1549 unsigned char ColorMap[3][MAXCOLORMAPSIZE];
1550 unsigned int BitPixel;
1551 unsigned int ColorResolution;
1552 unsigned int Background;
1553 unsigned int AspectRatio;
1554 } GifScreen;
1555 #endif
1557 int ZeroDataBlock;
1560 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1561 {
1562 gdImageLine(im, x1, y1, x2, y1, color);
1563 gdImageLine(im, x1, y2, x2, y2, color);
1564 gdImageLine(im, x1, y1, x1, y2, color);
1565 gdImageLine(im, x2, y1, x2, y2, color);
1566 }
1568 void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1569 {
1570 int x, y;
1571 for (y=y1; (y<=y2); y++) {
1572 for (x=x1; (x<=x2); x++) {
1573 gdImageSetPixel(im, x, y, color);
1574 }
1575 }
1576 }
1578 void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
1579 {
1580 int c;
1581 int x, y;
1582 int tox, toy;
1583 int i;
1584 int colorMap[gdMaxColors];
1585 for (i=0; (i<gdMaxColors); i++) {
1586 colorMap[i] = (-1);
1587 }
1588 toy = dstY;
1589 for (y=srcY; (y < (srcY + h)); y++) {
1590 tox = dstX;
1591 for (x=srcX; (x < (srcX + w)); x++) {
1592 int nc;
1593 c = gdImageGetPixel(src, x, y);
1594 /* Added 7/24/95: support transparent copies */
1595 if (gdImageGetTransparent(src) == c) {
1596 tox++;
1597 continue;
1598 }
1599 /* Have we established a mapping for this color? */
1600 if (colorMap[c] == (-1)) {
1601 /* If it's the same image, mapping is trivial */
1602 if (dst == src) {
1603 nc = c;
1604 } else {
1605 /* First look for an exact match */
1606 nc = gdImageColorExact(dst,
1607 src->red[c], src->green[c],
1608 src->blue[c]);
1609 }
1610 if (nc == (-1)) {
1611 /* No, so try to allocate it */
1612 nc = gdImageColorAllocate(dst,
1613 src->red[c], src->green[c],
1614 src->blue[c]);
1615 /* If we're out of colors, go for the
1616 closest color */
1617 if (nc == (-1)) {
1618 nc = gdImageColorClosest(dst,
1619 src->red[c], src->green[c],
1620 src->blue[c]);
1621 }
1622 }
1623 colorMap[c] = nc;
1624 }
1625 gdImageSetPixel(dst, tox, toy, colorMap[c]);
1626 tox++;
1627 }
1628 toy++;
1629 }
1630 }
1632 void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
1633 {
1634 int c;
1635 int x, y;
1636 int tox, toy;
1637 int ydest;
1638 int i;
1639 int colorMap[gdMaxColors];
1640 /* Stretch vectors */
1641 int *stx;
1642 int *sty;
1643 /* We only need to use floating point to determine the correct
1644 stretch vector for one line's worth. */
1645 double accum;
1646 stx = (int *) malloc(sizeof(int) * srcW);
1647 sty = (int *) malloc(sizeof(int) * srcH);
1648 accum = 0;
1649 for (i=0; (i < srcW); i++) {
1650 int got;
1651 accum += (double)dstW/(double)srcW;
1652 got = floor(accum);
1653 stx[i] = got;
1654 accum -= got;
1655 }
1656 accum = 0;
1657 for (i=0; (i < srcH); i++) {
1658 int got;
1659 accum += (double)dstH/(double)srcH;
1660 got = floor(accum);
1661 sty[i] = got;
1662 accum -= got;
1663 }
1664 for (i=0; (i<gdMaxColors); i++) {
1665 colorMap[i] = (-1);
1666 }
1667 toy = dstY;
1668 for (y=srcY; (y < (srcY + srcH)); y++) {
1669 for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
1670 tox = dstX;
1671 for (x=srcX; (x < (srcX + srcW)); x++) {
1672 int nc;
1673 if (!stx[x - srcX]) {
1674 continue;
1675 }
1676 c = gdImageGetPixel(src, x, y);
1677 /* Added 7/24/95: support transparent copies */
1678 if (gdImageGetTransparent(src) == c) {
1679 tox += stx[x-srcX];
1680 continue;
1681 }
1682 /* Have we established a mapping for this color? */
1683 if (colorMap[c] == (-1)) {
1684 /* If it's the same image, mapping is trivial */
1685 if (dst == src) {
1686 nc = c;
1687 } else {
1688 /* First look for an exact match */
1689 nc = gdImageColorExact(dst,
1690 src->red[c], src->green[c],
1691 src->blue[c]);
1692 }
1693 if (nc == (-1)) {
1694 /* No, so try to allocate it */
1695 nc = gdImageColorAllocate(dst,
1696 src->red[c], src->green[c],
1697 src->blue[c]);
1698 /* If we're out of colors, go for the
1699 closest color */
1700 if (nc == (-1)) {
1701 nc = gdImageColorClosest(dst,
1702 src->red[c], src->green[c],
1703 src->blue[c]);
1704 }
1705 }
1706 colorMap[c] = nc;
1707 }
1708 for (i=0; (i < stx[x - srcX]); i++) {
1709 gdImageSetPixel(dst, tox, toy, colorMap[c]);
1710 tox++;
1711 }
1712 }
1713 toy++;
1714 }
1715 }
1716 free(stx);
1717 free(sty);
1718 }
1720 int gdGetWord(int *result, FILE *in)
1721 {
1722 int r;
1723 r = getc(in);
1724 if (r == EOF) {
1725 return 0;
1726 }
1727 *result = r << 8;
1728 r = getc(in);
1729 if (r == EOF) {
1730 return 0;
1731 }
1732 *result += r;
1733 return 1;
1734 }
1736 void gdPutWord(int w, FILE *out)
1737 {
1738 putc((unsigned char)(w >> 8), out);
1739 putc((unsigned char)(w & 0xFF), out);
1740 }
1742 int gdGetByte(int *result, FILE *in)
1743 {
1744 int r;
1745 r = getc(in);
1746 if (r == EOF) {
1747 return 0;
1748 }
1749 *result = r;
1750 return 1;
1751 }
1753 gdImagePtr gdImageCreateFromGd(FILE *in)
1754 {
1755 int sx, sy;
1756 int x, y;
1757 int i;
1758 gdImagePtr im;
1759 if (!gdGetWord(&sx, in)) {
1760 goto fail1;
1761 }
1762 if (!gdGetWord(&sy, in)) {
1763 goto fail1;
1764 }
1765 im = gdImageCreate(sx, sy);
1766 if (!gdGetByte(&im->colorsTotal, in)) {
1767 goto fail2;
1768 }
1769 if (!gdGetWord(&im->transparent, in)) {
1770 goto fail2;
1771 }
1772 if (im->transparent == 257) {
1773 im->transparent = (-1);
1774 }
1775 for (i=0; (i<gdMaxColors); i++) {
1776 if (!gdGetByte(&im->red[i], in)) {
1777 goto fail2;
1778 }
1779 if (!gdGetByte(&im->green[i], in)) {
1780 goto fail2;
1781 }
1782 if (!gdGetByte(&im->blue[i], in)) {
1783 goto fail2;
1784 }
1785 }
1786 for (y=0; (y<sy); y++) {
1787 for (x=0; (x<sx); x++) {
1788 int ch;
1789 ch = getc(in);
1790 if (ch == EOF) {
1791 gdImageDestroy(im);
1792 return 0;
1793 }
1794 /* ROW-MAJOR IN GD 1.3 */
1795 im->pixels[y][x] = ch;
1796 }
1797 }
1798 return im;
1799 fail2:
1800 gdImageDestroy(im);
1801 fail1:
1802 return 0;
1803 }
1805 void gdImageGd(gdImagePtr im, FILE *out)
1806 {
1807 int x, y;
1808 int i;
1809 int trans;
1810 gdPutWord(im->sx, out);
1811 gdPutWord(im->sy, out);
1812 putc((unsigned char)im->colorsTotal, out);
1813 trans = im->transparent;
1814 if (trans == (-1)) {
1815 trans = 257;
1816 }
1817 gdPutWord(trans, out);
1818 for (i=0; (i<gdMaxColors); i++) {
1819 putc((unsigned char)im->red[i], out);
1820 putc((unsigned char)im->green[i], out);
1821 putc((unsigned char)im->blue[i], out);
1822 }
1823 for (y=0; (y < im->sy); y++) {
1824 for (x=0; (x < im->sx); x++) {
1825 /* ROW-MAJOR IN GD 1.3 */
1826 putc((unsigned char)im->pixels[y][x], out);
1827 }
1828 }
1829 }
1831 gdImagePtr
1832 gdImageCreateFromXbm(FILE *fd)
1833 {
1834 gdImagePtr im;
1835 int bit;
1836 int w, h;
1837 int bytes;
1838 int ch;
1839 int i, x, y;
1840 char *sp;
1841 char s[161];
1842 if (!fgets(s, 160, fd)) {
1843 return 0;
1844 }
1845 sp = &s[0];
1846 /* Skip #define */
1847 sp = strchr(sp, ' ');
1848 if (!sp) {
1849 return 0;
1850 }
1851 /* Skip width label */
1852 sp++;
1853 sp = strchr(sp, ' ');
1854 if (!sp) {
1855 return 0;
1856 }
1857 /* Get width */
1858 w = atoi(sp + 1);
1859 if (!w) {
1860 return 0;
1861 }
1862 if (!fgets(s, 160, fd)) {
1863 return 0;
1864 }
1865 sp = s;
1866 /* Skip #define */
1867 sp = strchr(sp, ' ');
1868 if (!sp) {
1869 return 0;
1870 }
1871 /* Skip height label */
1872 sp++;
1873 sp = strchr(sp, ' ');
1874 if (!sp) {
1875 return 0;
1876 }
1877 /* Get height */
1878 h = atoi(sp + 1);
1879 if (!h) {
1880 return 0;
1881 }
1882 /* Skip declaration line */
1883 if (!fgets(s, 160, fd)) {
1884 return 0;
1885 }
1886 bytes = (w * h / 8) + 1;
1887 im = gdImageCreate(w, h);
1888 gdImageColorAllocate(im, 255, 255, 255);
1889 gdImageColorAllocate(im, 0, 0, 0);
1890 x = 0;
1891 y = 0;
1892 for (i=0; (i < bytes); i++) {
1893 char h[3];
1894 int b;
1895 /* Skip spaces, commas, CRs, 0x */
1896 while(1) {
1897 ch = getc(fd);
1898 if (ch == EOF) {
1899 goto fail;
1900 }
1901 if (ch == 'x') {
1902 break;
1903 }
1904 }
1905 /* Get hex value */
1906 ch = getc(fd);
1907 if (ch == EOF) {
1908 goto fail;
1909 }
1910 h[0] = ch;
1911 ch = getc(fd);
1912 if (ch == EOF) {
1913 goto fail;
1914 }
1915 h[1] = ch;
1916 h[2] = '\0';
1917 sscanf(h, "%x", &b);
1918 for (bit = 1; (bit <= 128); (bit = bit << 1)) {
1919 gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
1920 if (x == im->sx) {
1921 x = 0;
1922 y++;
1923 if (y == im->sy) {
1924 return im;
1925 }
1926 /* Fix 8/8/95 */
1927 break;
1928 }
1929 }
1930 }
1931 /* Shouldn't happen */
1932 fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
1933 return 0;
1934 fail:
1935 gdImageDestroy(im);
1936 return 0;
1937 }
1939 void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
1940 {
1941 int i;
1942 int lx, ly;
1943 if (!n) {
1944 return;
1945 }
1946 lx = p->x;
1947 ly = p->y;
1948 gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
1949 for (i=1; (i < n); i++) {
1950 p++;
1951 gdImageLine(im, lx, ly, p->x, p->y, c);
1952 lx = p->x;
1953 ly = p->y;
1954 }
1955 }
1957 int gdCompareInt(const void *a, const void *b);
1959 void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
1960 {
1961 int i;
1962 int y;
1963 int y1, y2;
1964 int ints;
1965 if (!n) {
1966 return;
1967 }
1968 if (!im->polyAllocated) {
1969 im->polyInts = (int *) malloc(sizeof(int) * n);
1970 im->polyAllocated = n;
1971 }
1972 if (im->polyAllocated < n) {
1973 while (im->polyAllocated < n) {
1974 im->polyAllocated *= 2;
1975 }
1976 im->polyInts = (int *) realloc(im->polyInts,
1977 sizeof(int) * im->polyAllocated);
1978 }
1979 y1 = p[0].y;
1980 y2 = p[0].y;
1981 for (i=1; (i < n); i++) {
1982 if (p[i].y < y1) {
1983 y1 = p[i].y;
1984 }
1985 if (p[i].y > y2) {
1986 y2 = p[i].y;
1987 }
1988 }
1989 /* Fix in 1.3: count a vertex only once */
1990 for (y=y1; (y < y2); y++) {
1991 int interLast = 0;
1992 int dirLast = 0;
1993 int interFirst = 1;
1994 ints = 0;
1995 for (i=0; (i <= n); i++) {
1996 int x1, x2;
1997 int y1, y2;
1998 int dir;
1999 int ind1, ind2;
2000 int lastInd1 = 0;
2001 if ((i == n) || (!i)) {
2002 ind1 = n-1;
2003 ind2 = 0;
2004 } else {
2005 ind1 = i-1;
2006 ind2 = i;
2007 }
2008 y1 = p[ind1].y;
2009 y2 = p[ind2].y;
2010 if (y1 < y2) {
2011 y1 = p[ind1].y;
2012 y2 = p[ind2].y;
2013 x1 = p[ind1].x;
2014 x2 = p[ind2].x;
2015 dir = -1;
2016 } else if (y1 > y2) {
2017 y2 = p[ind1].y;
2018 y1 = p[ind2].y;
2019 x2 = p[ind1].x;
2020 x1 = p[ind2].x;
2021 dir = 1;
2022 } else {
2023 /* Horizontal; just draw it */
2024 gdImageLine(im,
2025 p[ind1].x, y1,
2026 p[ind2].x, y1,
2027 c);
2028 continue;
2029 }
2030 if ((y >= y1) && (y <= y2)) {
2031 int inter =
2032 (y-y1) * (x2-x1) / (y2-y1) + x1;
2033 /* Only count intersections once
2034 except at maxima and minima. Also,
2035 if two consecutive intersections are
2036 endpoints of the same horizontal line
2037 that is not at a maxima or minima,
2038 discard the leftmost of the two. */
2039 if (!interFirst) {
2040 if ((p[ind1].y == p[lastInd1].y) &&
2041 (p[ind1].x != p[lastInd1].x)) {
2042 if (dir == dirLast) {
2043 if (inter > interLast) {
2044 /* Replace the old one */
2045 im->polyInts[ints] = inter;
2046 } else {
2047 /* Discard this one */
2048 }
2049 continue;
2050 }
2051 }
2052 if (inter == interLast) {
2053 if (dir == dirLast) {
2054 continue;
2055 }
2056 }
2057 }
2058 if (i > 0) {
2059 im->polyInts[ints++] = inter;
2060 }
2061 lastInd1 = i;
2062 dirLast = dir;
2063 interLast = inter;
2064 interFirst = 0;
2065 }
2066 }
2067 qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
2068 for (i=0; (i < (ints-1)); i+=2) {
2069 gdImageLine(im, im->polyInts[i], y,
2070 im->polyInts[i+1], y, c);
2071 }
2072 }
2073 }
2075 int gdCompareInt(const void *a, const void *b)
2076 {
2077 return (*(const int *)a) - (*(const int *)b);
2078 }
2080 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
2081 {
2082 if (im->style) {
2083 free(im->style);
2084 }
2085 im->style = (int *)
2086 malloc(sizeof(int) * noOfPixels);
2087 memcpy(im->style, style, sizeof(int) * noOfPixels);
2088 im->styleLength = noOfPixels;
2089 im->stylePos = 0;
2090 }
2092 void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
2093 {
2094 int i;
2095 im->brush = brush;
2096 for (i=0; (i < gdImageColorsTotal(brush)); i++) {
2097 int index;
2098 index = gdImageColorExact(im,
2099 gdImageRed(brush, i),
2100 gdImageGreen(brush, i),
2101 gdImageBlue(brush, i));
2102 if (index == (-1)) {
2103 index = gdImageColorAllocate(im,
2104 gdImageRed(brush, i),
2105 gdImageGreen(brush, i),
2106 gdImageBlue(brush, i));
2107 if (index == (-1)) {
2108 index = gdImageColorClosest(im,
2109 gdImageRed(brush, i),
2110 gdImageGreen(brush, i),
2111 gdImageBlue(brush, i));
2112 }
2113 }
2114 im->brushColorMap[i] = index;
2115 }
2116 }
2118 void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
2119 {
2120 int i;
2121 im->tile = tile;
2122 for (i=0; (i < gdImageColorsTotal(tile)); i++) {
2123 int index;
2124 index = gdImageColorExact(im,
2125 gdImageRed(tile, i),
2126 gdImageGreen(tile, i),
2127 gdImageBlue(tile, i));
2128 if (index == (-1)) {
2129 index = gdImageColorAllocate(im,
2130 gdImageRed(tile, i),
2131 gdImageGreen(tile, i),
2132 gdImageBlue(tile, i));
2133 if (index == (-1)) {
2134 index = gdImageColorClosest(im,
2135 gdImageRed(tile, i),
2136 gdImageGreen(tile, i),
2137 gdImageBlue(tile, i));
2138 }
2139 }
2140 im->tileColorMap[i] = index;
2141 }
2142 }
2144 void gdImageInterlace(gdImagePtr im, int interlaceArg)
2145 {
2146 im->interlace = interlaceArg;
2147 }