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)
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);
19 im->polyAllocated = 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));
31 im->transparent = (-1);
36 void gdImageDestroy(gdImagePtr im)
39 for (i=0; (i<im->sy); i++) {
52 int gdImageColorClosest(gdImagePtr im, int r, int g, int b)
58 for (i=0; (i<(im->colorsTotal)); i++) {
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)) {
75 int gdImageColorExact(gdImagePtr im, int r, int g, int b)
78 for (i=0; (i<(im->colorsTotal)); i++) {
82 if ((im->red[i] == r) &&
83 (im->green[i] == g) &&
91 int gdImageColorAllocate(gdImagePtr im, int r, int g, int b)
95 for (i=0; (i<(im->colorsTotal)); i++) {
102 ct = im->colorsTotal;
103 if (ct == gdMaxColors) {
115 void gdImageColorDeallocate(gdImagePtr im, int color)
121 void gdImageColorTransparent(gdImagePtr im, int color)
123 im->transparent = color;
126 void gdImageSetPixel(gdImagePtr im, int x, int y, int color)
132 /* Refuse to draw if no style is set. */
135 p = im->style[im->stylePos++];
137 if (p != (gdTransparent)) {
138 gdImageSetPixel(im, x, y, p);
140 im->stylePos = im->stylePos % im->styleLength;
142 case gdStyledBrushed:
144 /* Refuse to draw if no style is set. */
147 p = im->style[im->stylePos++];
148 if ((p != gdTransparent) && (p != 0)) {
149 gdImageSetPixel(im, x, y, gdBrushed);
151 im->stylePos = im->stylePos % im->styleLength;
154 gdImageBrushApply(im, x, y);
157 gdImageTileApply(im, x, y);
160 if (gdImageBoundsSafe(im, x, y)) {
161 /* NOW ROW-MAJOR IN GD 1.3 */
162 im->pixels[y][x] = color;
168 static void gdImageBrushApply(gdImagePtr im, int x, int y)
178 hy = gdImageSY(im->brush)/2;
180 y2 = y1 + gdImageSY(im->brush);
181 hx = gdImageSX(im->brush)/2;
183 x2 = x1 + gdImageSX(im->brush);
185 for (ly = y1; (ly < y2); ly++) {
187 for (lx = x1; (lx < x2); lx++) {
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]);
201 static void gdImageTileApply(gdImagePtr im, int x, int y)
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]);
218 int gdImageGetPixel(gdImagePtr im, int x, int y)
220 if (gdImageBoundsSafe(im, x, y)) {
221 /* NOW ROW-MAJOR IN GD 1.3 */
222 return im->pixels[y][x];
228 /* Bresenham as presented in Foley & Van Dam */
230 void gdImageLine(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
232 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
238 incr2 = 2 * (dy - dx);
250 gdImageSetPixel(im, x, y, color);
251 if (((y2 - y1) * ydirflag) > 0) {
260 gdImageSetPixel(im, x, y, color);
271 gdImageSetPixel(im, x, y, color);
277 incr2 = 2 * (dx - dy);
289 gdImageSetPixel(im, x, y, color);
290 if (((x2 - x1) * xdirflag) > 0) {
299 gdImageSetPixel(im, x, y, color);
310 gdImageSetPixel(im, x, y, color);
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)
321 int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
329 incr2 = 2 * (dy - dx);
341 dashedSet(im, x, y, color, &on, &dashStep);
342 if (((y2 - y1) * ydirflag) > 0) {
351 dashedSet(im, x, y, color, &on, &dashStep);
362 dashedSet(im, x, y, color, &on, &dashStep);
368 incr2 = 2 * (dx - dy);
380 dashedSet(im, x, y, color, &on, &dashStep);
381 if (((x2 - x1) * xdirflag) > 0) {
390 dashedSet(im, x, y, color, &on, &dashStep);
401 dashedSet(im, x, y, color, &on, &dashStep);
407 static void dashedSet(gdImagePtr im, int x, int y, int color,
408 int *onP, int *dashStepP)
410 int dashStep = *dashStepP;
413 if (dashStep == gdDashSize) {
418 gdImageSetPixel(im, x, y, color);
420 *dashStepP = dashStep;
425 int gdImageBoundsSafe(gdImagePtr im, int x, int y)
427 return (!(((y < 0) || (y >= im->sy)) ||
428 ((x < 0) || (x >= im->sx))));
431 void gdImageChar(gdImagePtr im, gdFontPtr f, int x, int y,
439 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
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);
455 void gdImageCharUp(gdImagePtr im, gdFontPtr f,
456 int x, int y, int c, int color)
463 if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
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);
479 void gdImageString(gdImagePtr im, gdFontPtr f,
480 int x, int y, unsigned char *s, int color)
485 for (i=0; (i<l); i++) {
486 gdImageChar(im, f, x, y, s[i], color);
491 void gdImageStringUp(gdImagePtr im, gdFontPtr f,
492 int x, int y, unsigned char *s, int color)
497 for (i=0; (i<l); i++) {
498 gdImageCharUp(im, f, x, y, s[i], color);
503 static int strlen16(unsigned short *s);
505 void gdImageString16(gdImagePtr im, gdFontPtr f,
506 int x, int y, unsigned short *s, int color)
511 for (i=0; (i<l); i++) {
512 gdImageChar(im, f, x, y, s[i], color);
517 void gdImageStringUp16(gdImagePtr im, gdFontPtr f,
518 int x, int y, unsigned short *s, int color)
523 for (i=0; (i<l); i++) {
524 gdImageCharUp(im, f, x, y, s[i], color);
529 static int strlen16(unsigned short *s)
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)
559 for (i=s; (i <= e); i++) {
561 x = ((long)cost[i % 360] * (long)w2 / costScale) + cx;
562 y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
564 gdImageLine(im, lx, ly, x, y, color);
573 /* Bresenham octant code, which I should use eventually */
579 gdImageSetPixel(im, cx+x, cy+y, color);
583 d += 4 * (x - y) + 10;
589 gdImageSetPixel(im, cx+x, cy+y, color);
593 void gdImageFillToBorder(gdImagePtr im, int x, int y, int border, int color)
597 int leftLimit, rightLimit;
601 /* Refuse to fill to a non-solid border */
604 for (i = x; (i >= 0); i--) {
605 if (gdImageGetPixel(im, i, y) == border) {
608 gdImageSetPixel(im, i, y, color);
611 if (leftLimit == (-1)) {
616 for (i = (x+1); (i < im->sx); i++) {
617 if (gdImageGetPixel(im, i, y) == border) {
620 gdImageSetPixel(im, i, y, color);
623 /* Look at lines above and below and start paints */
627 for (i = leftLimit; (i <= rightLimit); i++) {
629 c = gdImageGetPixel(im, i, y-1);
631 if ((c != border) && (c != color)) {
632 gdImageFillToBorder(im, i, y-1,
636 } else if ((c == border) || (c == color)) {
642 if (y < ((im->sy) - 1)) {
644 for (i = leftLimit; (i <= rightLimit); i++) {
646 c = gdImageGetPixel(im, i, y+1);
648 if ((c != border) && (c != color)) {
649 gdImageFillToBorder(im, i, y+1,
653 } else if ((c == border) || (c == color)) {
660 void gdImageFill(gdImagePtr im, int x, int y, int color)
664 int leftLimit, rightLimit;
666 old = gdImageGetPixel(im, x, y);
667 if (color == gdTiled) {
668 /* Tile fill -- got to watch out! */
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)) {
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 */
689 /* Nothing to be done */
695 for (i = x; (i >= 0); i--) {
696 if (gdImageGetPixel(im, i, y) != old) {
699 gdImageSetPixel(im, i, y, color);
702 if (leftLimit == (-1)) {
707 for (i = (x+1); (i < im->sx); i++) {
708 if (gdImageGetPixel(im, i, y) != old) {
711 gdImageSetPixel(im, i, y, color);
714 /* Look at lines above and below and start paints */
718 for (i = leftLimit; (i <= rightLimit); i++) {
720 c = gdImageGetPixel(im, i, y-1);
723 gdImageFill(im, i, y-1, color);
726 } else if (c != old) {
732 if (y < ((im->sy) - 1)) {
734 for (i = leftLimit; (i <= rightLimit); i++) {
736 c = gdImageGetPixel(im, i, y+1);
739 gdImageFill(im, i, y+1, color);
742 } else if (c != old) {
749 /* Code drawn from ppmtogif.c, from the pbmplus package
751 ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
752 ** Lempel-Zim compression based on "compress".
754 ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
756 ** Copyright (C) 1989 by Jef Poskanzer.
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
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.
769 * Heavily modified by Mouse, 1998-02-12.
770 * Remove LZW compression.
771 * Added miGIF run length compression.
776 * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
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)
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 */
799 /* All set, let's do it. */
801 out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
802 im->red, im->green, im->blue, im);
806 colorstobpp(int colors)
812 else if ( colors <= 4 )
814 else if ( colors <= 8 )
816 else if ( colors <= 16 )
818 else if ( colors <= 32 )
820 else if ( colors <= 64 )
822 else if ( colors <= 128 )
824 else if ( colors <= 256 )
829 /*****************************************************************************
831 * GIFENCODE.C - GIF Image compression interface
833 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
834 * BitsPerPixel, Red, Green, Blue, gdImagePtr )
836 *****************************************************************************/
841 static int Width, Height;
842 static int curx, cury;
843 static long CountDown;
845 static int Interlace;
848 * Bump the 'curx' and 'cury' to point to the next pixel
854 * Bump the current X position
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.
863 if( curx == Width ) {
873 if( cury >= Height ) {
881 if( cury >= Height ) {
889 if( cury >= Height ) {
904 * Return the next pixel from the image
907 GIFNextPixel(gdImagePtr im)
916 r = gdImageGetPixel(im, curx, cury);
926 GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
936 Interlace = GInterlace;
938 ColorMapSize = 1 << BitsPerPixel;
940 RWidth = Width = GWidth;
941 RHeight = Height = GHeight;
942 LeftOfs = TopOfs = 0;
944 Resolution = BitsPerPixel;
947 * Calculate number of bits we are expecting
949 CountDown = (long)Width * (long)Height;
952 * Indicate which pass we are on (if interlace)
957 * The initial code size
959 if( BitsPerPixel <= 1 )
962 InitCodeSize = BitsPerPixel;
965 * Set up the current x and y position
970 * Write the Magic header
972 fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
975 * Write out the screen width and height
977 Putword( RWidth, fp );
978 Putword( RHeight, fp );
981 * Indicate that there is a global colour map
983 B = 0x80; /* Yes, there is a color map */
986 * OR in the resolution
988 B |= (Resolution - 1) << 4;
991 * OR in the Bits per Pixel
993 B |= (BitsPerPixel - 1);
1001 * Write out the Background colour
1003 fputc( Background, fp );
1006 * Byte of 0's (future expansion)
1011 * Write out the Global Colour Map
1013 for( i=0; i<ColorMapSize; ++i ) {
1014 fputc( Red[i], fp );
1015 fputc( Green[i], fp );
1016 fputc( Blue[i], fp );
1020 * Write out extension for transparent colour index, if necessary.
1022 if ( Transparent >= 0 ) {
1029 fputc( (unsigned char) Transparent, fp );
1034 * Write an Image separator
1039 * Write the Image header
1042 Putword( LeftOfs, fp );
1043 Putword( TopOfs, fp );
1044 Putword( Width, fp );
1045 Putword( Height, fp );
1048 * Write out whether or not the image is interlaced
1056 * Write out the initial code size
1058 fputc( InitCodeSize, fp );
1061 * Go and actually compress the data
1063 compress( InitCodeSize+1, fp, im, Background );
1066 * Write out a Zero-length packet (to end the series)
1071 * Write the GIF file terminator
1077 * Write out a word to the GIF file
1080 Putword(int w, FILE *fp)
1082 fputc( w & 0xff, fp );
1083 fputc( (w / 256) & 0xff, fp );
1088 /*-----------------------------------------------------------------------
1090 * miGIF Compression - mouse and ivo's GIF-compatible compression
1092 * -run length encoding compression routines-
1094 * Copyright (C) 1998 Hutchison Avenue Software Corporation
1095 * http://www.hasc.com
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
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.
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.
1121 * mouse@rodents.montreal.qc.ca
1122 * 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
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.
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;
1151 static unsigned char oblock[256];
1154 /* Used only when debugging GIF compression code */
1155 /* #define DEBUGGING_ENVARS */
1157 #ifdef DEBUGGING_ENVARS
1159 static int verbose_set = 0;
1161 #define VERBOSE (verbose_set?verbose:set_verbose())
1163 static int set_verbose(void)
1165 verbose = !!getenv("GIF_VERBOSE");
1177 static const char *binformat(unsigned int v, int nbits)
1179 static char bufs[8][64];
1180 static int bhand = 0;
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++ = '.';
1193 return(&bufs[bhand][0]);
1196 static void write_block(void)
1201 { printf("write_block %d:",oblen);
1202 for (i=0;i<oblen;i++) printf(" %02x",oblock[i]);
1206 fwrite(&oblock[0],1,oblen,ofile);
1210 static void block_out(unsigned char c)
1212 if (VERBOSE) printf("block_out %s\n",binformat(c,8));
1213 oblock[oblen++] = c;
1214 if (oblen >= 255) write_block();
1217 static void block_flush(void)
1219 if (VERBOSE) printf("block_flush\n");
1220 if (oblen > 0) write_block();
1223 static void output(int val)
1225 if (VERBOSE) printf("output %s [%s %d %d]\n",binformat(val,out_bits),binformat(obuf,obits),obits,out_bits);
1226 obuf |= val << obits;
1229 { block_out(obuf&0xff);
1233 if (VERBOSE) printf("output leaving [%s %d]\n",binformat(obuf,obits),obits);
1236 static void output_flush(void)
1238 if (VERBOSE) printf("output_flush\n");
1239 if (obits > 0) block_out(obuf);
1243 static void did_clear(void)
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;
1254 static void output_plain(int c)
1256 if (VERBOSE) printf("output_plain %s\n",binformat(c,out_bits));
1260 if (out_count >= out_bump)
1262 out_bump += 1 << (out_bits - 1);
1264 if (out_count >= out_clear)
1265 { output(code_clear);
1270 static unsigned int isqrt(unsigned int x)
1275 if (x < 2) return(x);
1276 for (v=x,r=1;v;v>>=2,r<<=1) ;
1278 { v = ((x / r) + r) / 2;
1279 if ((v == r) || (v == r+1)) return(r);
1284 static unsigned int compute_triangle_count(unsigned int count, unsigned int nrepcodes)
1286 unsigned int perrep;
1290 perrep = (nrepcodes * (nrepcodes+1)) / 2;
1291 while (count >= perrep)
1292 { ncost += nrepcodes;
1298 while ((n*(n+1)) >= 2*count) n --;
1299 while ((n*(n+1)) < 2*count) n ++;
1305 static void max_out_clear(void)
1307 out_clear = max_ocodes;
1310 static void reset_out_clear(void)
1312 out_clear = out_clear_init;
1313 if (out_count >= out_clear)
1314 { output(code_clear);
1319 static void rl_flush_fromclear(int count)
1323 if (VERBOSE) printf("rl_flush_fromclear %d\n",count);
1325 rl_table_pixel = rl_pixel;
1330 output_plain(rl_pixel);
1333 else if (count >= n)
1335 output_plain(rl_basecode+n-2);
1338 else if (count == 1)
1340 output_plain(rl_pixel);
1345 output_plain(rl_basecode+count-2);
1348 if (out_count == 0) n = 1; else n ++;
1351 if (VERBOSE) printf("rl_flush_fromclear leaving table_max=%d\n",rl_table_max);
1354 static void rl_flush_clearorrep(int count)
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);
1363 rl_flush_fromclear(count);
1366 { for (;count>0;count--) output_plain(rl_pixel);
1370 static void rl_flush_withtable(int count)
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);
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);
1389 rl_flush_fromclear(count);
1393 for (;repmax>0;repmax--) output_plain(rl_basecode+rl_table_max-2);
1396 { rl_flush_fromclear(leftover);
1398 else if (leftover == 1)
1399 { output_plain(rl_pixel);
1402 { output_plain(rl_basecode+leftover-2);
1408 static void rl_flush(void)
1411 if (VERBOSE) printf("rl_flush [ %d %d\n",rl_count,rl_pixel);
1413 { output_plain(rl_pixel);
1415 if (VERBOSE) printf("rl_flush ]\n");
1419 { rl_flush_fromclear(rl_count);
1421 else if ((rl_table_max < 2) || (rl_table_pixel != rl_pixel))
1422 { rl_flush_clearorrep(rl_count);
1425 { rl_flush_withtable(rl_count);
1427 if (VERBOSE) printf("rl_flush ]\n");
1431 static void compress(int init_bits, FILE *outfile, gdImagePtr im, int background)
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");
1450 { out_clear_init = atoi(ocienv);
1451 if (VERBOSE) printf("[overriding out_clear_init to %d]\n",out_clear_init);
1455 out_bits_init = init_bits;
1456 max_ocodes = (1 << GIFBITS) - ((1 << (out_bits_init - 1)) + 3);
1461 { c = GIFNextPixel(im);
1462 if ((rl_count > 0) && (c != rl_pixel)) rl_flush();
1463 if (c == EOF) break;
1476 /*-----------------------------------------------------------------------
1478 * End of miGIF section - See copyright notice at start of section.
1480 *-----------------------------------------------------------------------
1483 ******************************************************************************
1485 * GIF Specific routines
1487 ******************************************************************************/
1490 * Number of characters so far in this 'packet'
1495 * Define the storage for the packet accumulator
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
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
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 */
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;
1560 void gdImageRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
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);
1568 void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color)
1571 for (y=y1; (y<=y2); y++) {
1572 for (x=x1; (x<=x2); x++) {
1573 gdImageSetPixel(im, x, y, color);
1578 void gdImageCopy(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
1584 int colorMap[gdMaxColors];
1585 for (i=0; (i<gdMaxColors); i++) {
1589 for (y=srcY; (y < (srcY + h)); y++) {
1591 for (x=srcX; (x < (srcX + w)); x++) {
1593 c = gdImageGetPixel(src, x, y);
1594 /* Added 7/24/95: support transparent copies */
1595 if (gdImageGetTransparent(src) == c) {
1599 /* Have we established a mapping for this color? */
1600 if (colorMap[c] == (-1)) {
1601 /* If it's the same image, mapping is trivial */
1605 /* First look for an exact match */
1606 nc = gdImageColorExact(dst,
1607 src->red[c], src->green[c],
1611 /* No, so try to allocate it */
1612 nc = gdImageColorAllocate(dst,
1613 src->red[c], src->green[c],
1615 /* If we're out of colors, go for the
1618 nc = gdImageColorClosest(dst,
1619 src->red[c], src->green[c],
1625 gdImageSetPixel(dst, tox, toy, colorMap[c]);
1632 void gdImageCopyResized(gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
1639 int colorMap[gdMaxColors];
1640 /* Stretch vectors */
1643 /* We only need to use floating point to determine the correct
1644 stretch vector for one line's worth. */
1646 stx = (int *) malloc(sizeof(int) * srcW);
1647 sty = (int *) malloc(sizeof(int) * srcH);
1649 for (i=0; (i < srcW); i++) {
1651 accum += (double)dstW/(double)srcW;
1657 for (i=0; (i < srcH); i++) {
1659 accum += (double)dstH/(double)srcH;
1664 for (i=0; (i<gdMaxColors); i++) {
1668 for (y=srcY; (y < (srcY + srcH)); y++) {
1669 for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
1671 for (x=srcX; (x < (srcX + srcW)); x++) {
1673 if (!stx[x - srcX]) {
1676 c = gdImageGetPixel(src, x, y);
1677 /* Added 7/24/95: support transparent copies */
1678 if (gdImageGetTransparent(src) == c) {
1682 /* Have we established a mapping for this color? */
1683 if (colorMap[c] == (-1)) {
1684 /* If it's the same image, mapping is trivial */
1688 /* First look for an exact match */
1689 nc = gdImageColorExact(dst,
1690 src->red[c], src->green[c],
1694 /* No, so try to allocate it */
1695 nc = gdImageColorAllocate(dst,
1696 src->red[c], src->green[c],
1698 /* If we're out of colors, go for the
1701 nc = gdImageColorClosest(dst,
1702 src->red[c], src->green[c],
1708 for (i=0; (i < stx[x - srcX]); i++) {
1709 gdImageSetPixel(dst, tox, toy, colorMap[c]);
1720 int gdGetWord(int *result, FILE *in)
1736 void gdPutWord(int w, FILE *out)
1738 putc((unsigned char)(w >> 8), out);
1739 putc((unsigned char)(w & 0xFF), out);
1742 int gdGetByte(int *result, FILE *in)
1753 gdImagePtr gdImageCreateFromGd(FILE *in)
1759 if (!gdGetWord(&sx, in)) {
1762 if (!gdGetWord(&sy, in)) {
1765 im = gdImageCreate(sx, sy);
1766 if (!gdGetByte(&im->colorsTotal, in)) {
1769 if (!gdGetWord(&im->transparent, in)) {
1772 if (im->transparent == 257) {
1773 im->transparent = (-1);
1775 for (i=0; (i<gdMaxColors); i++) {
1776 if (!gdGetByte(&im->red[i], in)) {
1779 if (!gdGetByte(&im->green[i], in)) {
1782 if (!gdGetByte(&im->blue[i], in)) {
1786 for (y=0; (y<sy); y++) {
1787 for (x=0; (x<sx); x++) {
1794 /* ROW-MAJOR IN GD 1.3 */
1795 im->pixels[y][x] = ch;
1805 void gdImageGd(gdImagePtr im, FILE *out)
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)) {
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);
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);
1832 gdImageCreateFromXbm(FILE *fd)
1842 if (!fgets(s, 160, fd)) {
1847 sp = strchr(sp, ' ');
1851 /* Skip width label */
1853 sp = strchr(sp, ' ');
1862 if (!fgets(s, 160, fd)) {
1867 sp = strchr(sp, ' ');
1871 /* Skip height label */
1873 sp = strchr(sp, ' ');
1882 /* Skip declaration line */
1883 if (!fgets(s, 160, fd)) {
1886 bytes = (w * h / 8) + 1;
1887 im = gdImageCreate(w, h);
1888 gdImageColorAllocate(im, 255, 255, 255);
1889 gdImageColorAllocate(im, 0, 0, 0);
1892 for (i=0; (i < bytes); i++) {
1895 /* Skip spaces, commas, CRs, 0x */
1917 sscanf(h, "%x", &b);
1918 for (bit = 1; (bit <= 128); (bit = bit << 1)) {
1919 gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
1931 /* Shouldn't happen */
1932 fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
1939 void gdImagePolygon(gdImagePtr im, gdPointPtr p, int n, int c)
1948 gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
1949 for (i=1; (i < n); i++) {
1951 gdImageLine(im, lx, ly, p->x, p->y, c);
1957 int gdCompareInt(const void *a, const void *b);
1959 void gdImageFilledPolygon(gdImagePtr im, gdPointPtr p, int n, int c)
1968 if (!im->polyAllocated) {
1969 im->polyInts = (int *) malloc(sizeof(int) * n);
1970 im->polyAllocated = n;
1972 if (im->polyAllocated < n) {
1973 while (im->polyAllocated < n) {
1974 im->polyAllocated *= 2;
1976 im->polyInts = (int *) realloc(im->polyInts,
1977 sizeof(int) * im->polyAllocated);
1981 for (i=1; (i < n); i++) {
1989 /* Fix in 1.3: count a vertex only once */
1990 for (y=y1; (y < y2); y++) {
1995 for (i=0; (i <= n); i++) {
2001 if ((i == n) || (!i)) {
2016 } else if (y1 > y2) {
2023 /* Horizontal; just draw it */
2030 if ((y >= y1) && (y <= y2)) {
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. */
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;
2047 /* Discard this one */
2052 if (inter == interLast) {
2053 if (dir == dirLast) {
2059 im->polyInts[ints++] = inter;
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);
2075 int gdCompareInt(const void *a, const void *b)
2077 return (*(const int *)a) - (*(const int *)b);
2080 void gdImageSetStyle(gdImagePtr im, int *style, int noOfPixels)
2086 malloc(sizeof(int) * noOfPixels);
2087 memcpy(im->style, style, sizeof(int) * noOfPixels);
2088 im->styleLength = noOfPixels;
2092 void gdImageSetBrush(gdImagePtr im, gdImagePtr brush)
2096 for (i=0; (i < gdImageColorsTotal(brush)); i++) {
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));
2114 im->brushColorMap[i] = index;
2118 void gdImageSetTile(gdImagePtr im, gdImagePtr tile)
2122 for (i=0; (i < gdImageColorsTotal(tile)); i++) {
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));
2140 im->tileColorMap[i] = index;
2144 void gdImageInterlace(gdImagePtr im, int interlaceArg)
2146 im->interlace = interlaceArg;