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