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