Annotation of embedaddon/php/ext/gd/libgd/gd.c, revision 1.1
1.1 ! misho 1:
! 2: #include <math.h>
! 3: #include <string.h>
! 4: #include <stdlib.h>
! 5: #include "gd.h"
! 6: #include "gdhelpers.h"
! 7:
! 8: #include "php.h"
! 9:
! 10: #ifdef _MSC_VER
! 11: # if _MSC_VER >= 1300
! 12: /* in MSVC.NET these are available but only for __cplusplus and not _MSC_EXTENSIONS */
! 13: # if !defined(_MSC_EXTENSIONS) && defined(__cplusplus)
! 14: # define HAVE_FABSF 1
! 15: extern float fabsf(float x);
! 16: # define HAVE_FLOORF 1
! 17: extern float floorf(float x);
! 18: # endif /*MSVC.NET */
! 19: # endif /* MSC */
! 20: #endif
! 21: #ifndef HAVE_FABSF
! 22: # define HAVE_FABSF 0
! 23: #endif
! 24: #ifndef HAVE_FLOORF
! 25: # define HAVE_FLOORF 0
! 26: #endif
! 27: #if HAVE_FABSF == 0
! 28: /* float fabsf(float x); */
! 29: # ifndef fabsf
! 30: # define fabsf(x) ((float)(fabs(x)))
! 31: # endif
! 32: #endif
! 33: #if HAVE_FLOORF == 0
! 34: # ifndef floorf
! 35: /* float floorf(float x);*/
! 36: # define floorf(x) ((float)(floor(x)))
! 37: # endif
! 38: #endif
! 39:
! 40: #ifdef _OSD_POSIX /* BS2000 uses the EBCDIC char set instead of ASCII */
! 41: #define CHARSET_EBCDIC
! 42: #define __attribute__(any) /*nothing */
! 43: #endif
! 44: /*_OSD_POSIX*/
! 45:
! 46: #ifndef CHARSET_EBCDIC
! 47: #define ASC(ch) ch
! 48: #else /*CHARSET_EBCDIC */
! 49: #define ASC(ch) gd_toascii[(unsigned char)ch]
! 50: static const unsigned char gd_toascii[256] =
! 51: {
! 52: /*00 */ 0x00, 0x01, 0x02, 0x03, 0x85, 0x09, 0x86, 0x7f,
! 53: 0x87, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /*................ */
! 54: /*10 */ 0x10, 0x11, 0x12, 0x13, 0x8f, 0x0a, 0x08, 0x97,
! 55: 0x18, 0x19, 0x9c, 0x9d, 0x1c, 0x1d, 0x1e, 0x1f, /*................ */
! 56: /*20 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x92, 0x17, 0x1b,
! 57: 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, /*................ */
! 58: /*30 */ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
! 59: 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, /*................ */
! 60: /*40 */ 0x20, 0xa0, 0xe2, 0xe4, 0xe0, 0xe1, 0xe3, 0xe5,
! 61: 0xe7, 0xf1, 0x60, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, /* .........`.<(+| */
! 62: /*50 */ 0x26, 0xe9, 0xea, 0xeb, 0xe8, 0xed, 0xee, 0xef,
! 63: 0xec, 0xdf, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x9f, /*&.........!$*);. */
! 64: /*60 */ 0x2d, 0x2f, 0xc2, 0xc4, 0xc0, 0xc1, 0xc3, 0xc5,
! 65: 0xc7, 0xd1, 0x5e, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
! 66: /*-/........^,%_>?*/
! 67: /*70 */ 0xf8, 0xc9, 0xca, 0xcb, 0xc8, 0xcd, 0xce, 0xcf,
! 68: 0xcc, 0xa8, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, /*..........:#@'=" */
! 69: /*80 */ 0xd8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
! 70: 0x68, 0x69, 0xab, 0xbb, 0xf0, 0xfd, 0xfe, 0xb1, /*.abcdefghi...... */
! 71: /*90 */ 0xb0, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
! 72: 0x71, 0x72, 0xaa, 0xba, 0xe6, 0xb8, 0xc6, 0xa4, /*.jklmnopqr...... */
! 73: /*a0 */ 0xb5, 0xaf, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
! 74: 0x79, 0x7a, 0xa1, 0xbf, 0xd0, 0xdd, 0xde, 0xae, /*..stuvwxyz...... */
! 75: /*b0 */ 0xa2, 0xa3, 0xa5, 0xb7, 0xa9, 0xa7, 0xb6, 0xbc,
! 76: 0xbd, 0xbe, 0xac, 0x5b, 0x5c, 0x5d, 0xb4, 0xd7, /*...........[\].. */
! 77: /*c0 */ 0xf9, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
! 78: 0x48, 0x49, 0xad, 0xf4, 0xf6, 0xf2, 0xf3, 0xf5, /*.ABCDEFGHI...... */
! 79: /*d0 */ 0xa6, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
! 80: 0x51, 0x52, 0xb9, 0xfb, 0xfc, 0xdb, 0xfa, 0xff, /*.JKLMNOPQR...... */
! 81: /*e0 */ 0xd9, 0xf7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
! 82: 0x59, 0x5a, 0xb2, 0xd4, 0xd6, 0xd2, 0xd3, 0xd5, /*..STUVWXYZ...... */
! 83: /*f0 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
! 84: 0x38, 0x39, 0xb3, 0x7b, 0xdc, 0x7d, 0xda, 0x7e /*0123456789.{.}.~ */
! 85: };
! 86: #endif /*CHARSET_EBCDIC */
! 87:
! 88: /* 2.0.10: cast instead of floor() yields 35% performance improvement. Thanks to John Buckman. */
! 89: #define floor_cast(exp) ((long) exp)
! 90:
! 91: extern int gdCosT[];
! 92: extern int gdSinT[];
! 93:
! 94: static void gdImageBrushApply(gdImagePtr im, int x, int y);
! 95: static void gdImageTileApply(gdImagePtr im, int x, int y);
! 96: static void gdImageAntiAliasedApply(gdImagePtr im, int x, int y);
! 97: static int gdLayerOverlay(int dst, int src);
! 98: static int gdAlphaOverlayColor(int src, int dst, int max);
! 99: int gdImageGetTrueColorPixel(gdImagePtr im, int x, int y);
! 100:
! 101: void php_gd_error_ex(int type, const char *format, ...)
! 102: {
! 103: va_list args;
! 104:
! 105: TSRMLS_FETCH();
! 106:
! 107: va_start(args, format);
! 108: php_verror(NULL, "", type, format, args TSRMLS_CC);
! 109: va_end(args);
! 110: }
! 111:
! 112: void php_gd_error(const char *format, ...)
! 113: {
! 114: va_list args;
! 115:
! 116: TSRMLS_FETCH();
! 117:
! 118: va_start(args, format);
! 119: php_verror(NULL, "", E_WARNING, format, args TSRMLS_CC);
! 120: va_end(args);
! 121: }
! 122:
! 123: gdImagePtr gdImageCreate (int sx, int sy)
! 124: {
! 125: int i;
! 126: gdImagePtr im;
! 127:
! 128: if (overflow2(sx, sy)) {
! 129: return NULL;
! 130: }
! 131:
! 132: if (overflow2(sizeof(unsigned char *), sy)) {
! 133: return NULL;
! 134: }
! 135:
! 136: im = (gdImage *) gdCalloc(1, sizeof(gdImage));
! 137:
! 138: /* Row-major ever since gd 1.3 */
! 139: im->pixels = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
! 140: im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
! 141: im->polyInts = 0;
! 142: im->polyAllocated = 0;
! 143: im->brush = 0;
! 144: im->tile = 0;
! 145: im->style = 0;
! 146: for (i = 0; i < sy; i++) {
! 147: /* Row-major ever since gd 1.3 */
! 148: im->pixels[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
! 149: im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
! 150: }
! 151: im->sx = sx;
! 152: im->sy = sy;
! 153: im->colorsTotal = 0;
! 154: im->transparent = (-1);
! 155: im->interlace = 0;
! 156: im->thick = 1;
! 157: im->AA = 0;
! 158: im->AA_polygon = 0;
! 159: for (i = 0; i < gdMaxColors; i++) {
! 160: im->open[i] = 1;
! 161: im->red[i] = 0;
! 162: im->green[i] = 0;
! 163: im->blue[i] = 0;
! 164: }
! 165: im->trueColor = 0;
! 166: im->tpixels = 0;
! 167: im->cx1 = 0;
! 168: im->cy1 = 0;
! 169: im->cx2 = im->sx - 1;
! 170: im->cy2 = im->sy - 1;
! 171: return im;
! 172: }
! 173:
! 174: gdImagePtr gdImageCreateTrueColor (int sx, int sy)
! 175: {
! 176: int i;
! 177: gdImagePtr im;
! 178:
! 179: if (overflow2(sx, sy)) {
! 180: return NULL;
! 181: }
! 182:
! 183: if (overflow2(sizeof(unsigned char *), sy)) {
! 184: return NULL;
! 185: }
! 186:
! 187: if (overflow2(sizeof(int), sx)) {
! 188: return NULL;
! 189: }
! 190:
! 191: im = (gdImage *) gdMalloc(sizeof(gdImage));
! 192: memset(im, 0, sizeof(gdImage));
! 193: im->tpixels = (int **) gdMalloc(sizeof(int *) * sy);
! 194: im->AA_opacity = (unsigned char **) gdMalloc(sizeof(unsigned char *) * sy);
! 195: im->polyInts = 0;
! 196: im->polyAllocated = 0;
! 197: im->brush = 0;
! 198: im->tile = 0;
! 199: im->style = 0;
! 200: for (i = 0; i < sy; i++) {
! 201: im->tpixels[i] = (int *) gdCalloc(sx, sizeof(int));
! 202: im->AA_opacity[i] = (unsigned char *) gdCalloc(sx, sizeof(unsigned char));
! 203: }
! 204: im->sx = sx;
! 205: im->sy = sy;
! 206: im->transparent = (-1);
! 207: im->interlace = 0;
! 208: im->trueColor = 1;
! 209: /* 2.0.2: alpha blending is now on by default, and saving of alpha is
! 210: * off by default. This allows font antialiasing to work as expected
! 211: * on the first try in JPEGs -- quite important -- and also allows
! 212: * for smaller PNGs when saving of alpha channel is not really
! 213: * desired, which it usually isn't!
! 214: */
! 215: im->saveAlphaFlag = 0;
! 216: im->alphaBlendingFlag = 1;
! 217: im->thick = 1;
! 218: im->AA = 0;
! 219: im->AA_polygon = 0;
! 220: im->cx1 = 0;
! 221: im->cy1 = 0;
! 222: im->cx2 = im->sx - 1;
! 223: im->cy2 = im->sy - 1;
! 224: return im;
! 225: }
! 226:
! 227: void gdImageDestroy (gdImagePtr im)
! 228: {
! 229: int i;
! 230: if (im->pixels) {
! 231: for (i = 0; i < im->sy; i++) {
! 232: gdFree(im->pixels[i]);
! 233: }
! 234: gdFree(im->pixels);
! 235: }
! 236: if (im->tpixels) {
! 237: for (i = 0; i < im->sy; i++) {
! 238: gdFree(im->tpixels[i]);
! 239: }
! 240: gdFree(im->tpixels);
! 241: }
! 242: if (im->AA_opacity) {
! 243: for (i = 0; i < im->sy; i++) {
! 244: gdFree(im->AA_opacity[i]);
! 245: }
! 246: gdFree(im->AA_opacity);
! 247: }
! 248: if (im->polyInts) {
! 249: gdFree(im->polyInts);
! 250: }
! 251: if (im->style) {
! 252: gdFree(im->style);
! 253: }
! 254: gdFree(im);
! 255: }
! 256:
! 257: int gdImageColorClosest (gdImagePtr im, int r, int g, int b)
! 258: {
! 259: return gdImageColorClosestAlpha (im, r, g, b, gdAlphaOpaque);
! 260: }
! 261:
! 262: int gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a)
! 263: {
! 264: int i;
! 265: long rd, gd, bd, ad;
! 266: int ct = (-1);
! 267: int first = 1;
! 268: long mindist = 0;
! 269:
! 270: if (im->trueColor) {
! 271: return gdTrueColorAlpha(r, g, b, a);
! 272: }
! 273: for (i = 0; i < im->colorsTotal; i++) {
! 274: long dist;
! 275: if (im->open[i]) {
! 276: continue;
! 277: }
! 278: rd = im->red[i] - r;
! 279: gd = im->green[i] - g;
! 280: bd = im->blue[i] - b;
! 281: /* gd 2.02: whoops, was - b (thanks to David Marwood) */
! 282: ad = im->alpha[i] - a;
! 283: dist = rd * rd + gd * gd + bd * bd + ad * ad;
! 284: if (first || (dist < mindist)) {
! 285: mindist = dist;
! 286: ct = i;
! 287: first = 0;
! 288: }
! 289: }
! 290: return ct;
! 291: }
! 292:
! 293: /* This code is taken from http://www.acm.org/jgt/papers/SmithLyons96/hwb_rgb.html, an article
! 294: * on colour conversion to/from RBG and HWB colour systems.
! 295: * It has been modified to return the converted value as a * parameter.
! 296: */
! 297:
! 298: #define RETURN_HWB(h, w, b) {HWB->H = h; HWB->W = w; HWB->B = b; return HWB;}
! 299: #define RETURN_RGB(r, g, b) {RGB->R = r; RGB->G = g; RGB->B = b; return RGB;}
! 300: #define HWB_UNDEFINED -1
! 301: #define SETUP_RGB(s, r, g, b) {s.R = r/255.0f; s.G = g/255.0f; s.B = b/255.0f;}
! 302:
! 303: #ifndef MIN
! 304: #define MIN(a,b) ((a)<(b)?(a):(b))
! 305: #endif
! 306: #define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c)))
! 307: #ifndef MAX
! 308: #define MAX(a,b) ((a)<(b)?(b):(a))
! 309: #endif
! 310: #define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c)))
! 311:
! 312:
! 313: /*
! 314: * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms. Pure
! 315: * red always maps to 6 in this implementation. Therefore UNDEFINED can be
! 316: * defined as 0 in situations where only unsigned numbers are desired.
! 317: */
! 318: typedef struct
! 319: {
! 320: float R, G, B;
! 321: }
! 322: RGBType;
! 323: typedef struct
! 324: {
! 325: float H, W, B;
! 326: }
! 327: HWBType;
! 328:
! 329: static HWBType * RGB_to_HWB (RGBType RGB, HWBType * HWB)
! 330: {
! 331: /*
! 332: * RGB are each on [0, 1]. W and B are returned on [0, 1] and H is
! 333: * returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B.
! 334: */
! 335:
! 336: float R = RGB.R, G = RGB.G, B = RGB.B, w, v, b, f;
! 337: int i;
! 338:
! 339: w = MIN3 (R, G, B);
! 340: v = MAX3 (R, G, B);
! 341: b = 1 - v;
! 342: if (v == w) {
! 343: RETURN_HWB(HWB_UNDEFINED, w, b);
! 344: }
! 345: f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
! 346: i = (R == w) ? 3 : ((G == w) ? 5 : 1);
! 347:
! 348: RETURN_HWB(i - f / (v - w), w, b);
! 349: }
! 350:
! 351: static float HWB_Diff (int r1, int g1, int b1, int r2, int g2, int b2)
! 352: {
! 353: RGBType RGB1, RGB2;
! 354: HWBType HWB1, HWB2;
! 355: float diff;
! 356:
! 357: SETUP_RGB(RGB1, r1, g1, b1);
! 358: SETUP_RGB(RGB2, r2, g2, b2);
! 359:
! 360: RGB_to_HWB(RGB1, &HWB1);
! 361: RGB_to_HWB(RGB2, &HWB2);
! 362:
! 363: /*
! 364: * I made this bit up; it seems to produce OK results, and it is certainly
! 365: * more visually correct than the current RGB metric. (PJW)
! 366: */
! 367:
! 368: if ((HWB1.H == HWB_UNDEFINED) || (HWB2.H == HWB_UNDEFINED)) {
! 369: diff = 0.0f; /* Undefined hues always match... */
! 370: } else {
! 371: diff = fabsf(HWB1.H - HWB2.H);
! 372: if (diff > 3.0f) {
! 373: diff = 6.0f - diff; /* Remember, it's a colour circle */
! 374: }
! 375: }
! 376:
! 377: diff = diff * diff + (HWB1.W - HWB2.W) * (HWB1.W - HWB2.W) + (HWB1.B - HWB2.B) * (HWB1.B - HWB2.B);
! 378:
! 379: return diff;
! 380: }
! 381:
! 382:
! 383: #if 0
! 384: /*
! 385: * This is not actually used, but is here for completeness, in case someone wants to
! 386: * use the HWB stuff for anything else...
! 387: */
! 388: static RGBType * HWB_to_RGB (HWBType HWB, RGBType * RGB)
! 389: {
! 390: /*
! 391: * H is given on [0, 6] or UNDEFINED. W and B are given on [0, 1].
! 392: * RGB are each returned on [0, 1].
! 393: */
! 394:
! 395: float h = HWB.H, w = HWB.W, b = HWB.B, v, n, f;
! 396: int i;
! 397:
! 398: v = 1 - b;
! 399: if (h == HWB_UNDEFINED) {
! 400: RETURN_RGB(v, v, v);
! 401: }
! 402: i = floor(h);
! 403: f = h - i;
! 404: if (i & 1) {
! 405: f = 1 - f; /* if i is odd */
! 406: }
! 407: n = w + f * (v - w); /* linear interpolation between w and v */
! 408: switch (i) {
! 409: case 6:
! 410: case 0:
! 411: RETURN_RGB(v, n, w);
! 412: case 1:
! 413: RETURN_RGB(n, v, w);
! 414: case 2:
! 415: RETURN_RGB(w, v, n);
! 416: case 3:
! 417: RETURN_RGB(w, n, v);
! 418: case 4:
! 419: RETURN_RGB(n, w, v);
! 420: case 5:
! 421: RETURN_RGB(v, w, n);
! 422: }
! 423:
! 424: return RGB;
! 425: }
! 426: #endif
! 427:
! 428: int gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b)
! 429: {
! 430: int i;
! 431: /* long rd, gd, bd; */
! 432: int ct = (-1);
! 433: int first = 1;
! 434: float mindist = 0;
! 435: if (im->trueColor) {
! 436: return gdTrueColor(r, g, b);
! 437: }
! 438: for (i = 0; i < im->colorsTotal; i++) {
! 439: float dist;
! 440: if (im->open[i]) {
! 441: continue;
! 442: }
! 443: dist = HWB_Diff(im->red[i], im->green[i], im->blue[i], r, g, b);
! 444: if (first || (dist < mindist)) {
! 445: mindist = dist;
! 446: ct = i;
! 447: first = 0;
! 448: }
! 449: }
! 450: return ct;
! 451: }
! 452:
! 453: int gdImageColorExact (gdImagePtr im, int r, int g, int b)
! 454: {
! 455: return gdImageColorExactAlpha (im, r, g, b, gdAlphaOpaque);
! 456: }
! 457:
! 458: int gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a)
! 459: {
! 460: int i;
! 461: if (im->trueColor) {
! 462: return gdTrueColorAlpha(r, g, b, a);
! 463: }
! 464: for (i = 0; i < im->colorsTotal; i++) {
! 465: if (im->open[i]) {
! 466: continue;
! 467: }
! 468: if ((im->red[i] == r) && (im->green[i] == g) && (im->blue[i] == b) && (im->alpha[i] == a)) {
! 469: return i;
! 470: }
! 471: }
! 472: return -1;
! 473: }
! 474:
! 475: int gdImageColorAllocate (gdImagePtr im, int r, int g, int b)
! 476: {
! 477: return gdImageColorAllocateAlpha (im, r, g, b, gdAlphaOpaque);
! 478: }
! 479:
! 480: int gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a)
! 481: {
! 482: int i;
! 483: int ct = (-1);
! 484: if (im->trueColor) {
! 485: return gdTrueColorAlpha(r, g, b, a);
! 486: }
! 487: for (i = 0; i < im->colorsTotal; i++) {
! 488: if (im->open[i]) {
! 489: ct = i;
! 490: break;
! 491: }
! 492: }
! 493: if (ct == (-1)) {
! 494: ct = im->colorsTotal;
! 495: if (ct == gdMaxColors) {
! 496: return -1;
! 497: }
! 498: im->colorsTotal++;
! 499: }
! 500: im->red[ct] = r;
! 501: im->green[ct] = g;
! 502: im->blue[ct] = b;
! 503: im->alpha[ct] = a;
! 504: im->open[ct] = 0;
! 505:
! 506: return ct;
! 507: }
! 508:
! 509: /*
! 510: * gdImageColorResolve is an alternative for the code fragment:
! 511: *
! 512: * if ((color=gdImageColorExact(im,R,G,B)) < 0)
! 513: * if ((color=gdImageColorAllocate(im,R,G,B)) < 0)
! 514: * color=gdImageColorClosest(im,R,G,B);
! 515: *
! 516: * in a single function. Its advantage is that it is guaranteed to
! 517: * return a color index in one search over the color table.
! 518: */
! 519:
! 520: int gdImageColorResolve (gdImagePtr im, int r, int g, int b)
! 521: {
! 522: return gdImageColorResolveAlpha(im, r, g, b, gdAlphaOpaque);
! 523: }
! 524:
! 525: int gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a)
! 526: {
! 527: int c;
! 528: int ct = -1;
! 529: int op = -1;
! 530: long rd, gd, bd, ad, dist;
! 531: long mindist = 4 * 255 * 255; /* init to max poss dist */
! 532: if (im->trueColor)
! 533: {
! 534: return gdTrueColorAlpha (r, g, b, a);
! 535: }
! 536:
! 537: for (c = 0; c < im->colorsTotal; c++)
! 538: {
! 539: if (im->open[c])
! 540: {
! 541: op = c; /* Save open slot */
! 542: continue; /* Color not in use */
! 543: }
! 544: if (c == im->transparent)
! 545: {
! 546: /* don't ever resolve to the color that has
! 547: * been designated as the transparent color */
! 548: continue;
! 549: }
! 550: rd = (long) (im->red[c] - r);
! 551: gd = (long) (im->green[c] - g);
! 552: bd = (long) (im->blue[c] - b);
! 553: ad = (long) (im->alpha[c] - a);
! 554: dist = rd * rd + gd * gd + bd * bd + ad * ad;
! 555: if (dist < mindist)
! 556: {
! 557: if (dist == 0)
! 558: {
! 559: return c; /* Return exact match color */
! 560: }
! 561: mindist = dist;
! 562: ct = c;
! 563: }
! 564: }
! 565: /* no exact match. We now know closest, but first try to allocate exact */
! 566: if (op == -1)
! 567: {
! 568: op = im->colorsTotal;
! 569: if (op == gdMaxColors)
! 570: { /* No room for more colors */
! 571: return ct; /* Return closest available color */
! 572: }
! 573: im->colorsTotal++;
! 574: }
! 575: im->red[op] = r;
! 576: im->green[op] = g;
! 577: im->blue[op] = b;
! 578: im->alpha[op] = a;
! 579: im->open[op] = 0;
! 580: return op; /* Return newly allocated color */
! 581: }
! 582:
! 583: void gdImageColorDeallocate (gdImagePtr im, int color)
! 584: {
! 585: if (im->trueColor) {
! 586: return;
! 587: }
! 588: /* Mark it open. */
! 589: im->open[color] = 1;
! 590: }
! 591:
! 592: void gdImageColorTransparent (gdImagePtr im, int color)
! 593: {
! 594: if (!im->trueColor) {
! 595: if (im->transparent != -1) {
! 596: im->alpha[im->transparent] = gdAlphaOpaque;
! 597: }
! 598: if (color > -1 && color < im->colorsTotal && color < gdMaxColors) {
! 599: im->alpha[color] = gdAlphaTransparent;
! 600: } else {
! 601: return;
! 602: }
! 603: }
! 604: im->transparent = color;
! 605: }
! 606:
! 607: void gdImagePaletteCopy (gdImagePtr to, gdImagePtr from)
! 608: {
! 609: int i;
! 610: int x, y, p;
! 611: int xlate[256];
! 612: if (to->trueColor || from->trueColor) {
! 613: return;
! 614: }
! 615:
! 616: for (i = 0; i < 256; i++) {
! 617: xlate[i] = -1;
! 618: }
! 619:
! 620: for (y = 0; y < to->sy; y++) {
! 621: for (x = 0; x < to->sx; x++) {
! 622: p = gdImageGetPixel(to, x, y);
! 623: if (xlate[p] == -1) {
! 624: /* This ought to use HWB, but we don't have an alpha-aware version of that yet. */
! 625: xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]);
! 626: }
! 627: gdImageSetPixel(to, x, y, xlate[p]);
! 628: }
! 629: }
! 630:
! 631: for (i = 0; i < from->colorsTotal; i++) {
! 632: to->red[i] = from->red[i];
! 633: to->blue[i] = from->blue[i];
! 634: to->green[i] = from->green[i];
! 635: to->alpha[i] = from->alpha[i];
! 636: to->open[i] = 0;
! 637: }
! 638:
! 639: for (i = from->colorsTotal; i < to->colorsTotal; i++) {
! 640: to->open[i] = 1;
! 641: }
! 642:
! 643: to->colorsTotal = from->colorsTotal;
! 644: }
! 645:
! 646: /* 2.0.10: before the drawing routines, some code to clip points that are
! 647: * outside the drawing window. Nick Atty (nick@canalplan.org.uk)
! 648: *
! 649: * This is the Sutherland Hodgman Algorithm, as implemented by
! 650: * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's
! 651: * Journal, January 1996, pp107-110 and 116-117
! 652: *
! 653: * Given the end points of a line, and a bounding rectangle (which we
! 654: * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on
! 655: * the edges of the rectangle if the line should be drawn at all,
! 656: * otherwise return a failure code
! 657: */
! 658:
! 659: /* this does "one-dimensional" clipping: note that the second time it
! 660: * is called, all the x parameters refer to height and the y to width
! 661: * - the comments ignore this (if you can understand it when it's
! 662: * looking at the X parameters, it should become clear what happens on
! 663: * the second call!) The code is simplified from that in the article,
! 664: * as we know that gd images always start at (0,0)
! 665: */
! 666:
! 667: static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) {
! 668: double m; /* gradient of line */
! 669:
! 670: if (*x0 < 0) { /* start of line is left of window */
! 671: if(*x1 < 0) { /* as is the end, so the line never cuts the window */
! 672: return 0;
! 673: }
! 674: m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
! 675: /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */
! 676: *y0 -= (int)(m * *x0);
! 677: *x0 = 0;
! 678: /* now, perhaps, adjust the far end of the line as well */
! 679: if (*x1 > maxdim) {
! 680: *y1 += (int)(m * (maxdim - *x1));
! 681: *x1 = maxdim;
! 682: }
! 683: return 1;
! 684: }
! 685: if (*x0 > maxdim) { /* start of line is right of window - complement of above */
! 686: if (*x1 > maxdim) { /* as is the end, so the line misses the window */
! 687: return 0;
! 688: }
! 689: m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
! 690: *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right boundary */
! 691: *x0 = maxdim;
! 692: /* now, perhaps, adjust the end of the line */
! 693: if (*x1 < 0) {
! 694: *y1 -= (int)(m * *x1);
! 695: *x1 = 0;
! 696: }
! 697: return 1;
! 698: }
! 699: /* the final case - the start of the line is inside the window */
! 700: if (*x1 > maxdim) { /* other end is outside to the right */
! 701: m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
! 702: *y1 += (int)(m * (maxdim - *x1));
! 703: *x1 = maxdim;
! 704: return 1;
! 705: }
! 706: if (*x1 < 0) { /* other end is outside to the left */
! 707: m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */
! 708: *y1 -= (int)(m * *x1);
! 709: *x1 = 0;
! 710: return 1;
! 711: }
! 712: /* only get here if both points are inside the window */
! 713: return 1;
! 714: }
! 715:
! 716: void gdImageSetPixel (gdImagePtr im, int x, int y, int color)
! 717: {
! 718: int p;
! 719: switch (color) {
! 720: case gdStyled:
! 721: if (!im->style) {
! 722: /* Refuse to draw if no style is set. */
! 723: return;
! 724: } else {
! 725: p = im->style[im->stylePos++];
! 726: }
! 727: if (p != gdTransparent) {
! 728: gdImageSetPixel(im, x, y, p);
! 729: }
! 730: im->stylePos = im->stylePos % im->styleLength;
! 731: break;
! 732: case gdStyledBrushed:
! 733: if (!im->style) {
! 734: /* Refuse to draw if no style is set. */
! 735: return;
! 736: }
! 737: p = im->style[im->stylePos++];
! 738: if (p != gdTransparent && p != 0) {
! 739: gdImageSetPixel(im, x, y, gdBrushed);
! 740: }
! 741: im->stylePos = im->stylePos % im->styleLength;
! 742: break;
! 743: case gdBrushed:
! 744: gdImageBrushApply(im, x, y);
! 745: break;
! 746: case gdTiled:
! 747: gdImageTileApply(im, x, y);
! 748: break;
! 749: case gdAntiAliased:
! 750: gdImageAntiAliasedApply(im, x, y);
! 751: break;
! 752: default:
! 753: if (gdImageBoundsSafe(im, x, y)) {
! 754: if (im->trueColor) {
! 755: switch (im->alphaBlendingFlag) {
! 756: default:
! 757: case gdEffectReplace:
! 758: im->tpixels[y][x] = color;
! 759: break;
! 760: case gdEffectAlphaBlend:
! 761: im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
! 762: break;
! 763: case gdEffectNormal:
! 764: im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color);
! 765: break;
! 766: case gdEffectOverlay :
! 767: im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color);
! 768: break;
! 769: }
! 770: } else {
! 771: im->pixels[y][x] = color;
! 772: }
! 773: }
! 774: break;
! 775: }
! 776: }
! 777:
! 778: int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y)
! 779: {
! 780: int p = gdImageGetPixel(im, x, y);
! 781:
! 782: if (!im->trueColor) {
! 783: return gdTrueColorAlpha(im->red[p], im->green[p], im->blue[p], (im->transparent == p) ? gdAlphaTransparent : im->alpha[p]);
! 784: } else {
! 785: return p;
! 786: }
! 787: }
! 788:
! 789: static void gdImageBrushApply (gdImagePtr im, int x, int y)
! 790: {
! 791: int lx, ly;
! 792: int hy, hx;
! 793: int x1, y1, x2, y2;
! 794: int srcx, srcy;
! 795:
! 796: if (!im->brush) {
! 797: return;
! 798: }
! 799:
! 800: hy = gdImageSY(im->brush) / 2;
! 801: y1 = y - hy;
! 802: y2 = y1 + gdImageSY(im->brush);
! 803: hx = gdImageSX(im->brush) / 2;
! 804: x1 = x - hx;
! 805: x2 = x1 + gdImageSX(im->brush);
! 806: srcy = 0;
! 807:
! 808: if (im->trueColor) {
! 809: if (im->brush->trueColor) {
! 810: for (ly = y1; ly < y2; ly++) {
! 811: srcx = 0;
! 812: for (lx = x1; (lx < x2); lx++) {
! 813: int p;
! 814: p = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
! 815: /* 2.0.9, Thomas Winzig: apply simple full transparency */
! 816: if (p != gdImageGetTransparent(im->brush)) {
! 817: gdImageSetPixel(im, lx, ly, p);
! 818: }
! 819: srcx++;
! 820: }
! 821: srcy++;
! 822: }
! 823: } else {
! 824: /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger for pointing out the issue) */
! 825: for (ly = y1; ly < y2; ly++) {
! 826: srcx = 0;
! 827: for (lx = x1; lx < x2; lx++) {
! 828: int p, tc;
! 829: p = gdImageGetPixel(im->brush, srcx, srcy);
! 830: tc = gdImageGetTrueColorPixel(im->brush, srcx, srcy);
! 831: /* 2.0.9, Thomas Winzig: apply simple full transparency */
! 832: if (p != gdImageGetTransparent(im->brush)) {
! 833: gdImageSetPixel(im, lx, ly, tc);
! 834: }
! 835: srcx++;
! 836: }
! 837: srcy++;
! 838: }
! 839: }
! 840: } else {
! 841: for (ly = y1; ly < y2; ly++) {
! 842: srcx = 0;
! 843: for (lx = x1; lx < x2; lx++) {
! 844: int p;
! 845: p = gdImageGetPixel(im->brush, srcx, srcy);
! 846: /* Allow for non-square brushes! */
! 847: if (p != gdImageGetTransparent(im->brush)) {
! 848: /* Truecolor brush. Very slow on a palette destination. */
! 849: if (im->brush->trueColor) {
! 850: gdImageSetPixel(im, lx, ly, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p),
! 851: gdTrueColorGetGreen(p),
! 852: gdTrueColorGetBlue(p),
! 853: gdTrueColorGetAlpha(p)));
! 854: } else {
! 855: gdImageSetPixel(im, lx, ly, im->brushColorMap[p]);
! 856: }
! 857: }
! 858: srcx++;
! 859: }
! 860: srcy++;
! 861: }
! 862: }
! 863: }
! 864:
! 865: static void gdImageTileApply (gdImagePtr im, int x, int y)
! 866: {
! 867: gdImagePtr tile = im->tile;
! 868: int srcx, srcy;
! 869: int p;
! 870: if (!tile) {
! 871: return;
! 872: }
! 873: srcx = x % gdImageSX(tile);
! 874: srcy = y % gdImageSY(tile);
! 875: if (im->trueColor) {
! 876: p = gdImageGetPixel(tile, srcx, srcy);
! 877: if (p != gdImageGetTransparent (tile)) {
! 878: if (!tile->trueColor) {
! 879: p = gdTrueColorAlpha(tile->red[p], tile->green[p], tile->blue[p], tile->alpha[p]);
! 880: }
! 881: gdImageSetPixel(im, x, y, p);
! 882: }
! 883: } else {
! 884: p = gdImageGetPixel(tile, srcx, srcy);
! 885: /* Allow for transparency */
! 886: if (p != gdImageGetTransparent(tile)) {
! 887: if (tile->trueColor) {
! 888: /* Truecolor tile. Very slow on a palette destination. */
! 889: gdImageSetPixel(im, x, y, gdImageColorResolveAlpha(im,
! 890: gdTrueColorGetRed(p),
! 891: gdTrueColorGetGreen(p),
! 892: gdTrueColorGetBlue(p),
! 893: gdTrueColorGetAlpha(p)));
! 894: } else {
! 895: gdImageSetPixel(im, x, y, im->tileColorMap[p]);
! 896: }
! 897: }
! 898: }
! 899: }
! 900:
! 901:
! 902: static int gdImageTileGet (gdImagePtr im, int x, int y)
! 903: {
! 904: int srcx, srcy;
! 905: int tileColor,p;
! 906: if (!im->tile) {
! 907: return -1;
! 908: }
! 909: srcx = x % gdImageSX(im->tile);
! 910: srcy = y % gdImageSY(im->tile);
! 911: p = gdImageGetPixel(im->tile, srcx, srcy);
! 912:
! 913: if (im->trueColor) {
! 914: if (im->tile->trueColor) {
! 915: tileColor = p;
! 916: } else {
! 917: tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
! 918: }
! 919: } else {
! 920: if (im->tile->trueColor) {
! 921: tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p));
! 922: } else {
! 923: tileColor = p;
! 924: tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p));
! 925: }
! 926: }
! 927: return tileColor;
! 928: }
! 929:
! 930:
! 931: static void gdImageAntiAliasedApply (gdImagePtr im, int px, int py)
! 932: {
! 933: float p_dist, p_alpha;
! 934: unsigned char opacity;
! 935:
! 936: /*
! 937: * Find the perpendicular distance from point C (px, py) to the line
! 938: * segment AB that is being drawn. (Adapted from an algorithm from the
! 939: * comp.graphics.algorithms FAQ.)
! 940: */
! 941:
! 942: int LAC_2, LBC_2;
! 943:
! 944: int Ax_Cx = im->AAL_x1 - px;
! 945: int Ay_Cy = im->AAL_y1 - py;
! 946:
! 947: int Bx_Cx = im->AAL_x2 - px;
! 948: int By_Cy = im->AAL_y2 - py;
! 949:
! 950: /* 2.0.13: bounds check! AA_opacity is just as capable of
! 951: * overflowing as the main pixel array. Arne Jorgensen.
! 952: * 2.0.14: typo fixed. 2.0.15: moved down below declarations
! 953: * to satisfy non-C++ compilers.
! 954: */
! 955: if (!gdImageBoundsSafe(im, px, py)) {
! 956: return;
! 957: }
! 958:
! 959: /* Get the squares of the lengths of the segemnts AC and BC. */
! 960: LAC_2 = (Ax_Cx * Ax_Cx) + (Ay_Cy * Ay_Cy);
! 961: LBC_2 = (Bx_Cx * Bx_Cx) + (By_Cy * By_Cy);
! 962:
! 963: if (((im->AAL_LAB_2 + LAC_2) >= LBC_2) && ((im->AAL_LAB_2 + LBC_2) >= LAC_2)) {
! 964: /* The two angles are acute. The point lies inside the portion of the
! 965: * plane spanned by the line segment.
! 966: */
! 967: p_dist = fabs ((float) ((Ay_Cy * im->AAL_Bx_Ax) - (Ax_Cx * im->AAL_By_Ay)) / im->AAL_LAB);
! 968: } else {
! 969: /* The point is past an end of the line segment. It's length from the
! 970: * segment is the shorter of the lengths from the endpoints, but call
! 971: * the distance -1, so as not to compute the alpha nor draw the pixel.
! 972: */
! 973: p_dist = -1;
! 974: }
! 975:
! 976: if ((p_dist >= 0) && (p_dist <= (float) (im->thick))) {
! 977: p_alpha = pow (1.0 - (p_dist / 1.5), 2);
! 978:
! 979: if (p_alpha > 0) {
! 980: if (p_alpha >= 1) {
! 981: opacity = 255;
! 982: } else {
! 983: opacity = (unsigned char) (p_alpha * 255.0);
! 984: }
! 985: if (!im->AA_polygon || (im->AA_opacity[py][px] < opacity)) {
! 986: im->AA_opacity[py][px] = opacity;
! 987: }
! 988: }
! 989: }
! 990: }
! 991:
! 992:
! 993: int gdImageGetPixel (gdImagePtr im, int x, int y)
! 994: {
! 995: if (gdImageBoundsSafe(im, x, y)) {
! 996: if (im->trueColor) {
! 997: return im->tpixels[y][x];
! 998: } else {
! 999: return im->pixels[y][x];
! 1000: }
! 1001: } else {
! 1002: return 0;
! 1003: }
! 1004: }
! 1005:
! 1006: void gdImageAABlend (gdImagePtr im)
! 1007: {
! 1008: float p_alpha, old_alpha;
! 1009: int color = im->AA_color, color_red, color_green, color_blue;
! 1010: int old_color, old_red, old_green, old_blue;
! 1011: int p_color, p_red, p_green, p_blue;
! 1012: int px, py;
! 1013:
! 1014: color_red = gdImageRed(im, color);
! 1015: color_green = gdImageGreen(im, color);
! 1016: color_blue = gdImageBlue(im, color);
! 1017:
! 1018: /* Impose the anti-aliased drawing on the image. */
! 1019: for (py = 0; py < im->sy; py++) {
! 1020: for (px = 0; px < im->sx; px++) {
! 1021: if (im->AA_opacity[py][px] != 0) {
! 1022: old_color = gdImageGetPixel(im, px, py);
! 1023:
! 1024: if ((old_color != color) && ((old_color != im->AA_dont_blend) || (im->AA_opacity[py][px] == 255))) {
! 1025: /* Only blend with different colors that aren't the dont_blend color. */
! 1026: p_alpha = (float) (im->AA_opacity[py][px]) / 255.0;
! 1027: old_alpha = 1.0 - p_alpha;
! 1028:
! 1029: if (p_alpha >= 1.0) {
! 1030: p_color = color;
! 1031: } else {
! 1032: old_red = gdImageRed(im, old_color);
! 1033: old_green = gdImageGreen(im, old_color);
! 1034: old_blue = gdImageBlue(im, old_color);
! 1035:
! 1036: p_red = (int) (((float) color_red * p_alpha) + ((float) old_red * old_alpha));
! 1037: p_green = (int) (((float) color_green * p_alpha) + ((float) old_green * old_alpha));
! 1038: p_blue = (int) (((float) color_blue * p_alpha) + ((float) old_blue * old_alpha));
! 1039: p_color = gdImageColorResolve(im, p_red, p_green, p_blue);
! 1040: }
! 1041: gdImageSetPixel(im, px, py, p_color);
! 1042: }
! 1043: }
! 1044: }
! 1045: /* Clear the AA_opacity array behind us. */
! 1046: memset(im->AA_opacity[py], 0, im->sx);
! 1047: }
! 1048: }
! 1049:
! 1050: static void gdImageHLine(gdImagePtr im, int y, int x1, int x2, int col)
! 1051: {
! 1052: if (im->thick > 1) {
! 1053: int thickhalf = im->thick >> 1;
! 1054: gdImageFilledRectangle(im, x1, y - thickhalf, x2, y + im->thick - thickhalf - 1, col);
! 1055: } else {
! 1056: if (x2 < x1) {
! 1057: int t = x2;
! 1058: x2 = x1;
! 1059: x1 = t;
! 1060: }
! 1061:
! 1062: for (;x1 <= x2; x1++) {
! 1063: gdImageSetPixel(im, x1, y, col);
! 1064: }
! 1065: }
! 1066: return;
! 1067: }
! 1068:
! 1069: static void gdImageVLine(gdImagePtr im, int x, int y1, int y2, int col)
! 1070: {
! 1071: if (im->thick > 1) {
! 1072: int thickhalf = im->thick >> 1;
! 1073: gdImageFilledRectangle(im, x - thickhalf, y1, x + im->thick - thickhalf - 1, y2, col);
! 1074: } else {
! 1075: if (y2 < y1) {
! 1076: int t = y1;
! 1077: y1 = y2;
! 1078: y2 = t;
! 1079: }
! 1080:
! 1081: for (;y1 <= y2; y1++) {
! 1082: gdImageSetPixel(im, x, y1, col);
! 1083: }
! 1084: }
! 1085: return;
! 1086: }
! 1087:
! 1088: /* Bresenham as presented in Foley & Van Dam */
! 1089: void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
! 1090: {
! 1091: int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
! 1092: int wid;
! 1093: int w, wstart;
! 1094: int thick = im->thick;
! 1095:
! 1096: if (color == gdAntiAliased) {
! 1097: /*
! 1098: gdAntiAliased passed as color: use the much faster, much cheaper
! 1099: and equally attractive gdImageAALine implementation. That
! 1100: clips too, so don't clip twice.
! 1101: */
! 1102: gdImageAALine(im, x1, y1, x2, y2, im->AA_color);
! 1103: return;
! 1104: }
! 1105:
! 1106: /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */
! 1107: if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im))) {
! 1108: return;
! 1109: }
! 1110:
! 1111: dx = abs (x2 - x1);
! 1112: dy = abs (y2 - y1);
! 1113:
! 1114: if (dx == 0) {
! 1115: gdImageVLine(im, x1, y1, y2, color);
! 1116: return;
! 1117: } else if (dy == 0) {
! 1118: gdImageHLine(im, y1, x1, x2, color);
! 1119: return;
! 1120: }
! 1121:
! 1122: if (dy <= dx) {
! 1123: /* More-or-less horizontal. use wid for vertical stroke */
! 1124: /* Doug Claar: watch out for NaN in atan2 (2.0.5) */
! 1125: if ((dx == 0) && (dy == 0)) {
! 1126: wid = 1;
! 1127: } else {
! 1128: /* 2.0.12: Michael Schwartz: divide rather than multiply;
! 1129: TBB: but watch out for /0! */
! 1130: double ac = cos (atan2 (dy, dx));
! 1131: if (ac != 0) {
! 1132: wid = thick / ac;
! 1133: } else {
! 1134: wid = 1;
! 1135: }
! 1136: if (wid == 0) {
! 1137: wid = 1;
! 1138: }
! 1139: }
! 1140: d = 2 * dy - dx;
! 1141: incr1 = 2 * dy;
! 1142: incr2 = 2 * (dy - dx);
! 1143: if (x1 > x2) {
! 1144: x = x2;
! 1145: y = y2;
! 1146: ydirflag = (-1);
! 1147: xend = x1;
! 1148: } else {
! 1149: x = x1;
! 1150: y = y1;
! 1151: ydirflag = 1;
! 1152: xend = x2;
! 1153: }
! 1154:
! 1155: /* Set up line thickness */
! 1156: wstart = y - wid / 2;
! 1157: for (w = wstart; w < wstart + wid; w++) {
! 1158: gdImageSetPixel(im, x, w, color);
! 1159: }
! 1160:
! 1161: if (((y2 - y1) * ydirflag) > 0) {
! 1162: while (x < xend) {
! 1163: x++;
! 1164: if (d < 0) {
! 1165: d += incr1;
! 1166: } else {
! 1167: y++;
! 1168: d += incr2;
! 1169: }
! 1170: wstart = y - wid / 2;
! 1171: for (w = wstart; w < wstart + wid; w++) {
! 1172: gdImageSetPixel (im, x, w, color);
! 1173: }
! 1174: }
! 1175: } else {
! 1176: while (x < xend) {
! 1177: x++;
! 1178: if (d < 0) {
! 1179: d += incr1;
! 1180: } else {
! 1181: y--;
! 1182: d += incr2;
! 1183: }
! 1184: wstart = y - wid / 2;
! 1185: for (w = wstart; w < wstart + wid; w++) {
! 1186: gdImageSetPixel (im, x, w, color);
! 1187: }
! 1188: }
! 1189: }
! 1190: } else {
! 1191: /* More-or-less vertical. use wid for horizontal stroke */
! 1192: /* 2.0.12: Michael Schwartz: divide rather than multiply;
! 1193: TBB: but watch out for /0! */
! 1194: double as = sin (atan2 (dy, dx));
! 1195: if (as != 0) {
! 1196: wid = thick / as;
! 1197: } else {
! 1198: wid = 1;
! 1199: }
! 1200: if (wid == 0) {
! 1201: wid = 1;
! 1202: }
! 1203:
! 1204: d = 2 * dx - dy;
! 1205: incr1 = 2 * dx;
! 1206: incr2 = 2 * (dx - dy);
! 1207: if (y1 > y2) {
! 1208: y = y2;
! 1209: x = x2;
! 1210: yend = y1;
! 1211: xdirflag = (-1);
! 1212: } else {
! 1213: y = y1;
! 1214: x = x1;
! 1215: yend = y2;
! 1216: xdirflag = 1;
! 1217: }
! 1218:
! 1219: /* Set up line thickness */
! 1220: wstart = x - wid / 2;
! 1221: for (w = wstart; w < wstart + wid; w++) {
! 1222: gdImageSetPixel (im, w, y, color);
! 1223: }
! 1224:
! 1225: if (((x2 - x1) * xdirflag) > 0) {
! 1226: while (y < yend) {
! 1227: y++;
! 1228: if (d < 0) {
! 1229: d += incr1;
! 1230: } else {
! 1231: x++;
! 1232: d += incr2;
! 1233: }
! 1234: wstart = x - wid / 2;
! 1235: for (w = wstart; w < wstart + wid; w++) {
! 1236: gdImageSetPixel (im, w, y, color);
! 1237: }
! 1238: }
! 1239: } else {
! 1240: while (y < yend) {
! 1241: y++;
! 1242: if (d < 0) {
! 1243: d += incr1;
! 1244: } else {
! 1245: x--;
! 1246: d += incr2;
! 1247: }
! 1248: wstart = x - wid / 2;
! 1249: for (w = wstart; w < wstart + wid; w++) {
! 1250: gdImageSetPixel (im, w, y, color);
! 1251: }
! 1252: }
! 1253: }
! 1254: }
! 1255: }
! 1256:
! 1257:
! 1258: /*
! 1259: * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
! 1260: * */
! 1261: #define BLEND_COLOR(a, nc, c, cc) \
! 1262: nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
! 1263:
! 1264: inline static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
! 1265: {
! 1266: int dr,dg,db,p,r,g,b;
! 1267: dr = gdTrueColorGetRed(color);
! 1268: dg = gdTrueColorGetGreen(color);
! 1269: db = gdTrueColorGetBlue(color);
! 1270:
! 1271: p = gdImageGetPixel(im,x,y);
! 1272: r = gdTrueColorGetRed(p);
! 1273: g = gdTrueColorGetGreen(p);
! 1274: b = gdTrueColorGetBlue(p);
! 1275:
! 1276: BLEND_COLOR(t, dr, r, dr);
! 1277: BLEND_COLOR(t, dg, g, dg);
! 1278: BLEND_COLOR(t, db, b, db);
! 1279: im->tpixels[y][x]=gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
! 1280: }
! 1281:
! 1282: /*
! 1283: * Added on 2003/12 by Pierre-Alain Joye (pajoye@pearfr.org)
! 1284: **/
! 1285: void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col)
! 1286: {
! 1287: /* keep them as 32bits */
! 1288: long x, y, inc;
! 1289: long dx, dy,tmp;
! 1290:
! 1291: if (y1 < 0 && y2 < 0) {
! 1292: return;
! 1293: }
! 1294: if (y1 < 0) {
! 1295: x1 += (y1 * (x1 - x2)) / (y2 - y1);
! 1296: y1 = 0;
! 1297: }
! 1298: if (y2 < 0) {
! 1299: x2 += (y2 * (x1 - x2)) / (y2 - y1);
! 1300: y2 = 0;
! 1301: }
! 1302:
! 1303: /* bottom edge */
! 1304: if (y1 >= im->sy && y2 >= im->sy) {
! 1305: return;
! 1306: }
! 1307: if (y1 >= im->sy) {
! 1308: x1 -= ((im->sy - y1) * (x1 - x2)) / (y2 - y1);
! 1309: y1 = im->sy - 1;
! 1310: }
! 1311: if (y2 >= im->sy) {
! 1312: x2 -= ((im->sy - y2) * (x1 - x2)) / (y2 - y1);
! 1313: y2 = im->sy - 1;
! 1314: }
! 1315:
! 1316: /* left edge */
! 1317: if (x1 < 0 && x2 < 0) {
! 1318: return;
! 1319: }
! 1320: if (x1 < 0) {
! 1321: y1 += (x1 * (y1 - y2)) / (x2 - x1);
! 1322: x1 = 0;
! 1323: }
! 1324: if (x2 < 0) {
! 1325: y2 += (x2 * (y1 - y2)) / (x2 - x1);
! 1326: x2 = 0;
! 1327: }
! 1328: /* right edge */
! 1329: if (x1 >= im->sx && x2 >= im->sx) {
! 1330: return;
! 1331: }
! 1332: if (x1 >= im->sx) {
! 1333: y1 -= ((im->sx - x1) * (y1 - y2)) / (x2 - x1);
! 1334: x1 = im->sx - 1;
! 1335: }
! 1336: if (x2 >= im->sx) {
! 1337: y2 -= ((im->sx - x2) * (y1 - y2)) / (x2 - x1);
! 1338: x2 = im->sx - 1;
! 1339: }
! 1340:
! 1341: dx = x2 - x1;
! 1342: dy = y2 - y1;
! 1343:
! 1344: if (dx == 0 && dy == 0) {
! 1345: return;
! 1346: }
! 1347: if (abs(dx) > abs(dy)) {
! 1348: if (dx < 0) {
! 1349: tmp = x1;
! 1350: x1 = x2;
! 1351: x2 = tmp;
! 1352: tmp = y1;
! 1353: y1 = y2;
! 1354: y2 = tmp;
! 1355: dx = x2 - x1;
! 1356: dy = y2 - y1;
! 1357: }
! 1358: x = x1 << 16;
! 1359: y = y1 << 16;
! 1360: inc = (dy * 65536) / dx;
! 1361: while ((x >> 16) <= x2) {
! 1362: gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (y >> 8) & 0xFF);
! 1363: if ((y >> 16) + 1 < im->sy) {
! 1364: gdImageSetAAPixelColor(im, x >> 16, (y >> 16) + 1,col, (~y >> 8) & 0xFF);
! 1365: }
! 1366: x += (1 << 16);
! 1367: y += inc;
! 1368: }
! 1369: } else {
! 1370: if (dy < 0) {
! 1371: tmp = x1;
! 1372: x1 = x2;
! 1373: x2 = tmp;
! 1374: tmp = y1;
! 1375: y1 = y2;
! 1376: y2 = tmp;
! 1377: dx = x2 - x1;
! 1378: dy = y2 - y1;
! 1379: }
! 1380: x = x1 << 16;
! 1381: y = y1 << 16;
! 1382: inc = (dx * 65536) / dy;
! 1383: while ((y>>16) <= y2) {
! 1384: gdImageSetAAPixelColor(im, x >> 16, y >> 16, col, (x >> 8) & 0xFF);
! 1385: if ((x >> 16) + 1 < im->sx) {
! 1386: gdImageSetAAPixelColor(im, (x >> 16) + 1, (y >> 16),col, (~x >> 8) & 0xFF);
! 1387: }
! 1388: x += inc;
! 1389: y += (1<<16);
! 1390: }
! 1391: }
! 1392: }
! 1393:
! 1394: static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);
! 1395:
! 1396: void gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
! 1397: {
! 1398: int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
! 1399: int dashStep = 0;
! 1400: int on = 1;
! 1401: int wid;
! 1402: int vert;
! 1403: int thick = im->thick;
! 1404:
! 1405: dx = abs(x2 - x1);
! 1406: dy = abs(y2 - y1);
! 1407: if (dy <= dx) {
! 1408: /* More-or-less horizontal. use wid for vertical stroke */
! 1409: /* 2.0.12: Michael Schwartz: divide rather than multiply;
! 1410: TBB: but watch out for /0! */
! 1411: double as = sin(atan2(dy, dx));
! 1412: if (as != 0) {
! 1413: wid = thick / as;
! 1414: } else {
! 1415: wid = 1;
! 1416: }
! 1417: wid = (int)(thick * sin(atan2(dy, dx)));
! 1418: vert = 1;
! 1419:
! 1420: d = 2 * dy - dx;
! 1421: incr1 = 2 * dy;
! 1422: incr2 = 2 * (dy - dx);
! 1423: if (x1 > x2) {
! 1424: x = x2;
! 1425: y = y2;
! 1426: ydirflag = (-1);
! 1427: xend = x1;
! 1428: } else {
! 1429: x = x1;
! 1430: y = y1;
! 1431: ydirflag = 1;
! 1432: xend = x2;
! 1433: }
! 1434: dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
! 1435: if (((y2 - y1) * ydirflag) > 0) {
! 1436: while (x < xend) {
! 1437: x++;
! 1438: if (d < 0) {
! 1439: d += incr1;
! 1440: } else {
! 1441: y++;
! 1442: d += incr2;
! 1443: }
! 1444: dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
! 1445: }
! 1446: } else {
! 1447: while (x < xend) {
! 1448: x++;
! 1449: if (d < 0) {
! 1450: d += incr1;
! 1451: } else {
! 1452: y--;
! 1453: d += incr2;
! 1454: }
! 1455: dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
! 1456: }
! 1457: }
! 1458: } else {
! 1459: /* 2.0.12: Michael Schwartz: divide rather than multiply;
! 1460: TBB: but watch out for /0! */
! 1461: double as = sin (atan2 (dy, dx));
! 1462: if (as != 0) {
! 1463: wid = thick / as;
! 1464: } else {
! 1465: wid = 1;
! 1466: }
! 1467: vert = 0;
! 1468:
! 1469: d = 2 * dx - dy;
! 1470: incr1 = 2 * dx;
! 1471: incr2 = 2 * (dx - dy);
! 1472: if (y1 > y2) {
! 1473: y = y2;
! 1474: x = x2;
! 1475: yend = y1;
! 1476: xdirflag = (-1);
! 1477: } else {
! 1478: y = y1;
! 1479: x = x1;
! 1480: yend = y2;
! 1481: xdirflag = 1;
! 1482: }
! 1483: dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
! 1484: if (((x2 - x1) * xdirflag) > 0) {
! 1485: while (y < yend) {
! 1486: y++;
! 1487: if (d < 0) {
! 1488: d += incr1;
! 1489: } else {
! 1490: x++;
! 1491: d += incr2;
! 1492: }
! 1493: dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
! 1494: }
! 1495: } else {
! 1496: while (y < yend) {
! 1497: y++;
! 1498: if (d < 0) {
! 1499: d += incr1;
! 1500: } else {
! 1501: x--;
! 1502: d += incr2;
! 1503: }
! 1504: dashedSet(im, x, y, color, &on, &dashStep, wid, vert);
! 1505: }
! 1506: }
! 1507: }
! 1508: }
! 1509:
! 1510: static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert)
! 1511: {
! 1512: int dashStep = *dashStepP;
! 1513: int on = *onP;
! 1514: int w, wstart;
! 1515:
! 1516: dashStep++;
! 1517: if (dashStep == gdDashSize) {
! 1518: dashStep = 0;
! 1519: on = !on;
! 1520: }
! 1521: if (on) {
! 1522: if (vert) {
! 1523: wstart = y - wid / 2;
! 1524: for (w = wstart; w < wstart + wid; w++) {
! 1525: gdImageSetPixel(im, x, w, color);
! 1526: }
! 1527: } else {
! 1528: wstart = x - wid / 2;
! 1529: for (w = wstart; w < wstart + wid; w++) {
! 1530: gdImageSetPixel(im, w, y, color);
! 1531: }
! 1532: }
! 1533: }
! 1534: *dashStepP = dashStep;
! 1535: *onP = on;
! 1536: }
! 1537:
! 1538: void gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
! 1539: {
! 1540: int cx, cy;
! 1541: int px, py;
! 1542: int fline;
! 1543: cx = 0;
! 1544: cy = 0;
! 1545: #ifdef CHARSET_EBCDIC
! 1546: c = ASC (c);
! 1547: #endif /*CHARSET_EBCDIC */
! 1548: if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
! 1549: return;
! 1550: }
! 1551: fline = (c - f->offset) * f->h * f->w;
! 1552: for (py = y; (py < (y + f->h)); py++) {
! 1553: for (px = x; (px < (x + f->w)); px++) {
! 1554: if (f->data[fline + cy * f->w + cx]) {
! 1555: gdImageSetPixel(im, px, py, color);
! 1556: }
! 1557: cx++;
! 1558: }
! 1559: cx = 0;
! 1560: cy++;
! 1561: }
! 1562: }
! 1563:
! 1564: void gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, int color)
! 1565: {
! 1566: int cx, cy;
! 1567: int px, py;
! 1568: int fline;
! 1569: cx = 0;
! 1570: cy = 0;
! 1571: #ifdef CHARSET_EBCDIC
! 1572: c = ASC (c);
! 1573: #endif /*CHARSET_EBCDIC */
! 1574: if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
! 1575: return;
! 1576: }
! 1577: fline = (c - f->offset) * f->h * f->w;
! 1578: for (py = y; py > (y - f->w); py--) {
! 1579: for (px = x; px < (x + f->h); px++) {
! 1580: if (f->data[fline + cy * f->w + cx]) {
! 1581: gdImageSetPixel(im, px, py, color);
! 1582: }
! 1583: cy++;
! 1584: }
! 1585: cy = 0;
! 1586: cx++;
! 1587: }
! 1588: }
! 1589:
! 1590: void gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
! 1591: {
! 1592: int i;
! 1593: int l;
! 1594: l = strlen ((char *) s);
! 1595: for (i = 0; (i < l); i++) {
! 1596: gdImageChar(im, f, x, y, s[i], color);
! 1597: x += f->w;
! 1598: }
! 1599: }
! 1600:
! 1601: void gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, unsigned char *s, int color)
! 1602: {
! 1603: int i;
! 1604: int l;
! 1605: l = strlen ((char *) s);
! 1606: for (i = 0; (i < l); i++) {
! 1607: gdImageCharUp(im, f, x, y, s[i], color);
! 1608: y -= f->w;
! 1609: }
! 1610: }
! 1611:
! 1612: static int strlen16 (unsigned short *s);
! 1613:
! 1614: void gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
! 1615: {
! 1616: int i;
! 1617: int l;
! 1618: l = strlen16(s);
! 1619: for (i = 0; (i < l); i++) {
! 1620: gdImageChar(im, f, x, y, s[i], color);
! 1621: x += f->w;
! 1622: }
! 1623: }
! 1624:
! 1625: void gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, unsigned short *s, int color)
! 1626: {
! 1627: int i;
! 1628: int l;
! 1629: l = strlen16(s);
! 1630: for (i = 0; i < l; i++) {
! 1631: gdImageCharUp(im, f, x, y, s[i], color);
! 1632: y -= f->w;
! 1633: }
! 1634: }
! 1635:
! 1636: static int strlen16 (unsigned short *s)
! 1637: {
! 1638: int len = 0;
! 1639: while (*s) {
! 1640: s++;
! 1641: len++;
! 1642: }
! 1643: return len;
! 1644: }
! 1645:
! 1646: #ifndef HAVE_LSQRT
! 1647: /* If you don't have a nice square root function for longs, you can use
! 1648: ** this hack
! 1649: */
! 1650: long lsqrt (long n)
! 1651: {
! 1652: long result = (long) sqrt ((double) n);
! 1653: return result;
! 1654: }
! 1655: #endif
! 1656:
! 1657: /* s and e are integers modulo 360 (degrees), with 0 degrees
! 1658: being the rightmost extreme and degrees changing clockwise.
! 1659: cx and cy are the center in pixels; w and h are the horizontal
! 1660: and vertical diameter in pixels. Nice interface, but slow.
! 1661: See gd_arc_f_buggy.c for a better version that doesn't
! 1662: seem to be bug-free yet. */
! 1663:
! 1664: void gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color)
! 1665: {
! 1666: if ((s % 360) == (e % 360)) {
! 1667: gdImageEllipse(im, cx, cy, w, h, color);
! 1668: } else {
! 1669: gdImageFilledArc(im, cx, cy, w, h, s, e, color, gdNoFill);
! 1670: }
! 1671: }
! 1672:
! 1673: void gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, int color, int style)
! 1674: {
! 1675: gdPoint pts[3];
! 1676: int i;
! 1677: int lx = 0, ly = 0;
! 1678: int fx = 0, fy = 0;
! 1679:
! 1680:
! 1681: if ((s % 360) == (e % 360)) {
! 1682: s = 0; e = 360;
! 1683: } else {
! 1684: if (s > 360) {
! 1685: s = s % 360;
! 1686: }
! 1687:
! 1688: if (e > 360) {
! 1689: e = e % 360;
! 1690: }
! 1691:
! 1692: while (s < 0) {
! 1693: s += 360;
! 1694: }
! 1695:
! 1696: while (e < s) {
! 1697: e += 360;
! 1698: }
! 1699: if (s == e) {
! 1700: s = 0; e = 360;
! 1701: }
! 1702: }
! 1703:
! 1704: for (i = s; i <= e; i++) {
! 1705: int x, y;
! 1706: x = ((long) gdCosT[i % 360] * (long) w / (2 * 1024)) + cx;
! 1707: y = ((long) gdSinT[i % 360] * (long) h / (2 * 1024)) + cy;
! 1708: if (i != s) {
! 1709: if (!(style & gdChord)) {
! 1710: if (style & gdNoFill) {
! 1711: gdImageLine(im, lx, ly, x, y, color);
! 1712: } else {
! 1713: /* This is expensive! */
! 1714: pts[0].x = lx;
! 1715: pts[0].y = ly;
! 1716: pts[1].x = x;
! 1717: pts[1].y = y;
! 1718: pts[2].x = cx;
! 1719: pts[2].y = cy;
! 1720: gdImageFilledPolygon(im, pts, 3, color);
! 1721: }
! 1722: }
! 1723: } else {
! 1724: fx = x;
! 1725: fy = y;
! 1726: }
! 1727: lx = x;
! 1728: ly = y;
! 1729: }
! 1730: if (style & gdChord) {
! 1731: if (style & gdNoFill) {
! 1732: if (style & gdEdged) {
! 1733: gdImageLine(im, cx, cy, lx, ly, color);
! 1734: gdImageLine(im, cx, cy, fx, fy, color);
! 1735: }
! 1736: gdImageLine(im, fx, fy, lx, ly, color);
! 1737: } else {
! 1738: pts[0].x = fx;
! 1739: pts[0].y = fy;
! 1740: pts[1].x = lx;
! 1741: pts[1].y = ly;
! 1742: pts[2].x = cx;
! 1743: pts[2].y = cy;
! 1744: gdImageFilledPolygon(im, pts, 3, color);
! 1745: }
! 1746: } else {
! 1747: if (style & gdNoFill) {
! 1748: if (style & gdEdged) {
! 1749: gdImageLine(im, cx, cy, lx, ly, color);
! 1750: gdImageLine(im, cx, cy, fx, fy, color);
! 1751: }
! 1752: }
! 1753: }
! 1754: }
! 1755:
! 1756: void gdImageFillToBorder (gdImagePtr im, int x, int y, int border, int color)
! 1757: {
! 1758: int lastBorder;
! 1759: /* Seek left */
! 1760: int leftLimit = -1, rightLimit;
! 1761: int i, restoreAlphaBlending = 0;
! 1762:
! 1763: if (border < 0) {
! 1764: /* Refuse to fill to a non-solid border */
! 1765: return;
! 1766: }
! 1767:
! 1768: restoreAlphaBlending = im->alphaBlendingFlag;
! 1769: im->alphaBlendingFlag = 0;
! 1770:
! 1771: if (x >= im->sx) {
! 1772: x = im->sx - 1;
! 1773: }
! 1774: if (y >= im->sy) {
! 1775: y = im->sy - 1;
! 1776: }
! 1777:
! 1778: for (i = x; i >= 0; i--) {
! 1779: if (gdImageGetPixel(im, i, y) == border) {
! 1780: break;
! 1781: }
! 1782: gdImageSetPixel(im, i, y, color);
! 1783: leftLimit = i;
! 1784: }
! 1785: if (leftLimit == -1) {
! 1786: im->alphaBlendingFlag = restoreAlphaBlending;
! 1787: return;
! 1788: }
! 1789: /* Seek right */
! 1790: rightLimit = x;
! 1791: for (i = (x + 1); i < im->sx; i++) {
! 1792: if (gdImageGetPixel(im, i, y) == border) {
! 1793: break;
! 1794: }
! 1795: gdImageSetPixel(im, i, y, color);
! 1796: rightLimit = i;
! 1797: }
! 1798: /* Look at lines above and below and start paints */
! 1799: /* Above */
! 1800: if (y > 0) {
! 1801: lastBorder = 1;
! 1802: for (i = leftLimit; i <= rightLimit; i++) {
! 1803: int c = gdImageGetPixel(im, i, y - 1);
! 1804: if (lastBorder) {
! 1805: if ((c != border) && (c != color)) {
! 1806: gdImageFillToBorder(im, i, y - 1, border, color);
! 1807: lastBorder = 0;
! 1808: }
! 1809: } else if ((c == border) || (c == color)) {
! 1810: lastBorder = 1;
! 1811: }
! 1812: }
! 1813: }
! 1814:
! 1815: /* Below */
! 1816: if (y < ((im->sy) - 1)) {
! 1817: lastBorder = 1;
! 1818: for (i = leftLimit; i <= rightLimit; i++) {
! 1819: int c = gdImageGetPixel(im, i, y + 1);
! 1820:
! 1821: if (lastBorder) {
! 1822: if ((c != border) && (c != color)) {
! 1823: gdImageFillToBorder(im, i, y + 1, border, color);
! 1824: lastBorder = 0;
! 1825: }
! 1826: } else if ((c == border) || (c == color)) {
! 1827: lastBorder = 1;
! 1828: }
! 1829: }
! 1830: }
! 1831: im->alphaBlendingFlag = restoreAlphaBlending;
! 1832: }
! 1833:
! 1834: /*
! 1835: * set the pixel at (x,y) and its 4-connected neighbors
! 1836: * with the same pixel value to the new pixel value nc (new color).
! 1837: * A 4-connected neighbor: pixel above, below, left, or right of a pixel.
! 1838: * ideas from comp.graphics discussions.
! 1839: * For tiled fill, the use of a flag buffer is mandatory. As the tile image can
! 1840: * contain the same color as the color to fill. To do not bloat normal filling
! 1841: * code I added a 2nd private function.
! 1842: */
! 1843:
! 1844: /* horizontal segment of scan line y */
! 1845: struct seg {int y, xl, xr, dy;};
! 1846:
! 1847: /* max depth of stack */
! 1848: #define FILL_MAX ((int)(im->sy*im->sx)/4)
! 1849: #define FILL_PUSH(Y, XL, XR, DY) \
! 1850: if (sp<stack+FILL_MAX && Y+(DY)>=0 && Y+(DY)<wy2) \
! 1851: {sp->y = Y; sp->xl = XL; sp->xr = XR; sp->dy = DY; sp++;}
! 1852:
! 1853: #define FILL_POP(Y, XL, XR, DY) \
! 1854: {sp--; Y = sp->y+(DY = sp->dy); XL = sp->xl; XR = sp->xr;}
! 1855:
! 1856: static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc);
! 1857:
! 1858: void gdImageFill(gdImagePtr im, int x, int y, int nc)
! 1859: {
! 1860: int l, x1, x2, dy;
! 1861: int oc; /* old pixel value */
! 1862: int wx2,wy2;
! 1863:
! 1864: int alphablending_bak;
! 1865:
! 1866: /* stack of filled segments */
! 1867: /* struct seg stack[FILL_MAX],*sp = stack;; */
! 1868: struct seg *stack = NULL;
! 1869: struct seg *sp;
! 1870:
! 1871: if (!im->trueColor && nc > (im->colorsTotal -1)) {
! 1872: return;
! 1873: }
! 1874:
! 1875: alphablending_bak = im->alphaBlendingFlag;
! 1876: im->alphaBlendingFlag = 0;
! 1877:
! 1878: if (nc==gdTiled){
! 1879: _gdImageFillTiled(im,x,y,nc);
! 1880: im->alphaBlendingFlag = alphablending_bak;
! 1881: return;
! 1882: }
! 1883:
! 1884: wx2=im->sx;wy2=im->sy;
! 1885: oc = gdImageGetPixel(im, x, y);
! 1886: if (oc==nc || x<0 || x>wx2 || y<0 || y>wy2) {
! 1887: im->alphaBlendingFlag = alphablending_bak;
! 1888: return;
! 1889: }
! 1890:
! 1891: /* Do not use the 4 neighbors implementation with
! 1892: * small images
! 1893: */
! 1894: if (im->sx < 4) {
! 1895: int ix = x, iy = y, c;
! 1896: do {
! 1897: do {
! 1898: c = gdImageGetPixel(im, ix, iy);
! 1899: if (c != oc) {
! 1900: goto done;
! 1901: }
! 1902: gdImageSetPixel(im, ix, iy, nc);
! 1903: } while(ix++ < (im->sx -1));
! 1904: ix = x;
! 1905: } while(iy++ < (im->sy -1));
! 1906: goto done;
! 1907: }
! 1908:
! 1909: stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
! 1910: sp = stack;
! 1911:
! 1912: /* required! */
! 1913: FILL_PUSH(y,x,x,1);
! 1914: /* seed segment (popped 1st) */
! 1915: FILL_PUSH(y+1, x, x, -1);
! 1916: while (sp>stack) {
! 1917: FILL_POP(y, x1, x2, dy);
! 1918:
! 1919: for (x=x1; x>=0 && gdImageGetPixel(im,x, y)==oc; x--) {
! 1920: gdImageSetPixel(im,x, y, nc);
! 1921: }
! 1922: if (x>=x1) {
! 1923: goto skip;
! 1924: }
! 1925: l = x+1;
! 1926:
! 1927: /* leak on left? */
! 1928: if (l<x1) {
! 1929: FILL_PUSH(y, l, x1-1, -dy);
! 1930: }
! 1931: x = x1+1;
! 1932: do {
! 1933: for (; x<=wx2 && gdImageGetPixel(im,x, y)==oc; x++) {
! 1934: gdImageSetPixel(im, x, y, nc);
! 1935: }
! 1936: FILL_PUSH(y, l, x-1, dy);
! 1937: /* leak on right? */
! 1938: if (x>x2+1) {
! 1939: FILL_PUSH(y, x2+1, x-1, -dy);
! 1940: }
! 1941: skip: for (x++; x<=x2 && (gdImageGetPixel(im, x, y)!=oc); x++);
! 1942:
! 1943: l = x;
! 1944: } while (x<=x2);
! 1945: }
! 1946:
! 1947: efree(stack);
! 1948:
! 1949: done:
! 1950: im->alphaBlendingFlag = alphablending_bak;
! 1951: }
! 1952:
! 1953: static void _gdImageFillTiled(gdImagePtr im, int x, int y, int nc)
! 1954: {
! 1955: int i, l, x1, x2, dy;
! 1956: int oc; /* old pixel value */
! 1957: int tiled;
! 1958: int wx2,wy2;
! 1959: /* stack of filled segments */
! 1960: struct seg *stack;
! 1961: struct seg *sp;
! 1962: char **pts;
! 1963:
! 1964: if (!im->tile) {
! 1965: return;
! 1966: }
! 1967:
! 1968: wx2=im->sx;wy2=im->sy;
! 1969: tiled = nc==gdTiled;
! 1970:
! 1971: nc = gdImageTileGet(im,x,y);
! 1972:
! 1973: pts = (char **) ecalloc(im->sy + 1, sizeof(char *));
! 1974: for (i = 0; i < im->sy + 1; i++) {
! 1975: pts[i] = (char *) ecalloc(im->sx + 1, sizeof(char));
! 1976: }
! 1977:
! 1978: stack = (struct seg *)safe_emalloc(sizeof(struct seg), ((int)(im->sy*im->sx)/4), 1);
! 1979: sp = stack;
! 1980:
! 1981: oc = gdImageGetPixel(im, x, y);
! 1982:
! 1983: /* required! */
! 1984: FILL_PUSH(y,x,x,1);
! 1985: /* seed segment (popped 1st) */
! 1986: FILL_PUSH(y+1, x, x, -1);
! 1987: while (sp>stack) {
! 1988: FILL_POP(y, x1, x2, dy);
! 1989: for (x=x1; x>=0 && (!pts[y][x] && gdImageGetPixel(im,x,y)==oc); x--) {
! 1990: nc = gdImageTileGet(im,x,y);
! 1991: pts[y][x] = 1;
! 1992: gdImageSetPixel(im,x, y, nc);
! 1993: }
! 1994: if (x>=x1) {
! 1995: goto skip;
! 1996: }
! 1997: l = x+1;
! 1998:
! 1999: /* leak on left? */
! 2000: if (l<x1) {
! 2001: FILL_PUSH(y, l, x1-1, -dy);
! 2002: }
! 2003: x = x1+1;
! 2004: do {
! 2005: for(; x<wx2 && (!pts[y][x] && gdImageGetPixel(im,x, y)==oc); x++) {
! 2006: nc = gdImageTileGet(im,x,y);
! 2007: pts[y][x] = 1;
! 2008: gdImageSetPixel(im, x, y, nc);
! 2009: }
! 2010: FILL_PUSH(y, l, x-1, dy);
! 2011: /* leak on right? */
! 2012: if (x>x2+1) {
! 2013: FILL_PUSH(y, x2+1, x-1, -dy);
! 2014: }
! 2015: skip: for(x++; x<=x2 && (pts[y][x] || gdImageGetPixel(im,x, y)!=oc); x++);
! 2016: l = x;
! 2017: } while (x<=x2);
! 2018: }
! 2019:
! 2020: for(i = 0; i < im->sy + 1; i++) {
! 2021: efree(pts[i]);
! 2022: }
! 2023:
! 2024: efree(pts);
! 2025: efree(stack);
! 2026: }
! 2027:
! 2028:
! 2029:
! 2030: void gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
! 2031: {
! 2032: int x1h = x1, x1v = x1, y1h = y1, y1v = y1, x2h = x2, x2v = x2, y2h = y2, y2v = y2;
! 2033: int thick = im->thick;
! 2034: int half1 = 1;
! 2035: int t;
! 2036:
! 2037: if (x1 == x2 && y1 == y2 && thick == 1) {
! 2038: gdImageSetPixel(im, x1, y1, color);
! 2039: return;
! 2040: }
! 2041:
! 2042: if (y2 < y1) {
! 2043: t=y1;
! 2044: y1 = y2;
! 2045: y2 = t;
! 2046:
! 2047: t = x1;
! 2048: x1 = x2;
! 2049: x2 = t;
! 2050: }
! 2051:
! 2052: x1h = x1; x1v = x1; y1h = y1; y1v = y1; x2h = x2; x2v = x2; y2h = y2; y2v = y2;
! 2053: if (thick > 1) {
! 2054: int cx, cy, x1ul, y1ul, x2lr, y2lr;
! 2055: int half = thick >> 1;
! 2056: half1 = thick - half;
! 2057: x1ul = x1 - half;
! 2058: y1ul = y1 - half;
! 2059:
! 2060: x2lr = x2 + half;
! 2061: y2lr = y2 + half;
! 2062:
! 2063: cy = y1ul + thick;
! 2064: while (cy-- > y1ul) {
! 2065: cx = x1ul - 1;
! 2066: while (cx++ < x2lr) {
! 2067: gdImageSetPixel(im, cx, cy, color);
! 2068: }
! 2069: }
! 2070:
! 2071: cy = y2lr - thick;
! 2072: while (cy++ < y2lr) {
! 2073: cx = x1ul - 1;
! 2074: while (cx++ < x2lr) {
! 2075: gdImageSetPixel(im, cx, cy, color);
! 2076: }
! 2077: }
! 2078:
! 2079: cy = y1ul + thick - 1;
! 2080: while (cy++ < y2lr -thick) {
! 2081: cx = x1ul - 1;
! 2082: while (cx++ < x1ul + thick) {
! 2083: gdImageSetPixel(im, cx, cy, color);
! 2084: }
! 2085: }
! 2086:
! 2087: cy = y1ul + thick - 1;
! 2088: while (cy++ < y2lr -thick) {
! 2089: cx = x2lr - thick - 1;
! 2090: while (cx++ < x2lr) {
! 2091: gdImageSetPixel(im, cx, cy, color);
! 2092: }
! 2093: }
! 2094:
! 2095: return;
! 2096: } else {
! 2097: y1v = y1h + 1;
! 2098: y2v = y2h - 1;
! 2099: gdImageLine(im, x1h, y1h, x2h, y1h, color);
! 2100: gdImageLine(im, x1h, y2h, x2h, y2h, color);
! 2101: gdImageLine(im, x1v, y1v, x1v, y2v, color);
! 2102: gdImageLine(im, x2v, y1v, x2v, y2v, color);
! 2103: }
! 2104: }
! 2105:
! 2106: void gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, int color)
! 2107: {
! 2108: int x, y;
! 2109:
! 2110:
! 2111: if (x1 == x2 && y1 == y2) {
! 2112: gdImageSetPixel(im, x1, y1, color);
! 2113: return;
! 2114: }
! 2115:
! 2116: if (x1 > x2) {
! 2117: x = x1;
! 2118: x1 = x2;
! 2119: x2 = x;
! 2120: }
! 2121:
! 2122: if (y1 > y2) {
! 2123: y = y1;
! 2124: y1 = y2;
! 2125: y2 = y;
! 2126: }
! 2127:
! 2128: if (x1 < 0) {
! 2129: x1 = 0;
! 2130: }
! 2131:
! 2132: if (x2 >= gdImageSX(im)) {
! 2133: x2 = gdImageSX(im) - 1;
! 2134: }
! 2135:
! 2136: if (y1 < 0) {
! 2137: y1 = 0;
! 2138: }
! 2139:
! 2140: if (y2 >= gdImageSY(im)) {
! 2141: y2 = gdImageSY(im) - 1;
! 2142: }
! 2143:
! 2144: for (y = y1; (y <= y2); y++) {
! 2145: for (x = x1; (x <= x2); x++) {
! 2146: gdImageSetPixel (im, x, y, color);
! 2147: }
! 2148: }
! 2149: }
! 2150:
! 2151: void gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h)
! 2152: {
! 2153: int c;
! 2154: int x, y;
! 2155: int tox, toy;
! 2156: int i;
! 2157: int colorMap[gdMaxColors];
! 2158:
! 2159: if (dst->trueColor) {
! 2160: /* 2.0: much easier when the destination is truecolor. */
! 2161: /* 2.0.10: needs a transparent-index check that is still valid if
! 2162: * the source is not truecolor. Thanks to Frank Warmerdam.
! 2163: */
! 2164:
! 2165: if (src->trueColor) {
! 2166: for (y = 0; (y < h); y++) {
! 2167: for (x = 0; (x < w); x++) {
! 2168: int c = gdImageGetTrueColorPixel (src, srcX + x, srcY + y);
! 2169: gdImageSetPixel (dst, dstX + x, dstY + y, c);
! 2170: }
! 2171: }
! 2172: } else {
! 2173: /* source is palette based */
! 2174: for (y = 0; (y < h); y++) {
! 2175: for (x = 0; (x < w); x++) {
! 2176: int c = gdImageGetPixel (src, srcX + x, srcY + y);
! 2177: if (c != src->transparent) {
! 2178: gdImageSetPixel(dst, dstX + x, dstY + y, gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]));
! 2179: }
! 2180: }
! 2181: }
! 2182: }
! 2183: return;
! 2184: }
! 2185:
! 2186: /* Destination is palette based */
! 2187: if (src->trueColor) { /* But source is truecolor (Ouch!) */
! 2188: toy = dstY;
! 2189: for (y = srcY; (y < (srcY + h)); y++) {
! 2190: tox = dstX;
! 2191: for (x = srcX; x < (srcX + w); x++) {
! 2192: int nc;
! 2193: c = gdImageGetPixel (src, x, y);
! 2194:
! 2195: /* Get best match possible. */
! 2196: nc = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c), gdTrueColorGetAlpha(c));
! 2197:
! 2198: gdImageSetPixel(dst, tox, toy, nc);
! 2199: tox++;
! 2200: }
! 2201: toy++;
! 2202: }
! 2203: return;
! 2204: }
! 2205:
! 2206: /* Palette based to palette based */
! 2207: for (i = 0; i < gdMaxColors; i++) {
! 2208: colorMap[i] = (-1);
! 2209: }
! 2210: toy = dstY;
! 2211: for (y = srcY; y < (srcY + h); y++) {
! 2212: tox = dstX;
! 2213: for (x = srcX; x < (srcX + w); x++) {
! 2214: int nc;
! 2215: int mapTo;
! 2216: c = gdImageGetPixel (src, x, y);
! 2217: /* Added 7/24/95: support transparent copies */
! 2218: if (gdImageGetTransparent (src) == c) {
! 2219: tox++;
! 2220: continue;
! 2221: }
! 2222: /* Have we established a mapping for this color? */
! 2223: if (src->trueColor) {
! 2224: /* 2.05: remap to the palette available in the destination image. This is slow and
! 2225: * works badly, but it beats crashing! Thanks to Padhrig McCarthy.
! 2226: */
! 2227: mapTo = gdImageColorResolveAlpha (dst, gdTrueColorGetRed (c), gdTrueColorGetGreen (c), gdTrueColorGetBlue (c), gdTrueColorGetAlpha (c));
! 2228: } else if (colorMap[c] == (-1)) {
! 2229: /* If it's the same image, mapping is trivial */
! 2230: if (dst == src) {
! 2231: nc = c;
! 2232: } else {
! 2233: /* Get best match possible. This function never returns error. */
! 2234: nc = gdImageColorResolveAlpha (dst, src->red[c], src->green[c], src->blue[c], src->alpha[c]);
! 2235: }
! 2236: colorMap[c] = nc;
! 2237: mapTo = colorMap[c];
! 2238: } else {
! 2239: mapTo = colorMap[c];
! 2240: }
! 2241: gdImageSetPixel (dst, tox, toy, mapTo);
! 2242: tox++;
! 2243: }
! 2244: toy++;
! 2245: }
! 2246: }
! 2247:
! 2248: /* This function is a substitute for real alpha channel operations,
! 2249: so it doesn't pay attention to the alpha channel. */
! 2250: void gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
! 2251: {
! 2252: int c, dc;
! 2253: int x, y;
! 2254: int tox, toy;
! 2255: int ncR, ncG, ncB;
! 2256: toy = dstY;
! 2257:
! 2258: for (y = srcY; y < (srcY + h); y++) {
! 2259: tox = dstX;
! 2260: for (x = srcX; x < (srcX + w); x++) {
! 2261: int nc;
! 2262: c = gdImageGetPixel(src, x, y);
! 2263: /* Added 7/24/95: support transparent copies */
! 2264: if (gdImageGetTransparent(src) == c) {
! 2265: tox++;
! 2266: continue;
! 2267: }
! 2268: /* If it's the same image, mapping is trivial */
! 2269: if (dst == src) {
! 2270: nc = c;
! 2271: } else {
! 2272: dc = gdImageGetPixel(dst, tox, toy);
! 2273:
! 2274: ncR = (int)(gdImageRed (src, c) * (pct / 100.0) + gdImageRed (dst, dc) * ((100 - pct) / 100.0));
! 2275: ncG = (int)(gdImageGreen (src, c) * (pct / 100.0) + gdImageGreen (dst, dc) * ((100 - pct) / 100.0));
! 2276: ncB = (int)(gdImageBlue (src, c) * (pct / 100.0) + gdImageBlue (dst, dc) * ((100 - pct) / 100.0));
! 2277:
! 2278: /* Find a reasonable color */
! 2279: nc = gdImageColorResolve (dst, ncR, ncG, ncB);
! 2280: }
! 2281: gdImageSetPixel (dst, tox, toy, nc);
! 2282: tox++;
! 2283: }
! 2284: toy++;
! 2285: }
! 2286: }
! 2287:
! 2288: /* This function is a substitute for real alpha channel operations,
! 2289: so it doesn't pay attention to the alpha channel. */
! 2290: void gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct)
! 2291: {
! 2292: int c, dc;
! 2293: int x, y;
! 2294: int tox, toy;
! 2295: int ncR, ncG, ncB;
! 2296: float g;
! 2297: toy = dstY;
! 2298:
! 2299: for (y = srcY; (y < (srcY + h)); y++) {
! 2300: tox = dstX;
! 2301: for (x = srcX; (x < (srcX + w)); x++) {
! 2302: int nc;
! 2303: c = gdImageGetPixel (src, x, y);
! 2304: /* Added 7/24/95: support transparent copies */
! 2305: if (gdImageGetTransparent(src) == c) {
! 2306: tox++;
! 2307: continue;
! 2308: }
! 2309:
! 2310: /*
! 2311: * If it's the same image, mapping is NOT trivial since we
! 2312: * merge with greyscale target, but if pct is 100, the grey
! 2313: * value is not used, so it becomes trivial. pjw 2.0.12.
! 2314: */
! 2315: if (dst == src && pct == 100) {
! 2316: nc = c;
! 2317: } else {
! 2318: dc = gdImageGetPixel(dst, tox, toy);
! 2319: g = (0.29900f * gdImageRed(dst, dc)) + (0.58700f * gdImageGreen(dst, dc)) + (0.11400f * gdImageBlue(dst, dc));
! 2320:
! 2321: ncR = (int)(gdImageRed (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
! 2322: ncG = (int)(gdImageGreen (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
! 2323: ncB = (int)(gdImageBlue (src, c) * (pct / 100.0f) + g * ((100 - pct) / 100.0));
! 2324:
! 2325:
! 2326: /* First look for an exact match */
! 2327: nc = gdImageColorExact(dst, ncR, ncG, ncB);
! 2328: if (nc == (-1)) {
! 2329: /* No, so try to allocate it */
! 2330: nc = gdImageColorAllocate(dst, ncR, ncG, ncB);
! 2331: /* If we're out of colors, go for the closest color */
! 2332: if (nc == (-1)) {
! 2333: nc = gdImageColorClosest(dst, ncR, ncG, ncB);
! 2334: }
! 2335: }
! 2336: }
! 2337: gdImageSetPixel(dst, tox, toy, nc);
! 2338: tox++;
! 2339: }
! 2340: toy++;
! 2341: }
! 2342: }
! 2343:
! 2344: void gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
! 2345: {
! 2346: int c;
! 2347: int x, y;
! 2348: int tox, toy;
! 2349: int ydest;
! 2350: int i;
! 2351: int colorMap[gdMaxColors];
! 2352: /* Stretch vectors */
! 2353: int *stx, *sty;
! 2354: /* We only need to use floating point to determine the correct stretch vector for one line's worth. */
! 2355: double accum;
! 2356:
! 2357: if (overflow2(sizeof(int), srcW)) {
! 2358: return;
! 2359: }
! 2360: if (overflow2(sizeof(int), srcH)) {
! 2361: return;
! 2362: }
! 2363:
! 2364: stx = (int *) gdMalloc (sizeof (int) * srcW);
! 2365: sty = (int *) gdMalloc (sizeof (int) * srcH);
! 2366: accum = 0;
! 2367:
! 2368: /* Fixed by Mao Morimoto 2.0.16 */
! 2369: for (i = 0; (i < srcW); i++) {
! 2370: stx[i] = dstW * (i+1) / srcW - dstW * i / srcW ;
! 2371: }
! 2372: for (i = 0; (i < srcH); i++) {
! 2373: sty[i] = dstH * (i+1) / srcH - dstH * i / srcH ;
! 2374: }
! 2375: for (i = 0; (i < gdMaxColors); i++) {
! 2376: colorMap[i] = (-1);
! 2377: }
! 2378: toy = dstY;
! 2379: for (y = srcY; (y < (srcY + srcH)); y++) {
! 2380: for (ydest = 0; (ydest < sty[y - srcY]); ydest++) {
! 2381: tox = dstX;
! 2382: for (x = srcX; (x < (srcX + srcW)); x++) {
! 2383: int nc = 0;
! 2384: int mapTo;
! 2385: if (!stx[x - srcX]) {
! 2386: continue;
! 2387: }
! 2388: if (dst->trueColor) {
! 2389: /* 2.0.9: Thorben Kundinger: Maybe the source image is not a truecolor image */
! 2390: if (!src->trueColor) {
! 2391: int tmp = gdImageGetPixel (src, x, y);
! 2392: mapTo = gdImageGetTrueColorPixel (src, x, y);
! 2393: if (gdImageGetTransparent (src) == tmp) {
! 2394: /* 2.0.21, TK: not tox++ */
! 2395: tox += stx[x - srcX];
! 2396: continue;
! 2397: }
! 2398: } else {
! 2399: /* TK: old code follows */
! 2400: mapTo = gdImageGetTrueColorPixel (src, x, y);
! 2401: /* Added 7/24/95: support transparent copies */
! 2402: if (gdImageGetTransparent (src) == mapTo) {
! 2403: /* 2.0.21, TK: not tox++ */
! 2404: tox += stx[x - srcX];
! 2405: continue;
! 2406: }
! 2407: }
! 2408: } else {
! 2409: c = gdImageGetPixel (src, x, y);
! 2410: /* Added 7/24/95: support transparent copies */
! 2411: if (gdImageGetTransparent (src) == c) {
! 2412: tox += stx[x - srcX];
! 2413: continue;
! 2414: }
! 2415: if (src->trueColor) {
! 2416: /* Remap to the palette available in the destination image. This is slow and works badly. */
! 2417: mapTo = gdImageColorResolveAlpha(dst, gdTrueColorGetRed(c),
! 2418: gdTrueColorGetGreen(c),
! 2419: gdTrueColorGetBlue(c),
! 2420: gdTrueColorGetAlpha (c));
! 2421: } else {
! 2422: /* Have we established a mapping for this color? */
! 2423: if (colorMap[c] == (-1)) {
! 2424: /* If it's the same image, mapping is trivial */
! 2425: if (dst == src) {
! 2426: nc = c;
! 2427: } else {
! 2428: /* Find or create the best match */
! 2429: /* 2.0.5: can't use gdTrueColorGetRed, etc with palette */
! 2430: nc = gdImageColorResolveAlpha(dst, gdImageRed(src, c),
! 2431: gdImageGreen(src, c),
! 2432: gdImageBlue(src, c),
! 2433: gdImageAlpha(src, c));
! 2434: }
! 2435: colorMap[c] = nc;
! 2436: }
! 2437: mapTo = colorMap[c];
! 2438: }
! 2439: }
! 2440: for (i = 0; (i < stx[x - srcX]); i++) {
! 2441: gdImageSetPixel (dst, tox, toy, mapTo);
! 2442: tox++;
! 2443: }
! 2444: }
! 2445: toy++;
! 2446: }
! 2447: }
! 2448: gdFree (stx);
! 2449: gdFree (sty);
! 2450: }
! 2451:
! 2452: /* When gd 1.x was first created, floating point was to be avoided.
! 2453: These days it is often faster than table lookups or integer
! 2454: arithmetic. The routine below is shamelessly, gloriously
! 2455: floating point. TBB */
! 2456:
! 2457: void gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH)
! 2458: {
! 2459: int x, y;
! 2460: double sy1, sy2, sx1, sx2;
! 2461:
! 2462: if (!dst->trueColor) {
! 2463: gdImageCopyResized (dst, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH);
! 2464: return;
! 2465: }
! 2466: for (y = dstY; (y < dstY + dstH); y++) {
! 2467: sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH;
! 2468: sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / (double) dstH;
! 2469: for (x = dstX; (x < dstX + dstW); x++) {
! 2470: double sx, sy;
! 2471: double spixels = 0;
! 2472: double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
! 2473: double alpha_factor, alpha_sum = 0.0, contrib_sum = 0.0;
! 2474: sx1 = ((double) x - (double) dstX) * (double) srcW / dstW;
! 2475: sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW;
! 2476: sy = sy1;
! 2477: do {
! 2478: double yportion;
! 2479: if (floor_cast(sy) == floor_cast(sy1)) {
! 2480: yportion = 1.0f - (sy - floor_cast(sy));
! 2481: if (yportion > sy2 - sy1) {
! 2482: yportion = sy2 - sy1;
! 2483: }
! 2484: sy = floor_cast(sy);
! 2485: } else if (sy == floorf(sy2)) {
! 2486: yportion = sy2 - floor_cast(sy2);
! 2487: } else {
! 2488: yportion = 1.0f;
! 2489: }
! 2490: sx = sx1;
! 2491: do {
! 2492: double xportion;
! 2493: double pcontribution;
! 2494: int p;
! 2495: if (floorf(sx) == floor_cast(sx1)) {
! 2496: xportion = 1.0f - (sx - floor_cast(sx));
! 2497: if (xportion > sx2 - sx1) {
! 2498: xportion = sx2 - sx1;
! 2499: }
! 2500: sx = floor_cast(sx);
! 2501: } else if (sx == floorf(sx2)) {
! 2502: xportion = sx2 - floor_cast(sx2);
! 2503: } else {
! 2504: xportion = 1.0f;
! 2505: }
! 2506: pcontribution = xportion * yportion;
! 2507: p = gdImageGetTrueColorPixel(src, (int) sx + srcX, (int) sy + srcY);
! 2508:
! 2509: alpha_factor = ((gdAlphaMax - gdTrueColorGetAlpha(p))) * pcontribution;
! 2510: red += gdTrueColorGetRed (p) * alpha_factor;
! 2511: green += gdTrueColorGetGreen (p) * alpha_factor;
! 2512: blue += gdTrueColorGetBlue (p) * alpha_factor;
! 2513: alpha += gdTrueColorGetAlpha (p) * pcontribution;
! 2514: alpha_sum += alpha_factor;
! 2515: contrib_sum += pcontribution;
! 2516: spixels += xportion * yportion;
! 2517: sx += 1.0f;
! 2518: }
! 2519: while (sx < sx2);
! 2520:
! 2521: sy += 1.0f;
! 2522: }
! 2523:
! 2524: while (sy < sy2);
! 2525:
! 2526: if (spixels != 0.0f) {
! 2527: red /= spixels;
! 2528: green /= spixels;
! 2529: blue /= spixels;
! 2530: alpha /= spixels;
! 2531: alpha += 0.5;
! 2532: }
! 2533: if ( alpha_sum != 0.0f) {
! 2534: if( contrib_sum != 0.0f) {
! 2535: alpha_sum /= contrib_sum;
! 2536: }
! 2537: red /= alpha_sum;
! 2538: green /= alpha_sum;
! 2539: blue /= alpha_sum;
! 2540: }
! 2541: /* Clamping to allow for rounding errors above */
! 2542: if (red > 255.0f) {
! 2543: red = 255.0f;
! 2544: }
! 2545: if (green > 255.0f) {
! 2546: green = 255.0f;
! 2547: }
! 2548: if (blue > 255.0f) {
! 2549: blue = 255.0f;
! 2550: }
! 2551: if (alpha > gdAlphaMax) {
! 2552: alpha = gdAlphaMax;
! 2553: }
! 2554: gdImageSetPixel(dst, x, y, gdTrueColorAlpha ((int) red, (int) green, (int) blue, (int) alpha));
! 2555: }
! 2556: }
! 2557: }
! 2558:
! 2559: void gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c)
! 2560: {
! 2561: int i;
! 2562: int lx, ly;
! 2563: typedef void (*image_line)(gdImagePtr im, int x1, int y1, int x2, int y2, int color);
! 2564: image_line draw_line;
! 2565:
! 2566: if (n <= 0) {
! 2567: return;
! 2568: }
! 2569:
! 2570: /* Let it be known that we are drawing a polygon so that the opacity
! 2571: * mask doesn't get cleared after each line.
! 2572: */
! 2573: if (c == gdAntiAliased) {
! 2574: im->AA_polygon = 1;
! 2575: }
! 2576:
! 2577: if ( im->antialias) {
! 2578: draw_line = gdImageAALine;
! 2579: } else {
! 2580: draw_line = gdImageLine;
! 2581: }
! 2582: lx = p->x;
! 2583: ly = p->y;
! 2584: draw_line(im, lx, ly, p[n - 1].x, p[n - 1].y, c);
! 2585: for (i = 1; i < n; i++) {
! 2586: p++;
! 2587: draw_line(im, lx, ly, p->x, p->y, c);
! 2588: lx = p->x;
! 2589: ly = p->y;
! 2590: }
! 2591:
! 2592: if (c == gdAntiAliased) {
! 2593: im->AA_polygon = 0;
! 2594: gdImageAABlend(im);
! 2595: }
! 2596: }
! 2597:
! 2598: int gdCompareInt (const void *a, const void *b);
! 2599:
! 2600: /* THANKS to Kirsten Schulz for the polygon fixes! */
! 2601:
! 2602: /* The intersection finding technique of this code could be improved
! 2603: * by remembering the previous intertersection, and by using the slope.
! 2604: * That could help to adjust intersections to produce a nice
! 2605: * interior_extrema.
! 2606: */
! 2607:
! 2608: void gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c)
! 2609: {
! 2610: int i;
! 2611: int y;
! 2612: int miny, maxy, pmaxy;
! 2613: int x1, y1;
! 2614: int x2, y2;
! 2615: int ind1, ind2;
! 2616: int ints;
! 2617: int fill_color;
! 2618:
! 2619: if (n <= 0) {
! 2620: return;
! 2621: }
! 2622:
! 2623: if (overflow2(sizeof(int), n)) {
! 2624: return;
! 2625: }
! 2626:
! 2627: if (c == gdAntiAliased) {
! 2628: fill_color = im->AA_color;
! 2629: } else {
! 2630: fill_color = c;
! 2631: }
! 2632:
! 2633: if (!im->polyAllocated) {
! 2634: im->polyInts = (int *) gdMalloc(sizeof(int) * n);
! 2635: im->polyAllocated = n;
! 2636: }
! 2637: if (im->polyAllocated < n) {
! 2638: while (im->polyAllocated < n) {
! 2639: im->polyAllocated *= 2;
! 2640: }
! 2641: if (overflow2(sizeof(int), im->polyAllocated)) {
! 2642: return;
! 2643: }
! 2644: im->polyInts = (int *) gdRealloc(im->polyInts, sizeof(int) * im->polyAllocated);
! 2645: }
! 2646: miny = p[0].y;
! 2647: maxy = p[0].y;
! 2648: for (i = 1; i < n; i++) {
! 2649: if (p[i].y < miny) {
! 2650: miny = p[i].y;
! 2651: }
! 2652: if (p[i].y > maxy) {
! 2653: maxy = p[i].y;
! 2654: }
! 2655: }
! 2656: pmaxy = maxy;
! 2657: /* 2.0.16: Optimization by Ilia Chipitsine -- don't waste time offscreen */
! 2658: if (miny < 0) {
! 2659: miny = 0;
! 2660: }
! 2661: if (maxy >= gdImageSY(im)) {
! 2662: maxy = gdImageSY(im) - 1;
! 2663: }
! 2664:
! 2665: /* Fix in 1.3: count a vertex only once */
! 2666: for (y = miny; y <= maxy; y++) {
! 2667: /*1.4 int interLast = 0; */
! 2668: /* int dirLast = 0; */
! 2669: /* int interFirst = 1; */
! 2670: ints = 0;
! 2671: for (i = 0; i < n; i++) {
! 2672: if (!i) {
! 2673: ind1 = n - 1;
! 2674: ind2 = 0;
! 2675: } else {
! 2676: ind1 = i - 1;
! 2677: ind2 = i;
! 2678: }
! 2679: y1 = p[ind1].y;
! 2680: y2 = p[ind2].y;
! 2681: if (y1 < y2) {
! 2682: x1 = p[ind1].x;
! 2683: x2 = p[ind2].x;
! 2684: } else if (y1 > y2) {
! 2685: y2 = p[ind1].y;
! 2686: y1 = p[ind2].y;
! 2687: x2 = p[ind1].x;
! 2688: x1 = p[ind2].x;
! 2689: } else {
! 2690: continue;
! 2691: }
! 2692: /* Do the following math as float intermediately, and round to ensure
! 2693: * that Polygon and FilledPolygon for the same set of points have the
! 2694: * same footprint.
! 2695: */
! 2696: if (y >= y1 && y < y2) {
! 2697: im->polyInts[ints++] = (float) ((y - y1) * (x2 - x1)) / (float) (y2 - y1) + 0.5 + x1;
! 2698: } else if (y == pmaxy && y == y2) {
! 2699: im->polyInts[ints++] = x2;
! 2700: }
! 2701: }
! 2702: qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
! 2703:
! 2704: for (i = 0; i < ints - 1; i += 2) {
! 2705: gdImageLine(im, im->polyInts[i], y, im->polyInts[i + 1], y, fill_color);
! 2706: }
! 2707: }
! 2708:
! 2709: /* If we are drawing this AA, then redraw the border with AA lines. */
! 2710: if (c == gdAntiAliased) {
! 2711: gdImagePolygon(im, p, n, c);
! 2712: }
! 2713: }
! 2714:
! 2715: int gdCompareInt (const void *a, const void *b)
! 2716: {
! 2717: return (*(const int *) a) - (*(const int *) b);
! 2718: }
! 2719:
! 2720: void gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels)
! 2721: {
! 2722: if (im->style) {
! 2723: gdFree(im->style);
! 2724: }
! 2725: im->style = (int *) gdMalloc(sizeof(int) * noOfPixels);
! 2726: memcpy(im->style, style, sizeof(int) * noOfPixels);
! 2727: im->styleLength = noOfPixels;
! 2728: im->stylePos = 0;
! 2729: }
! 2730:
! 2731: void gdImageSetThickness (gdImagePtr im, int thickness)
! 2732: {
! 2733: im->thick = thickness;
! 2734: }
! 2735:
! 2736: void gdImageSetBrush (gdImagePtr im, gdImagePtr brush)
! 2737: {
! 2738: int i;
! 2739: im->brush = brush;
! 2740: if (!im->trueColor && !im->brush->trueColor) {
! 2741: for (i = 0; i < gdImageColorsTotal(brush); i++) {
! 2742: int index;
! 2743: index = gdImageColorResolveAlpha(im, gdImageRed(brush, i), gdImageGreen(brush, i), gdImageBlue(brush, i), gdImageAlpha(brush, i));
! 2744: im->brushColorMap[i] = index;
! 2745: }
! 2746: }
! 2747: }
! 2748:
! 2749: void gdImageSetTile (gdImagePtr im, gdImagePtr tile)
! 2750: {
! 2751: int i;
! 2752: im->tile = tile;
! 2753: if (!im->trueColor && !im->tile->trueColor) {
! 2754: for (i = 0; i < gdImageColorsTotal(tile); i++) {
! 2755: int index;
! 2756: index = gdImageColorResolveAlpha(im, gdImageRed(tile, i), gdImageGreen(tile, i), gdImageBlue(tile, i), gdImageAlpha(tile, i));
! 2757: im->tileColorMap[i] = index;
! 2758: }
! 2759: }
! 2760: }
! 2761:
! 2762: void gdImageSetAntiAliased (gdImagePtr im, int c)
! 2763: {
! 2764: im->AA = 1;
! 2765: im->AA_color = c;
! 2766: im->AA_dont_blend = -1;
! 2767: }
! 2768:
! 2769: void gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend)
! 2770: {
! 2771: im->AA = 1;
! 2772: im->AA_color = c;
! 2773: im->AA_dont_blend = dont_blend;
! 2774: }
! 2775:
! 2776:
! 2777: void gdImageInterlace (gdImagePtr im, int interlaceArg)
! 2778: {
! 2779: im->interlace = interlaceArg;
! 2780: }
! 2781:
! 2782: int gdImageCompare (gdImagePtr im1, gdImagePtr im2)
! 2783: {
! 2784: int x, y;
! 2785: int p1, p2;
! 2786: int cmpStatus = 0;
! 2787: int sx, sy;
! 2788:
! 2789: if (im1->interlace != im2->interlace) {
! 2790: cmpStatus |= GD_CMP_INTERLACE;
! 2791: }
! 2792:
! 2793: if (im1->transparent != im2->transparent) {
! 2794: cmpStatus |= GD_CMP_TRANSPARENT;
! 2795: }
! 2796:
! 2797: if (im1->trueColor != im2->trueColor) {
! 2798: cmpStatus |= GD_CMP_TRUECOLOR;
! 2799: }
! 2800:
! 2801: sx = im1->sx;
! 2802: if (im1->sx != im2->sx) {
! 2803: cmpStatus |= GD_CMP_SIZE_X + GD_CMP_IMAGE;
! 2804: if (im2->sx < im1->sx) {
! 2805: sx = im2->sx;
! 2806: }
! 2807: }
! 2808:
! 2809: sy = im1->sy;
! 2810: if (im1->sy != im2->sy) {
! 2811: cmpStatus |= GD_CMP_SIZE_Y + GD_CMP_IMAGE;
! 2812: if (im2->sy < im1->sy) {
! 2813: sy = im2->sy;
! 2814: }
! 2815: }
! 2816:
! 2817: if (im1->colorsTotal != im2->colorsTotal) {
! 2818: cmpStatus |= GD_CMP_NUM_COLORS;
! 2819: }
! 2820:
! 2821: for (y = 0; y < sy; y++) {
! 2822: for (x = 0; x < sx; x++) {
! 2823: p1 = im1->trueColor ? gdImageTrueColorPixel(im1, x, y) : gdImagePalettePixel(im1, x, y);
! 2824: p2 = im2->trueColor ? gdImageTrueColorPixel(im2, x, y) : gdImagePalettePixel(im2, x, y);
! 2825:
! 2826: if (gdImageRed(im1, p1) != gdImageRed(im2, p2)) {
! 2827: cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
! 2828: break;
! 2829: }
! 2830: if (gdImageGreen(im1, p1) != gdImageGreen(im2, p2)) {
! 2831: cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
! 2832: break;
! 2833: }
! 2834: if (gdImageBlue(im1, p1) != gdImageBlue(im2, p2)) {
! 2835: cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
! 2836: break;
! 2837: }
! 2838: #if 0
! 2839: /* Soon we'll add alpha channel to palettes */
! 2840: if (gdImageAlpha(im1, p1) != gdImageAlpha(im2, p2)) {
! 2841: cmpStatus |= GD_CMP_COLOR + GD_CMP_IMAGE;
! 2842: break;
! 2843: }
! 2844: #endif
! 2845: }
! 2846: if (cmpStatus & GD_CMP_COLOR) {
! 2847: break;
! 2848: }
! 2849: }
! 2850:
! 2851: return cmpStatus;
! 2852: }
! 2853:
! 2854: int
! 2855: gdAlphaBlendOld (int dst, int src)
! 2856: {
! 2857: /* 2.0.12: TBB: alpha in the destination should be a
! 2858: * component of the result. Thanks to Frank Warmerdam for
! 2859: * pointing out the issue.
! 2860: */
! 2861: return ((((gdTrueColorGetAlpha (src) *
! 2862: gdTrueColorGetAlpha (dst)) / gdAlphaMax) << 24) +
! 2863: ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
! 2864: gdTrueColorGetRed (src) / gdAlphaMax) +
! 2865: (gdTrueColorGetAlpha (src) *
! 2866: gdTrueColorGetRed (dst)) / gdAlphaMax) << 16) +
! 2867: ((((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
! 2868: gdTrueColorGetGreen (src) / gdAlphaMax) +
! 2869: (gdTrueColorGetAlpha (src) *
! 2870: gdTrueColorGetGreen (dst)) / gdAlphaMax) << 8) +
! 2871: (((gdAlphaTransparent - gdTrueColorGetAlpha (src)) *
! 2872: gdTrueColorGetBlue (src) / gdAlphaMax) +
! 2873: (gdTrueColorGetAlpha (src) *
! 2874: gdTrueColorGetBlue (dst)) / gdAlphaMax));
! 2875: }
! 2876:
! 2877: int gdAlphaBlend (int dst, int src) {
! 2878: int src_alpha = gdTrueColorGetAlpha(src);
! 2879: int dst_alpha, alpha, red, green, blue;
! 2880: int src_weight, dst_weight, tot_weight;
! 2881:
! 2882: /* -------------------------------------------------------------------- */
! 2883: /* Simple cases we want to handle fast. */
! 2884: /* -------------------------------------------------------------------- */
! 2885: if( src_alpha == gdAlphaOpaque )
! 2886: return src;
! 2887:
! 2888: dst_alpha = gdTrueColorGetAlpha(dst);
! 2889: if( src_alpha == gdAlphaTransparent )
! 2890: return dst;
! 2891: if( dst_alpha == gdAlphaTransparent )
! 2892: return src;
! 2893:
! 2894: /* -------------------------------------------------------------------- */
! 2895: /* What will the source and destination alphas be? Note that */
! 2896: /* the destination weighting is substantially reduced as the */
! 2897: /* overlay becomes quite opaque. */
! 2898: /* -------------------------------------------------------------------- */
! 2899: src_weight = gdAlphaTransparent - src_alpha;
! 2900: dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
! 2901: tot_weight = src_weight + dst_weight;
! 2902:
! 2903: /* -------------------------------------------------------------------- */
! 2904: /* What red, green and blue result values will we use? */
! 2905: /* -------------------------------------------------------------------- */
! 2906: alpha = src_alpha * dst_alpha / gdAlphaMax;
! 2907:
! 2908: red = (gdTrueColorGetRed(src) * src_weight
! 2909: + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
! 2910: green = (gdTrueColorGetGreen(src) * src_weight
! 2911: + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
! 2912: blue = (gdTrueColorGetBlue(src) * src_weight
! 2913: + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
! 2914:
! 2915: /* -------------------------------------------------------------------- */
! 2916: /* Return merged result. */
! 2917: /* -------------------------------------------------------------------- */
! 2918: return ((alpha << 24) + (red << 16) + (green << 8) + blue);
! 2919:
! 2920: }
! 2921:
! 2922: void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
! 2923: {
! 2924: im->alphaBlendingFlag = alphaBlendingArg;
! 2925: }
! 2926:
! 2927: void gdImageAntialias (gdImagePtr im, int antialias)
! 2928: {
! 2929: if (im->trueColor){
! 2930: im->antialias = antialias;
! 2931: }
! 2932: }
! 2933:
! 2934: void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
! 2935: {
! 2936: im->saveAlphaFlag = saveAlphaArg;
! 2937: }
! 2938:
! 2939: static int gdLayerOverlay (int dst, int src)
! 2940: {
! 2941: int a1, a2;
! 2942: a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
! 2943: a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
! 2944: return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
! 2945: (gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
! 2946: (gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
! 2947: (gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
! 2948: );
! 2949: }
! 2950:
! 2951: static int gdAlphaOverlayColor (int src, int dst, int max )
! 2952: {
! 2953: /* this function implements the algorithm
! 2954: *
! 2955: * for dst[rgb] < 0.5,
! 2956: * c[rgb] = 2.src[rgb].dst[rgb]
! 2957: * and for dst[rgb] > 0.5,
! 2958: * c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
! 2959: *
! 2960: */
! 2961:
! 2962: dst = dst << 1;
! 2963: if( dst > max ) {
! 2964: /* in the "light" zone */
! 2965: return dst + (src << 1) - (dst * src / max) - max;
! 2966: } else {
! 2967: /* in the "dark" zone */
! 2968: return dst * src / max;
! 2969: }
! 2970: }
! 2971:
! 2972: void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
! 2973: {
! 2974: if (x1 < 0) {
! 2975: x1 = 0;
! 2976: }
! 2977: if (x1 >= im->sx) {
! 2978: x1 = im->sx - 1;
! 2979: }
! 2980: if (x2 < 0) {
! 2981: x2 = 0;
! 2982: }
! 2983: if (x2 >= im->sx) {
! 2984: x2 = im->sx - 1;
! 2985: }
! 2986: if (y1 < 0) {
! 2987: y1 = 0;
! 2988: }
! 2989: if (y1 >= im->sy) {
! 2990: y1 = im->sy - 1;
! 2991: }
! 2992: if (y2 < 0) {
! 2993: y2 = 0;
! 2994: }
! 2995: if (y2 >= im->sy) {
! 2996: y2 = im->sy - 1;
! 2997: }
! 2998: im->cx1 = x1;
! 2999: im->cy1 = y1;
! 3000: im->cx2 = x2;
! 3001: im->cy2 = y2;
! 3002: }
! 3003:
! 3004: void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
! 3005: {
! 3006: *x1P = im->cx1;
! 3007: *y1P = im->cy1;
! 3008: *x2P = im->cx2;
! 3009: *y2P = im->cy2;
! 3010: }
! 3011:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>