|
|
1.3 paf 1: /** @file
2: Parser: image manipulations impl1.
3:
1.25 paf 4: Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
1.26 ! paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.8 parser 6:
1.26 ! paf 7: $Id: gif.C,v 1.25 2002/02/08 07:27:42 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;
1.24 paf 341: while (e < s) e += 360;
342: // paf
343: while(s<0) s+=360;
344: while(s>360) s-=360;
345: while(e<0) e+=360;
346: while(e>360) e-=360;
1.13 parser 347: for (i=s; (i <= e); i++) {
348: int x, y;
1.24 paf 349: x = ((long)cost[i] * (long)w2 / costScale) + cx;
350: y = ((long)sint[i] * (long)h2 / sintScale) + cy;
1.13 parser 351: if (i != s) {
352: Line(lx, ly, x, y, color);
353: }
354: lx = x;
355: ly = y;
356: }
1.15 parser 357: #if 0
1.11 parser 358: }
1.15 parser 359: #endif
1.11 parser 360: }
1.14 parser 361:
362: /*
363:
364: // http://firststeps.narod.ru/cgi/18.html
365:
366: int CGIScreen::Ellipse(int exc, int eyc, int ea, int eb , unsigned char Color)
367: {
368: int elx, ely;
369: long aa, aa2, bb, bb2, d, dx, dy;
370:
371: elx = 0; ely = eb; aa = (long)ea * ea; aa2 = 2 * aa;
372: bb = (long)eb * eb; bb2 = 2 * bb;
373: d = bb - aa * eb + aa/4; dx = 0; dy = aa2 * eb;
374: PutPixel(exc, eyc - ely, Color); PutPixel(exc, eyc + ely, Color);
375: PutPixel(exc - ea, eyc, Color); PutPixel(exc + ea, eyc, Color);
376:
377: while (dx < dy)
378: {
379: if (d > 0) { ely--; dy-=aa2; d-=dy;}
380: elx++; dx+=bb2; d+=bb+dx;
381: PutPixel(exc + elx, eyc + ely, Color);
382: PutPixel(exc - elx, eyc + ely, Color);
383: PutPixel(exc + elx, eyc - ely, Color);
384: PutPixel(exc - elx, eyc - ely, Color);
385: };
386: d+=(3 * (aa - bb)/2 - (dx + dy))/2;
387: while (ely > 0)
388: {
389: if (d < 0) {elx++; dx+=bb2; d+=bb + dx;}
390: ely--; dy-=aa2; d+=aa - dy;
391: PutPixel(exc + elx, eyc + ely, Color);
392: PutPixel(exc - elx, eyc + ely, Color);
393: PutPixel(exc + elx, eyc - ely, Color);
394: PutPixel(exc - elx, eyc - ely, Color);
395: };
396: return 0;
397: };
398:
399: */
1.11 parser 400:
1.12 parser 401:
402: void gdImage::Sector(int cx, int cy, int w, int h, int s, int e, int color)
403: {
404: int i;
405: int lx = 0, ly = 0;
406: int w2, h2;
407: w2 = w/2;
408: h2 = h/2;
1.24 paf 409: while (e < s) e += 360;
410: // paf
411: while(s<0) s+=360;
412: while(s>360) s-=360;
413: while(e<0) e+=360;
414: while(e>360) e-=360;
1.12 parser 415: for (i=s; (i <= e); i++) {
416: int x, y;
1.24 paf 417: x = ((long)cost[i] * (long)w2 / costScale) + cx;
418: y = ((long)sint[i] * (long)h2 / sintScale) + cy;
1.12 parser 419: if(i==s || i==e)
420: Line(cx, cy, x, y, color);
421: if (i != s) {
422: Line(lx, ly, x, y, color);
423: }
424: lx = x;
425: ly = y;
426: }
427: }
1.11 parser 428:
429:
1.1 paf 430:
1.2 paf 431: void gdImage::FillToBorder(int x, int y, int border, int color)
1.1 paf 432: {
1.4 paf 433: if(!BoundsSafe(x, y)) //PAF
434: return;
435:
1.1 paf 436: int lastBorder;
437: /* Seek left */
438: int leftLimit, rightLimit;
439: int i;
440: leftLimit = (-1);
441: if (border < 0) {
442: /* Refuse to fill to a non-solid border */
443: return;
444: }
445: for (i = x; (i >= 0); i--) {
1.2 paf 446: if (GetPixel(i, y) == border) {
1.1 paf 447: break;
448: }
1.2 paf 449: SetPixel(i, y, color);
1.1 paf 450: leftLimit = i;
451: }
452: if (leftLimit == (-1)) {
453: return;
454: }
455: /* Seek right */
456: rightLimit = x;
1.2 paf 457: for (i = (x+1); (i < sx); i++) {
458: if (GetPixel(i, y) == border) {
1.1 paf 459: break;
460: }
1.2 paf 461: SetPixel(i, y, color);
1.1 paf 462: rightLimit = i;
463: }
464: /* Look at lines above and below and start paints */
465: /* Above */
466: if (y > 0) {
467: lastBorder = 1;
468: for (i = leftLimit; (i <= rightLimit); i++) {
469: int c;
1.2 paf 470: c = GetPixel(i, y-1);
1.1 paf 471: if (lastBorder) {
472: if ((c != border) && (c != color)) {
1.2 paf 473: FillToBorder(i, y-1,
1.1 paf 474: border, color);
475: lastBorder = 0;
476: }
477: } else if ((c == border) || (c == color)) {
478: lastBorder = 1;
479: }
480: }
481: }
482: /* Below */
1.2 paf 483: if (y < ((sy) - 1)) {
1.1 paf 484: lastBorder = 1;
485: for (i = leftLimit; (i <= rightLimit); i++) {
486: int c;
1.2 paf 487: c = GetPixel(i, y+1);
1.1 paf 488: if (lastBorder) {
489: if ((c != border) && (c != color)) {
1.2 paf 490: FillToBorder(i, y+1,
1.1 paf 491: border, color);
492: lastBorder = 0;
493: }
494: } else if ((c == border) || (c == color)) {
495: lastBorder = 1;
496: }
497: }
498: }
499: }
500:
1.2 paf 501: void gdImage::Fill(int x, int y, int color)
1.1 paf 502: {
1.4 paf 503: if(!BoundsSafe(x, y)) //PAF
504: return;
505:
1.1 paf 506: int lastBorder;
507: int old;
508: int leftLimit, rightLimit;
509: int i;
1.2 paf 510: old = GetPixel(x, y);
1.1 paf 511: if (old == color) {
512: /* Nothing to be done */
513: return;
514: }
515: /* Seek left */
516: leftLimit = (-1);
517: for (i = x; (i >= 0); i--) {
1.2 paf 518: if (GetPixel(i, y) != old) {
1.1 paf 519: break;
520: }
1.2 paf 521: SetPixel(i, y, color);
1.1 paf 522: leftLimit = i;
523: }
524: if (leftLimit == (-1)) {
525: return;
526: }
527: /* Seek right */
528: rightLimit = x;
1.2 paf 529: for (i = (x+1); (i < sx); i++) {
530: if (GetPixel(i, y) != old) {
1.1 paf 531: break;
532: }
1.2 paf 533: SetPixel(i, y, color);
1.1 paf 534: rightLimit = i;
535: }
536: /* Look at lines above and below and start paints */
537: /* Above */
538: if (y > 0) {
539: lastBorder = 1;
540: for (i = leftLimit; (i <= rightLimit); i++) {
541: int c;
1.2 paf 542: c = GetPixel(i, y-1);
1.1 paf 543: if (lastBorder) {
544: if (c == old) {
1.2 paf 545: Fill(i, y-1, color);
1.1 paf 546: lastBorder = 0;
547: }
548: } else if (c != old) {
549: lastBorder = 1;
550: }
551: }
552: }
553: /* Below */
1.2 paf 554: if (y < ((sy) - 1)) {
1.1 paf 555: lastBorder = 1;
556: for (i = leftLimit; (i <= rightLimit); i++) {
557: int c;
1.2 paf 558: c = GetPixel(i, y+1);
1.1 paf 559: if (lastBorder) {
560: if (c == old) {
1.2 paf 561: Fill(i, y+1, color);
1.1 paf 562: lastBorder = 0;
563: }
564: } else if (c != old) {
565: lastBorder = 1;
566: }
567: }
568: }
569: }
570:
1.2 paf 571: void gdImage::Rectangle(int x1, int y1, int x2, int y2, int color)
1.1 paf 572: {
1.2 paf 573: Line(x1, y1, x2, y1, color);
574: Line(x1, y2, x2, y2, color);
575: Line(x1, y1, x1, y2, color);
576: Line(x2, y1, x2, y2, color);
1.1 paf 577: }
578:
1.2 paf 579: void gdImage::FilledRectangle(int x1, int y1, int x2, int y2, int color)
1.1 paf 580: {
1.10 parser 581: if(x1>x2) {
582: int t=x1;
583: x1=x2;
584: x2=t;
585: }
586: if(y1>y2) {
587: int t=y1;
588: y1=y2;
589: y2=t;
590: }
1.1 paf 591: int x, y;
1.10 parser 592:
1.2 paf 593: for (y=y1; (y<=y2); y++)
594: for (x=x1; (x<=x2); x++)
595: SetPixel(x, y, color);
1.1 paf 596: }
597:
1.2 paf 598: void gdImage::Copy(gdImage& dst, int dstX, int dstY, int srcX, int srcY, int w, int h)
1.1 paf 599: {
600: int c;
601: int x, y;
602: int tox, toy;
603: int i;
604: int colorMap[gdMaxColors];
605: for (i=0; (i<gdMaxColors); i++) {
606: colorMap[i] = (-1);
607: }
608: toy = dstY;
609: for (y=srcY; (y < (srcY + h)); y++) {
610: tox = dstX;
611: for (x=srcX; (x < (srcX + w)); x++) {
612: int nc;
1.2 paf 613: c = GetPixel(x, y);
1.1 paf 614: /* Added 7/24/95: support transparent copies */
1.2 paf 615: if (GetTransparent() == c) {
1.1 paf 616: tox++;
617: continue;
618: }
619: /* Have we established a mapping for this color? */
620: if (colorMap[c] == (-1)) {
621: /* If it's the same image, mapping is trivial */
1.2 paf 622: if (&dst == this) {
1.1 paf 623: nc = c;
624: } else {
625: /* First look for an exact match */
1.2 paf 626: nc = dst.ColorExact(
627: red[c], green[c],
628: blue[c]);
1.1 paf 629: }
630: if (nc == (-1)) {
631: /* No, so try to allocate it */
1.2 paf 632: nc = dst.ColorAllocate(
633: red[c], green[c],
634: blue[c]);
1.1 paf 635: /* If we're out of colors, go for the
636: closest color */
637: if (nc == (-1)) {
1.2 paf 638: nc = dst.ColorClosest(
639: red[c], green[c],
640: blue[c]);
1.1 paf 641: }
642: }
643: colorMap[c] = nc;
644: }
1.2 paf 645: dst.SetPixel(tox, toy, colorMap[c]);
1.1 paf 646: tox++;
647: }
648: toy++;
649: }
650: }
1.16 parser 651:
1.18 parser 652: void gdImage::CopyResampled(gdImage& dst,
653: int dstX, int dstY,
654: int srcX, int srcY,
655: int dstW, int dstH,
1.19 parser 656: int srcW, int srcH,
657: int tolerance)
1.16 parser 658: {
659: gdImage& src=*this;
660: int x, y;
1.18 parser 661: for (y = dstY; (y < dstY + dstH); y++) {
662: for (x = dstX; (x < dstX + dstW); x++) {
663: int pd = dst.GetPixel (x, y);
664: /* Added 7/24/95: support transparent copies */
665: if (src.GetTransparent() == pd)
666: continue;
667:
1.20 parser 668: double sy1, sy2, sx1, sx2;
669: double sx, sy;
670: double spixels = 0;
671: double red = 0.0, green = 0.0, blue = 0.0;
672: sy1 = ((double) y - (double) dstY) * (double) srcH /
673: (double) dstH;
674: sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH /
675: (double) dstH;
1.18 parser 676: sy = sy1;
677: do
678: {
1.20 parser 679: double yportion;
1.18 parser 680: if (floor (sy) == floor (sy1))
681: {
682: yportion = 1.0 - (sy - floor (sy));
683: if (yportion > sy2 - sy1)
684: {
685: yportion = sy2 - sy1;
686: }
687: sy = floor (sy);
688: }
689: else if (sy == floor (sy2))
690: {
691: yportion = sy2 - floor (sy2);
692: }
693: else
694: {
695: yportion = 1.0;
696: }
1.20 parser 697: sx1 = ((double) x - (double) dstX) * (double) srcW /
1.18 parser 698: dstW;
1.20 parser 699: sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW /
1.18 parser 700: dstW;
701: sx = sx1;
702: do
703: {
1.20 parser 704: double xportion;
705: double pcontribution;
1.18 parser 706: int p;
707: if (floor (sx) == floor (sx1))
708: {
709: xportion = 1.0 - (sx - floor (sx));
710: if (xportion > sx2 - sx1)
711: {
712: xportion = sx2 - sx1;
1.16 parser 713: }
1.18 parser 714: sx = floor (sx);
715: }
716: else if (sx == floor (sx2))
717: {
718: xportion = sx2 - floor (sx2);
1.16 parser 719: }
1.18 parser 720: else
721: {
722: xportion = 1.0;
723: }
724: pcontribution = xportion * yportion;
725: p = src.GetPixel (
726: (int) sx,
727: (int) sy);
728: red += Red (p) * pcontribution;
729: green += Green (p) * pcontribution;
730: blue += Blue (p) * pcontribution;
731: spixels += xportion * yportion;
732: sx += 1.0;
733: } while (sx < sx2);
734: sy += 1.0;
735: } while (sy < sy2);
736: if (spixels != 0.0) {
737: red /= spixels;
738: green /= spixels;
739: blue /= spixels;
740: }
741: /* Clamping to allow for rounding errors above */
742: if (red > 255.0)
743: red = 255.0;
744: if (green > 255.0)
745: green = 255.0;
746: if (blue > 255.0)
747: blue = 255.0;
748:
749: red=round(red);
750: green=round(green);
751: blue=round(blue);
752: /* First look for an exact match */
1.20 parser 753: int nc = dst.ColorExact((int)red, (int)green, (int)blue);
1.18 parser 754: if (nc == (-1)) {
755: /* No, so go for the closest color with high tolerance */
1.20 parser 756: nc = dst.ColorClosest((int)red, (int)green, (int)blue, tolerance);
1.18 parser 757: if (nc == (-1)) {
758: /* Not found with even high tolerance, so try to allocate it */
1.20 parser 759: nc = dst.ColorAllocate((int)red, (int)green, (int)blue);
1.18 parser 760:
761: /* If we're out of colors, go for the closest color */
762: if (nc == (-1))
1.20 parser 763: nc = dst.ColorClosest((int)red, (int)green, (int)blue);
1.16 parser 764: }
765: }
1.18 parser 766: dst.SetPixel(x, y, nc);
1.16 parser 767: }
1.18 parser 768: }
1.16 parser 769: }
1.1 paf 770:
1.2 paf 771: static int gdGetWord(int *result, FILE *in)
1.1 paf 772: {
773: int r;
774: r = getc(in);
775: if (r == EOF) {
776: return 0;
777: }
778: *result = r << 8;
779: r = getc(in);
780: if (r == EOF) {
781: return 0;
782: }
783: *result += r;
784: return 1;
785: }
786:
1.2 paf 787: static void gdPutWord(int w, FILE *out)
1.1 paf 788: {
789: putc((unsigned char)(w >> 8), out);
790: putc((unsigned char)(w & 0xFF), out);
791: }
792:
1.2 paf 793: static int gdGetByte(int *result, FILE *in)
1.1 paf 794: {
795: int r;
796: r = getc(in);
797: if (r == EOF) {
798: return 0;
799: }
800: *result = r;
801: return 1;
802: }
803:
1.6 parser 804: void gdImage::Polygon(Point *p, int n, int c, bool closed)
1.1 paf 805: {
806: int i;
807: int lx, ly;
808: if (!n) {
809: return;
810: }
811: lx = p->x;
812: ly = p->y;
1.6 parser 813: if(closed)
814: Line(lx, ly, p[n-1].x, p[n-1].y, c);
1.1 paf 815: for (i=1; (i < n); i++) {
816: p++;
1.2 paf 817: Line(lx, ly, p->x, p->y, c);
1.1 paf 818: lx = p->x;
819: ly = p->y;
820: }
821: }
822:
1.5 paf 823: static int gdCompareInt(const void *a, const void *b)
824: {
825: return (*(const int *)a) - (*(const int *)b);
826: }
827:
828:
1.1 paf 829:
1.2 paf 830: void gdImage::FilledPolygon(Point *p, int n, int c)
1.1 paf 831: {
832: int i;
833: int y;
834: int y1, y2;
835: int ints;
836: if (!n) {
837: return;
838: }
1.2 paf 839: if (!polyAllocated) {
840: polyInts = (int *) malloc(sizeof(int) * n);
841: polyAllocated = n;
1.1 paf 842: }
1.2 paf 843: if (polyAllocated < n) {
844: while (polyAllocated < n) {
845: polyAllocated *= 2;
1.1 paf 846: }
1.2 paf 847: polyInts = (int *) realloc(polyInts,
848: sizeof(int) * polyAllocated);
1.1 paf 849: }
850: y1 = p[0].y;
851: y2 = p[0].y;
852: for (i=1; (i < n); i++) {
853: if (p[i].y < y1) {
854: y1 = p[i].y;
855: }
856: if (p[i].y > y2) {
857: y2 = p[i].y;
858: }
859: }
860: for (y=y1; (y <= y2); y++) {
861: int interLast = 0;
862: int dirLast = 0;
863: int interFirst = 1;
864: ints = 0;
865: for (i=0; (i <= n); i++) {
866: int x1, x2;
867: int y1, y2;
868: int dir;
869: int ind1, ind2;
870: int lastInd1 = 0;
871: if ((i == n) || (!i)) {
872: ind1 = n-1;
873: ind2 = 0;
874: } else {
875: ind1 = i-1;
876: ind2 = i;
877: }
878: y1 = p[ind1].y;
879: y2 = p[ind2].y;
880: if (y1 < y2) {
881: y1 = p[ind1].y;
882: y2 = p[ind2].y;
883: x1 = p[ind1].x;
884: x2 = p[ind2].x;
885: dir = -1;
886: } else if (y1 > y2) {
887: y2 = p[ind1].y;
888: y1 = p[ind2].y;
889: x2 = p[ind1].x;
890: x1 = p[ind2].x;
891: dir = 1;
892: } else {
893: /* Horizontal; just draw it */
1.2 paf 894: Line(
1.1 paf 895: p[ind1].x, y1,
896: p[ind2].x, y1,
897: c);
898: continue;
899: }
900: if ((y >= y1) && (y <= y2)) {
901: int inter =
902: (y-y1) * (x2-x1) / (y2-y1) + x1;
903: /* Only count intersections once
904: except at maxima and minima. Also,
905: if two consecutive intersections are
906: endpoints of the same horizontal line
907: that is not at a maxima or minima,
908: discard the leftmost of the two. */
909: if (!interFirst) {
910: if ((p[ind1].y == p[lastInd1].y) &&
911: (p[ind1].x != p[lastInd1].x)) {
912: if (dir == dirLast) {
913: if (inter > interLast) {
914: /* Replace the old one */
1.2 paf 915: polyInts[ints] = inter;
1.1 paf 916: } else {
917: /* Discard this one */
918: }
919: continue;
920: }
921: }
922: if (inter == interLast) {
923: if (dir == dirLast) {
924: continue;
925: }
926: }
927: }
928: if (i > 0) {
1.2 paf 929: polyInts[ints++] = inter;
1.1 paf 930: }
931: lastInd1 = i;
932: dirLast = dir;
933: interLast = inter;
934: interFirst = 0;
935: }
936: }
1.2 paf 937: qsort(polyInts, ints, sizeof(int), gdCompareInt);
938: for (i=0; (i < (ints-1)); i+=2)
939: Line(polyInts[i], y, polyInts[i+1], y, c);
1.1 paf 940: }
941: }
942:
1.2 paf 943: //001005paf this used in drawing straight lines in gdImage::FilledPolygonReplaceColor
944: void gdImage::LineReplaceColor(int x1, int y1, int x2, int y2, int a, int b) {
1.1 paf 945: if(y1!=y2)
946: return;
947:
1.23 paf 948: for(int x=x1; x<=x2; x++)
949: if(BoundsSafe(x, y1)) {
950: unsigned char *pixel=&pixels[x][y1];
951: if(*pixel==a)
952: *pixel=b;
953: }
1.1 paf 954: }
955:
1.2 paf 956: void gdImage::FilledPolygonReplaceColor(Point *p, int n, int a, int b)
1.1 paf 957: {
958: int i;
959: int y;
960: int y1, y2;
961: int ints;
962: if (!n) {
963: return;
964: }
1.2 paf 965: if (!polyAllocated) {
966: polyInts = (int *) malloc(sizeof(int) * n);
967: polyAllocated = n;
1.1 paf 968: }
1.2 paf 969: if (polyAllocated < n) {
970: while (polyAllocated < n) {
971: polyAllocated *= 2;
1.1 paf 972: }
1.2 paf 973: polyInts = (int *) realloc(polyInts,
974: sizeof(int) * polyAllocated);
1.1 paf 975: }
976: y1 = p[0].y;
977: y2 = p[0].y;
978: for (i=1; (i < n); i++) {
979: if (p[i].y < y1) {
980: y1 = p[i].y;
981: }
982: if (p[i].y > y2) {
983: y2 = p[i].y;
984: }
985: }
986: for (y=y1; (y <= y2); y++) {
987: int interLast = 0;
988: int dirLast = 0;
989: int interFirst = 1;
990: ints = 0;
991: for (i=0; (i <= n); i++) {
992: int x1, x2;
993: int y1, y2;
994: int dir;
995: int ind1, ind2;
996: int lastInd1 = 0;
997: if ((i == n) || (!i)) {
998: ind1 = n-1;
999: ind2 = 0;
1000: } else {
1001: ind1 = i-1;
1002: ind2 = i;
1003: }
1004: y1 = p[ind1].y;
1005: y2 = p[ind2].y;
1006: if (y1 < y2) {
1007: y1 = p[ind1].y;
1008: y2 = p[ind2].y;
1009: x1 = p[ind1].x;
1010: x2 = p[ind2].x;
1011: dir = -1;
1012: } else if (y1 > y2) {
1013: y2 = p[ind1].y;
1014: y1 = p[ind2].y;
1015: x2 = p[ind1].x;
1016: x1 = p[ind2].x;
1017: dir = 1;
1018: } else {
1019: /* Horizontal; just draw it */
1.2 paf 1020: LineReplaceColor(
1.1 paf 1021: p[ind1].x, y1,
1022: p[ind2].x, y1,
1023: a,b);
1024: continue;
1025: }
1026: if ((y >= y1) && (y <= y2)) {
1027: int inter =
1028: (y-y1) * (x2-x1) / (y2-y1) + x1;
1029: /* Only count intersections once
1030: except at maxima and minima. Also,
1031: if two consecutive intersections are
1032: endpoints of the same horizontal line
1033: that is not at a maxima or minima,
1034: discard the leftmost of the two. */
1035: if (!interFirst) {
1036: if ((p[ind1].y == p[lastInd1].y) &&
1037: (p[ind1].x != p[lastInd1].x)) {
1038: if (dir == dirLast) {
1039: if (inter > interLast) {
1040: /* Replace the old one */
1.2 paf 1041: polyInts[ints] = inter;
1.1 paf 1042: } else {
1043: /* Discard this one */
1044: }
1045: continue;
1046: }
1047: }
1048: if (inter == interLast) {
1049: if (dir == dirLast) {
1050: continue;
1051: }
1052: }
1053: }
1054: if (i > 0) {
1.2 paf 1055: polyInts[ints++] = inter;
1.1 paf 1056: }
1057: lastInd1 = i;
1058: dirLast = dir;
1059: interLast = inter;
1060: interFirst = 0;
1061: }
1062: }
1.2 paf 1063: qsort(polyInts, ints, sizeof(int), gdCompareInt);
1.1 paf 1064: for (i=0; (i < (ints-1)); i+=2) {
1.2 paf 1065: LineReplaceColor(polyInts[i], y,
1066: polyInts[i+1], y, a,b);
1.1 paf 1067: }
1068: }
1069: }
1070:
1.2 paf 1071: void gdImage::SetInterlace(int interlaceArg)
1.1 paf 1072: {
1.2 paf 1073: interlace = interlaceArg;
1.1 paf 1074: }
1075:
1.6 parser 1076: void gdImage::SetLineWidth(int width)
1077: {
1078: lineWidth=width;
1079: }
1080:
1081: void gdImage::SetLineStyle(const char *alineStyle)
1.1 paf 1082: {
1.6 parser 1083: lineStyle=alineStyle;
1.1 paf 1084: }
1085: