|
|
1.1 paf 1: /** @file
2: Parser: image manipulations impl1.
3:
1.2 paf 4: Copyright (c) 2001-2004 ArtLebedev Group (http://www.artlebedev.com)
1.1 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
6: based on: gd
7:
8: Written by Tom Boutell, 5/94.
9: Copyright 1994, Cold Spring Harbor Labs.
10: Permission granted to use this code in any fashion provided
11: that this notice is retained and any alterations are
12: labeled as such. It is requested, but not required, that
13: you share extensions to this module with us so that we
14: can incorporate them into new versions.
15: */
16:
1.4 ! paf 17: static const char * const IDENT_GIF_C="$Date: 2004/03/01 13:33:11 $";
1.1 paf 18:
19: #include "gif.h"
20:
21: #include "mtables.h"
22: //#include "pa_common.h"
23:
24: //static void BrushApply(int x, int y);
25: //static void TileApply(int x, int y);
26:
27: void gdImage::Create(int asx, int asy) {
28: sx = asx;
29: sy = asy;
30:
31: int i;
32: pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx);
33: polyInts = 0;
34: polyAllocated = 0;
35: lineWidth = 1;
36: for (i=0; (i<asx); i++)
37: pixels[i] = (unsigned char *) malloc_atomic(asy);
38: colorsTotal = 0;
39: transparent = (-1);
40: interlace = 0;
41: }
42:
43: int gdImage::ColorClosest(int r, int g, int b, int tolerance)
44: {
45: int i;
46: long rd, gd, bd;
47: int ct = (-1);
48: long mindist = 0;
49: for (i=0; (i<(colorsTotal)); i++) {
50: long dist;
51: if (open[i]) {
52: continue;
53: }
54: rd = (red[i] - r);
55: gd = (green[i] - g);
56: bd = (blue[i] - b);
57: dist = rd * rd + gd * gd + bd * bd;
58: if ((i == 0) || (dist < mindist+tolerance)) {
59: mindist = dist;
60: ct = i;
61: }
62: }
63: return mindist<tolerance?ct:-1;
64: }
65:
66: int gdImage::ColorExact(int r, int g, int b)
67: {
68: int i;
69: for (i=0; (i<(colorsTotal)); i++) {
70: if (open[i]) {
71: continue;
72: }
73: if ((red[i] == r) &&
74: (green[i] == g) &&
75: (blue[i] == b)) {
76: return i;
77: }
78: }
79: return -1;
80: }
81:
82: int gdImage::ColorAllocate(int r, int g, int b)
83: {
84: int i;
85: int ct = (-1);
86: for (i=0; (i<(colorsTotal)); i++) {
87: if (open[i]) {
88: ct = i;
89: break;
90: }
91: }
92: if (ct == (-1)) {
93: ct = colorsTotal;
94: if (ct == gdMaxColors) {
95: return -1;
96: }
97: colorsTotal++;
98: }
99: red[ct] = r;
100: green[ct] = g;
101: blue[ct] = b;
102: open[ct] = 0;
103: return ct;
104: }
105:
106: int gdImage::ColorRGB(int r, int g, int b){
107: int idx=ColorExact(r,g,b);
108: return idx<0 ? ColorAllocate(r,g,b) : idx;
109: }
110:
111: int gdImage::Color(unsigned int rgb){
112: unsigned int b=rgb, g=b>>8, r=g>>8;
113: return ColorRGB(r & 0xFF,g & 0xFF,b & 0xFF);
1.3 paf 114: }
115: unsigned int gdImage::DecodeColor(int color) {
1.4 ! paf 116: if(color<0)
! 117: return color;
1.3 paf 118: return (((red[color]<<8) + green[color])<<8)+blue[color];
1.1 paf 119: }
120:
121: void gdImage::ColorDeallocate(int color)
122: {
123: /* Mark it open. */
124: open[color] = 1;
125: }
126:
127: void gdImage::SetColorTransparent(int color)
128: {
129: transparent = color;
130: }
131:
132:
133: void gdImage::SetPixel(int x, int y, int color)
134: {
135: //paf int p;
136:
137: switch (lineWidth){
138: case 1: {
139: DoSetPixel(x, y,color);
140: return;
141: }
142: case 2: {
143: DoSetPixel(x, y-1,color);
144: DoSetPixel(x-1, y,color);
145: DoSetPixel(x, y,color);
146: DoSetPixel(x+1, y,color);
147: DoSetPixel(x, y+1,color);
148: return;
149: }
150: default:{
151: int i,j;
152: for (i=-1;i<=1;i++) DoSetPixel(x+i, y-2,color);
153: for (j=-1;j<=1;j++) for (i=-2;i<=2;i++) DoSetPixel(x+i, y+j,color);
154: for (i=-1;i<=1;i++) DoSetPixel(x+i, y+2,color);
155: return;
156: }
157: }
158: }
159:
160: int gdImage::GetPixel(int x, int y)
161: {
1.4 ! paf 162: return BoundsSafe(x, y) ? pixels[x][y]:-1;
1.1 paf 163: }
164:
165: /* Bresenham as presented in Foley & Van Dam */
166:
167: /* As above, plus dashing */
168:
169: #define styledSet \
170: { \
171: if (lineStyle) { \
172: if(!lineStyle[styleStep]) \
173: styleStep = 0; \
174: on=lineStyle[styleStep++]!=' '; \
175: } \
176: if (on) { \
177: SetPixel(x, y, color); \
178: } \
179: }
180:
181: void gdImage::Line(int x1, int y1, int x2, int y2, int color)
182: {
183: int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
184: int styleStep = 0;
185: int on = 1;
186: dx = abs(x2-x1);
187: dy = abs(y2-y1);
188: if (dy <= dx) {
189: d = 2*dy - dx;
190: incr1 = 2*dy;
191: incr2 = 2 * (dy - dx);
192: if (x1 > x2) {
193: x = x2;
194: y = y2;
195: ydirflag = (-1);
196: xend = x1;
197: } else {
198: x = x1;
199: y = y1;
200: ydirflag = 1;
201: xend = x2;
202: }
203: styledSet;
204: if (((y2 - y1) * ydirflag) > 0) {
205: while (x < xend) {
206: x++;
207: if (d <0) {
208: d+=incr1;
209: } else {
210: y++;
211: d+=incr2;
212: }
213: styledSet;
214: }
215: } else {
216: while (x < xend) {
217: x++;
218: if (d <0) {
219: d+=incr1;
220: } else {
221: y--;
222: d+=incr2;
223: }
224: styledSet;
225: }
226: }
227: } else {
228: d = 2*dx - dy;
229: incr1 = 2*dx;
230: incr2 = 2 * (dx - dy);
231: if (y1 > y2) {
232: y = y2;
233: x = x2;
234: yend = y1;
235: xdirflag = (-1);
236: } else {
237: y = y1;
238: x = x1;
239: yend = y2;
240: xdirflag = 1;
241: }
242: styledSet;
243: if (((x2 - x1) * xdirflag) > 0) {
244: while (y < yend) {
245: y++;
246: if (d <0) {
247: d+=incr1;
248: } else {
249: x++;
250: d+=incr2;
251: }
252: styledSet;
253: }
254: } else {
255: while (y < yend) {
256: y++;
257: if (d <0) {
258: d+=incr1;
259: } else {
260: x--;
261: d+=incr2;
262: }
263: styledSet;
264: }
265: }
266: }
267: }
268:
269: /* s and e are integers modulo 360 (degrees), with 0 degrees
270: being the rightmost extreme and degrees changing clockwise.
271: cx and cy are the center in pixels; w and h are the horizontal
272: and vertical diameter in pixels. Nice interface, but slow, since
273: I don't yet use Bresenham (I'm using an inefficient but
274: simple solution with too much work going on in it; generalizing
275: Bresenham to ellipses and partial arcs of ellipses is non-trivial,
276: at least for me) and there are other inefficiencies (small circles
277: do far too much work). */
278:
279: void gdImage::Arc(int cx, int cy, int w, int h, int s, int e, int color)
280: {
281: #if 0
282: if(s==0 && e==360) { // full
283: if(w==h) { // circle?
284: /* Bresenham octant code, which I should use eventually */
285: int x, y, d;
286: x = 0;
287: y = w/2;
288: d = 3-w;
289: while (x <= y) {
290: SetPixel(cx+x, cy+y, color);
291: SetPixel(cx+x, cy-y, color);
292: SetPixel(cx-x, cy+y, color);
293: SetPixel(cx-x, cy-y, color);
294: SetPixel(cx+y, cy+x, color);
295: SetPixel(cx+y, cy-x, color);
296: SetPixel(cx-y, cy+x, color);
297: SetPixel(cx-y, cy-x, color);
298: if (d < 0) {
299: d += 4 * x + 6;
300: } else {
301: d += 4 * (x - y) + 10;
302: y--;
303: }
304: x++;
305: }
306: } else { // full ellipse
307: w/=2;
308: h/=2;
309: int elx, ely;
310: long aa, aa2, bb, bb2, d, dx, dy;
311:
312: elx = 0; ely = h; aa = (long)w * w; aa2 = 2 * aa;
313: bb = (long)h * h; bb2 = 2 * bb;
314: d = bb - aa * h + aa/4; dx = 0; dy = aa2 * h;
315: SetPixel(cx, cy - ely, color); SetPixel(cx, cy + ely, color);
316: SetPixel(cx - w, cy, color); SetPixel(cx + w, cy, color);
317:
318: while (dx < dy)
319: {
320: if (d > 0) { ely--; dy-=aa2; d-=dy;}
321: elx++; dx+=bb2; d+=bb+dx;
322: SetPixel(cx + elx, cy + ely, color);
323: SetPixel(cx - elx, cy + ely, color);
324: SetPixel(cx + elx, cy - ely, color);
325: SetPixel(cx - elx, cy - ely, color);
326: };
327: d+=(3 * (aa - bb)/2 - (dx + dy))/2;
328: while (ely > 0)
329: {
330: if (d < 0) {elx++; dx+=bb2; d+=bb + dx;}
331: ely--; dy-=aa2; d+=aa - dy;
332: SetPixel(cx + elx, cy + ely, color);
333: SetPixel(cx - elx, cy + ely, color);
334: SetPixel(cx + elx, cy - ely, color);
335: SetPixel(cx - elx, cy - ely, color);
336: };
337: }
338: } else {
339: #endif
340: int i;
341: int lx = 0, ly = 0;
342: int w2, h2;
343: w2 = w/2;
344: h2 = h/2;
345: while (e < s) e += 360;
346: // paf
347: while(s<0) s+=360;
348: while(s>360) s-=360;
349: while(e<0) e+=360;
350: while(e>360) e-=360;
351: for (i=s; (i <= e); i++) {
352: int x, y;
353: x = ((long)cost[i] * (long)w2 / costScale) + cx;
354: y = ((long)sint[i] * (long)h2 / sintScale) + cy;
355: if (i != s) {
356: Line(lx, ly, x, y, color);
357: }
358: lx = x;
359: ly = y;
360: }
361: #if 0
362: }
363: #endif
364: }
365:
366: /*
367:
368: // http://firststeps.narod.ru/cgi/18.html
369:
370: int CGIScreen::Ellipse(int exc, int eyc, int ea, int eb , unsigned char Color)
371: {
372: int elx, ely;
373: long aa, aa2, bb, bb2, d, dx, dy;
374:
375: elx = 0; ely = eb; aa = (long)ea * ea; aa2 = 2 * aa;
376: bb = (long)eb * eb; bb2 = 2 * bb;
377: d = bb - aa * eb + aa/4; dx = 0; dy = aa2 * eb;
378: PutPixel(exc, eyc - ely, Color); PutPixel(exc, eyc + ely, Color);
379: PutPixel(exc - ea, eyc, Color); PutPixel(exc + ea, eyc, Color);
380:
381: while (dx < dy)
382: {
383: if (d > 0) { ely--; dy-=aa2; d-=dy;}
384: elx++; dx+=bb2; d+=bb+dx;
385: PutPixel(exc + elx, eyc + ely, Color);
386: PutPixel(exc - elx, eyc + ely, Color);
387: PutPixel(exc + elx, eyc - ely, Color);
388: PutPixel(exc - elx, eyc - ely, Color);
389: };
390: d+=(3 * (aa - bb)/2 - (dx + dy))/2;
391: while (ely > 0)
392: {
393: if (d < 0) {elx++; dx+=bb2; d+=bb + dx;}
394: ely--; dy-=aa2; d+=aa - dy;
395: PutPixel(exc + elx, eyc + ely, Color);
396: PutPixel(exc - elx, eyc + ely, Color);
397: PutPixel(exc + elx, eyc - ely, Color);
398: PutPixel(exc - elx, eyc - ely, Color);
399: };
400: return 0;
401: };
402:
403: */
404:
405:
406: void gdImage::Sector(int cx, int cy, int w, int h, int s, int e, int color)
407: {
408: int i;
409: int lx = 0, ly = 0;
410: int w2, h2;
411: w2 = w/2;
412: h2 = h/2;
413: while (e < s) e += 360;
414: // paf
415: while(s<0) s+=360;
416: while(s>360) s-=360;
417: while(e<0) e+=360;
418: while(e>360) e-=360;
419: for (i=s; (i <= e); i++) {
420: int x, y;
421: x = ((long)cost[i] * (long)w2 / costScale) + cx;
422: y = ((long)sint[i] * (long)h2 / sintScale) + cy;
423: if(i==s || i==e)
424: Line(cx, cy, x, y, color);
425: if (i != s) {
426: Line(lx, ly, x, y, color);
427: }
428: lx = x;
429: ly = y;
430: }
431: }
432:
433:
434:
435: void gdImage::FillToBorder(int x, int y, int border, int color)
436: {
437: if(!BoundsSafe(x, y)) //PAF
438: return;
439:
440: int lastBorder;
441: /* Seek left */
442: int leftLimit, rightLimit;
443: int i;
444: leftLimit = (-1);
445: if (border < 0) {
446: /* Refuse to fill to a non-solid border */
447: return;
448: }
449: for (i = x; (i >= 0); i--) {
450: if (GetPixel(i, y) == border) {
451: break;
452: }
453: SetPixel(i, y, color);
454: leftLimit = i;
455: }
456: if (leftLimit == (-1)) {
457: return;
458: }
459: /* Seek right */
460: rightLimit = x;
461: for (i = (x+1); (i < sx); i++) {
462: if (GetPixel(i, y) == border) {
463: break;
464: }
465: SetPixel(i, y, color);
466: rightLimit = i;
467: }
468: /* Look at lines above and below and start paints */
469: /* Above */
470: if (y > 0) {
471: lastBorder = 1;
472: for (i = leftLimit; (i <= rightLimit); i++) {
473: int c;
474: c = GetPixel(i, y-1);
475: if (lastBorder) {
476: if ((c != border) && (c != color)) {
477: FillToBorder(i, y-1,
478: border, color);
479: lastBorder = 0;
480: }
481: } else if ((c == border) || (c == color)) {
482: lastBorder = 1;
483: }
484: }
485: }
486: /* Below */
487: if (y < ((sy) - 1)) {
488: lastBorder = 1;
489: for (i = leftLimit; (i <= rightLimit); i++) {
490: int c;
491: c = GetPixel(i, y+1);
492: if (lastBorder) {
493: if ((c != border) && (c != color)) {
494: FillToBorder(i, y+1,
495: border, color);
496: lastBorder = 0;
497: }
498: } else if ((c == border) || (c == color)) {
499: lastBorder = 1;
500: }
501: }
502: }
503: }
504:
505: void gdImage::Fill(int x, int y, int color)
506: {
507: if(!BoundsSafe(x, y)) //PAF
508: return;
509:
510: int lastBorder;
511: int old;
512: int leftLimit, rightLimit;
513: int i;
514: old = GetPixel(x, y);
515: if (old == color) {
516: /* Nothing to be done */
517: return;
518: }
519: /* Seek left */
520: leftLimit = (-1);
521: for (i = x; (i >= 0); i--) {
522: if (GetPixel(i, y) != old) {
523: break;
524: }
525: SetPixel(i, y, color);
526: leftLimit = i;
527: }
528: if (leftLimit == (-1)) {
529: return;
530: }
531: /* Seek right */
532: rightLimit = x;
533: for (i = (x+1); (i < sx); i++) {
534: if (GetPixel(i, y) != old) {
535: break;
536: }
537: SetPixel(i, y, color);
538: rightLimit = i;
539: }
540: /* Look at lines above and below and start paints */
541: /* Above */
542: if (y > 0) {
543: lastBorder = 1;
544: for (i = leftLimit; (i <= rightLimit); i++) {
545: int c;
546: c = GetPixel(i, y-1);
547: if (lastBorder) {
548: if (c == old) {
549: Fill(i, y-1, color);
550: lastBorder = 0;
551: }
552: } else if (c != old) {
553: lastBorder = 1;
554: }
555: }
556: }
557: /* Below */
558: if (y < ((sy) - 1)) {
559: lastBorder = 1;
560: for (i = leftLimit; (i <= rightLimit); i++) {
561: int c;
562: c = GetPixel(i, y+1);
563: if (lastBorder) {
564: if (c == old) {
565: Fill(i, y+1, color);
566: lastBorder = 0;
567: }
568: } else if (c != old) {
569: lastBorder = 1;
570: }
571: }
572: }
573: }
574:
575: void gdImage::Rectangle(int x1, int y1, int x2, int y2, int color)
576: {
577: Line(x1, y1, x2, y1, color);
578: Line(x1, y2, x2, y2, color);
579: Line(x1, y1, x1, y2, color);
580: Line(x2, y1, x2, y2, color);
581: }
582:
583: void gdImage::FilledRectangle(int x1, int y1, int x2, int y2, int color)
584: {
585: if(x1>x2) {
586: int t=x1;
587: x1=x2;
588: x2=t;
589: }
590: if(y1>y2) {
591: int t=y1;
592: y1=y2;
593: y2=t;
594: }
595: int x, y;
596:
597: for (y=y1; (y<=y2); y++)
598: for (x=x1; (x<=x2); x++)
599: SetPixel(x, y, color);
600: }
601:
602: void gdImage::Copy(gdImage& dst, int dstX, int dstY, int srcX, int srcY, int w, int h)
603: {
604: int c;
605: int x, y;
606: int tox, toy;
607: int i;
608: int colorMap[gdMaxColors];
609: for (i=0; (i<gdMaxColors); i++) {
610: colorMap[i] = (-1);
611: }
612: toy = dstY;
613: for (y=srcY; (y < (srcY + h)); y++) {
614: tox = dstX;
615: for (x=srcX; (x < (srcX + w)); x++) {
616: int nc;
617: c = GetPixel(x, y);
618: /* Added 7/24/95: support transparent copies */
619: if (GetTransparent() == c) {
620: tox++;
621: continue;
622: }
623: /* Have we established a mapping for this color? */
624: if (colorMap[c] == (-1)) {
625: /* If it's the same image, mapping is trivial */
626: if (&dst == this) {
627: nc = c;
628: } else {
629: /* First look for an exact match */
630: nc = dst.ColorExact(
631: red[c], green[c],
632: blue[c]);
633: }
634: if (nc == (-1)) {
635: /* No, so try to allocate it */
636: nc = dst.ColorAllocate(
637: red[c], green[c],
638: blue[c]);
639: /* If we're out of colors, go for the
640: closest color */
641: if (nc == (-1)) {
642: nc = dst.ColorClosest(
643: red[c], green[c],
644: blue[c]);
645: }
646: }
647: colorMap[c] = nc;
648: }
649: dst.SetPixel(tox, toy, colorMap[c]);
650: tox++;
651: }
652: toy++;
653: }
654: }
655:
656: void gdImage::CopyResampled(gdImage& dst,
657: int dstX, int dstY,
658: int /*srcX*/, int /*srcY*/,
659: int dstW, int dstH,
660: int srcW, int srcH,
661: int tolerance)
662: {
663: gdImage& src=*this;
664: int x, y;
665: int srcTransparent=src.GetTransparent();
666: int dstTransparent=dst.GetTransparent();
667: for (y = dstY; (y < dstY + dstH); y++) {
668: for (x = dstX; (x < dstX + dstW); x++) {
669: int pd = dst.GetPixel (x, y);
670: /* Added 7/24/95: support transparent copies */
671: /* fixed by paf 20030116, another fix below */
672: if (pd == dstTransparent)
673: continue;
674:
675: double sy1, sy2, sx1, sx2;
676: double sx, sy;
677: double spixels = 0;
678: double red = 0.0, green = 0.0, blue = 0.0;
679: bool transparent=true;
680: sy1 = ((double) y - (double) dstY) * (double) srcH /
681: (double) dstH;
682: sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH /
683: (double) dstH;
684: sy = sy1;
685: do
686: {
687: double yportion;
688: if (floor (sy) == floor (sy1))
689: {
690: yportion = 1.0 - (sy - floor (sy));
691: if (yportion > sy2 - sy1)
692: {
693: yportion = sy2 - sy1;
694: }
695: sy = floor (sy);
696: }
697: else if (sy == floor (sy2))
698: {
699: yportion = sy2 - floor (sy2);
700: }
701: else
702: {
703: yportion = 1.0;
704: }
705: sx1 = ((double) x - (double) dstX) * (double) srcW /
706: dstW;
707: sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW /
708: dstW;
709: sx = sx1;
710: do
711: {
712: double xportion;
713: double pcontribution;
714: int p;
715: if (floor (sx) == floor (sx1))
716: {
717: xportion = 1.0 - (sx - floor (sx));
718: if (xportion > sx2 - sx1)
719: {
720: xportion = sx2 - sx1;
721: }
722: sx = floor (sx);
723: }
724: else if (sx == floor (sx2))
725: {
726: xportion = sx2 - floor (sx2);
727: }
728: else
729: {
730: xportion = 1.0;
731: }
732: pcontribution = xportion * yportion;
733: p = src.GetPixel (
734: (int) sx,
735: (int) sy);
736: // fix added 20020116 by paf to support transparent src
737: if (p!=srcTransparent) {
738: transparent = false;
739: red += Red (p) * pcontribution;
740: green += Green (p) * pcontribution;
741: blue += Blue (p) * pcontribution;
742: }
743: spixels += xportion * yportion;
744: sx += 1.0;
745: } while (sx < sx2);
746: sy += 1.0;
747: } while (sy < sy2);
748:
749: if(transparent)
750: continue;
751:
752: if (spixels != 0.0) {
753: red /= spixels;
754: green /= spixels;
755: blue /= spixels;
756: }
757: /* Clamping to allow for rounding errors above */
758: if (red > 255.0)
759: red = 255.0;
760: if (green > 255.0)
761: green = 255.0;
762: if (blue > 255.0)
763: blue = 255.0;
764:
765: red=round(red);
766: green=round(green);
767: blue=round(blue);
768: /* First look for an exact match */
769: int nc = dst.ColorExact((int)red, (int)green, (int)blue);
770: if (nc == (-1)) {
771: /* No, so go for the closest color with high tolerance */
772: nc = dst.ColorClosest((int)red, (int)green, (int)blue, tolerance);
773: if (nc == (-1)) {
774: /* Not found with even high tolerance, so try to allocate it */
775: nc = dst.ColorAllocate((int)red, (int)green, (int)blue);
776:
777: /* If we're out of colors, go for the closest color */
778: if (nc == (-1))
779: nc = dst.ColorClosest((int)red, (int)green, (int)blue);
780: }
781: }
782: dst.SetPixel(x, y, nc);
783: }
784: }
785: }
786:
787: void gdImage::Polygon(Point *p, int n, int c, bool closed)
788: {
789: int i;
790: int lx, ly;
791: if (!n) {
792: return;
793: }
794: lx = p->x;
795: ly = p->y;
796: if(closed)
797: Line(lx, ly, p[n-1].x, p[n-1].y, c);
798: for (i=1; (i < n); i++) {
799: p++;
800: Line(lx, ly, p->x, p->y, c);
801: lx = p->x;
802: ly = p->y;
803: }
804: }
805:
806: static int gdCompareInt(const void *a, const void *b)
807: {
808: return (*(const int *)a) - (*(const int *)b);
809: }
810:
811:
812:
813: void gdImage::FilledPolygon(Point *p, int n, int c)
814: {
815: int i;
816: int y;
817: int y1, y2;
818: int ints;
819: if (!n) {
820: return;
821: }
822: if (!polyAllocated) {
823: polyInts = (int *) malloc(sizeof(int) * n);
824: polyAllocated = n;
825: }
826: if (polyAllocated < n) {
827: while (polyAllocated < n) {
828: polyAllocated *= 2;
829: }
830: polyInts = (int *) realloc(polyInts,
831: sizeof(int) * polyAllocated);
832: }
833: y1 = p[0].y;
834: y2 = p[0].y;
835: for (i=1; (i < n); i++) {
836: if (p[i].y < y1) {
837: y1 = p[i].y;
838: }
839: if (p[i].y > y2) {
840: y2 = p[i].y;
841: }
842: }
843: for (y=y1; (y <= y2); y++) {
844: int interLast = 0;
845: int dirLast = 0;
846: int interFirst = 1;
847: ints = 0;
848: for (i=0; (i <= n); i++) {
849: int x1, x2;
850: int y1, y2;
851: int dir;
852: int ind1, ind2;
853: int lastInd1 = 0;
854: if ((i == n) || (!i)) {
855: ind1 = n-1;
856: ind2 = 0;
857: } else {
858: ind1 = i-1;
859: ind2 = i;
860: }
861: y1 = p[ind1].y;
862: y2 = p[ind2].y;
863: if (y1 < y2) {
864: y1 = p[ind1].y;
865: y2 = p[ind2].y;
866: x1 = p[ind1].x;
867: x2 = p[ind2].x;
868: dir = -1;
869: } else if (y1 > y2) {
870: y2 = p[ind1].y;
871: y1 = p[ind2].y;
872: x2 = p[ind1].x;
873: x1 = p[ind2].x;
874: dir = 1;
875: } else {
876: /* Horizontal; just draw it */
877: Line(
878: p[ind1].x, y1,
879: p[ind2].x, y1,
880: c);
881: continue;
882: }
883: if ((y >= y1) && (y <= y2)) {
884: int inter =
885: (y-y1) * (x2-x1) / (y2-y1) + x1;
886: /* Only count intersections once
887: except at maxima and minima. Also,
888: if two consecutive intersections are
889: endpoints of the same horizontal line
890: that is not at a maxima or minima,
891: discard the leftmost of the two. */
892: if (!interFirst) {
893: if ((p[ind1].y == p[lastInd1].y) &&
894: (p[ind1].x != p[lastInd1].x)) {
895: if (dir == dirLast) {
896: if (inter > interLast) {
897: /* Replace the old one */
898: polyInts[ints] = inter;
899: } else {
900: /* Discard this one */
901: }
902: continue;
903: }
904: }
905: if (inter == interLast) {
906: if (dir == dirLast) {
907: continue;
908: }
909: }
910: }
911: if (i > 0) {
912: polyInts[ints++] = inter;
913: }
914: lastInd1 = i;
915: dirLast = dir;
916: interLast = inter;
917: interFirst = 0;
918: }
919: }
920: qsort(polyInts, ints, sizeof(int), gdCompareInt);
921: for (i=0; (i < (ints-1)); i+=2)
922: Line(polyInts[i], y, polyInts[i+1], y, c);
923: }
924: }
925:
926: //001005paf this used in drawing straight lines in gdImage::FilledPolygonReplaceColor
927: void gdImage::LineReplaceColor(int x1, int y1, int x2, int y2, int a, int b) {
928: if(y1!=y2)
929: return;
930:
931: for(int x=x1; x<=x2; x++)
932: if(BoundsSafe(x, y1)) {
933: unsigned char *pixel=&pixels[x][y1];
934: if(*pixel==a)
935: *pixel=b;
936: }
937: }
938:
939: void gdImage::FilledPolygonReplaceColor(Point *p, int n, int a, int b)
940: {
941: int i;
942: int y;
943: int y1, y2;
944: int ints;
945: if (!n) {
946: return;
947: }
948: if (!polyAllocated) {
949: polyInts = (int *) malloc(sizeof(int) * n);
950: polyAllocated = n;
951: }
952: if (polyAllocated < n) {
953: while (polyAllocated < n) {
954: polyAllocated *= 2;
955: }
956: polyInts = (int *) realloc(polyInts,
957: sizeof(int) * polyAllocated);
958: }
959: y1 = p[0].y;
960: y2 = p[0].y;
961: for (i=1; (i < n); i++) {
962: if (p[i].y < y1) {
963: y1 = p[i].y;
964: }
965: if (p[i].y > y2) {
966: y2 = p[i].y;
967: }
968: }
969: for (y=y1; (y <= y2); y++) {
970: int interLast = 0;
971: int dirLast = 0;
972: int interFirst = 1;
973: ints = 0;
974: for (i=0; (i <= n); i++) {
975: int x1, x2;
976: int y1, y2;
977: int dir;
978: int ind1, ind2;
979: int lastInd1 = 0;
980: if ((i == n) || (!i)) {
981: ind1 = n-1;
982: ind2 = 0;
983: } else {
984: ind1 = i-1;
985: ind2 = i;
986: }
987: y1 = p[ind1].y;
988: y2 = p[ind2].y;
989: if (y1 < y2) {
990: y1 = p[ind1].y;
991: y2 = p[ind2].y;
992: x1 = p[ind1].x;
993: x2 = p[ind2].x;
994: dir = -1;
995: } else if (y1 > y2) {
996: y2 = p[ind1].y;
997: y1 = p[ind2].y;
998: x2 = p[ind1].x;
999: x1 = p[ind2].x;
1000: dir = 1;
1001: } else {
1002: /* Horizontal; just draw it */
1003: LineReplaceColor(
1004: p[ind1].x, y1,
1005: p[ind2].x, y1,
1006: a,b);
1007: continue;
1008: }
1009: if ((y >= y1) && (y <= y2)) {
1010: int inter =
1011: (y-y1) * (x2-x1) / (y2-y1) + x1;
1012: /* Only count intersections once
1013: except at maxima and minima. Also,
1014: if two consecutive intersections are
1015: endpoints of the same horizontal line
1016: that is not at a maxima or minima,
1017: discard the leftmost of the two. */
1018: if (!interFirst) {
1019: if ((p[ind1].y == p[lastInd1].y) &&
1020: (p[ind1].x != p[lastInd1].x)) {
1021: if (dir == dirLast) {
1022: if (inter > interLast) {
1023: /* Replace the old one */
1024: polyInts[ints] = inter;
1025: } else {
1026: /* Discard this one */
1027: }
1028: continue;
1029: }
1030: }
1031: if (inter == interLast) {
1032: if (dir == dirLast) {
1033: continue;
1034: }
1035: }
1036: }
1037: if (i > 0) {
1038: polyInts[ints++] = inter;
1039: }
1040: lastInd1 = i;
1041: dirLast = dir;
1042: interLast = inter;
1043: interFirst = 0;
1044: }
1045: }
1046: qsort(polyInts, ints, sizeof(int), gdCompareInt);
1047: for (i=0; (i < (ints-1)); i+=2) {
1048: LineReplaceColor(polyInts[i], y,
1049: polyInts[i+1], y, a,b);
1050: }
1051: }
1052: }
1053:
1054: void gdImage::SetInterlace(int interlaceArg)
1055: {
1056: interlace = interlaceArg;
1057: }
1058:
1059: void gdImage::SetLineWidth(int width)
1060: {
1061: lineWidth=width;
1062: }
1063:
1064: void gdImage::SetLineStyle(const char* alineStyle)
1065: {
1066: lineStyle=alineStyle;
1067: }
1068: