📄 gd.c
字号:
{ /* No room for more colors */ return ct; /* Return closest available color */ } im->colorsTotal++; } im->red[op] = r; im->green[op] = g; im->blue[op] = b; im->alpha[op] = a; im->open[op] = 0; return op; /* Return newly allocated color */}void gdImageColorDeallocate (gdImagePtr im, int color){ if (im->trueColor) { return; } /* Mark it open. */ im->open[color] = 1;}void gdImageColorTransparent (gdImagePtr im, int color){ if (!im->trueColor) { if (im->transparent != -1) { im->alpha[im->transparent] = gdAlphaOpaque; } if (color > -1 && color<im->colorsTotal && color<=gdMaxColors) { im->alpha[color] = gdAlphaTransparent; } else { return; } } im->transparent = color;}void gdImagePaletteCopy (gdImagePtr to, gdImagePtr from){ int i; int x, y, p; int xlate[256]; if (to->trueColor || from->trueColor) { return; } for (i = 0; i < 256; i++) { xlate[i] = -1; } for (x = 0; x < to->sx; x++) { for (y = 0; y < to->sy; y++) { p = gdImageGetPixel(to, x, y); if (xlate[p] == -1) { /* This ought to use HWB, but we don't have an alpha-aware version of that yet. */ xlate[p] = gdImageColorClosestAlpha (from, to->red[p], to->green[p], to->blue[p], to->alpha[p]); } gdImageSetPixel(to, x, y, xlate[p]); } } for (i = 0; i < from->colorsTotal; i++) { to->red[i] = from->red[i]; to->blue[i] = from->blue[i]; to->green[i] = from->green[i]; to->alpha[i] = from->alpha[i]; to->open[i] = 0; } for (i = from->colorsTotal; i < to->colorsTotal; i++) { to->open[i] = 1; } to->colorsTotal = from->colorsTotal;}/* 2.0.10: before the drawing routines, some code to clip points that are * outside the drawing window. Nick Atty (nick@canalplan.org.uk) * * This is the Sutherland Hodgman Algorithm, as implemented by * Duvanenko, Robbins and Gyurcsik - SH(DRG) for short. See Dr Dobb's * Journal, January 1996, pp107-110 and 116-117 * * Given the end points of a line, and a bounding rectangle (which we * know to be from (0,0) to (SX,SY)), adjust the endpoints to be on * the edges of the rectangle if the line should be drawn at all, * otherwise return a failure code *//* this does "one-dimensional" clipping: note that the second time it * is called, all the x parameters refer to height and the y to width * - the comments ignore this (if you can understand it when it's * looking at the X parameters, it should become clear what happens on * the second call!) The code is simplified from that in the article, * as we know that gd images always start at (0,0) */static int clip_1d(int *x0, int *y0, int *x1, int *y1, int maxdim) { double m; /* gradient of line */ if (*x0 < 0) { /* start of line is left of window */ if(*x1 < 0) { /* as is the end, so the line never cuts the window */ return 0; } m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ /* adjust x0 to be on the left boundary (ie to be zero), and y0 to match */ *y0 -= (int)(m * *x0); *x0 = 0; /* now, perhaps, adjust the far end of the line as well */ if (*x1 > maxdim) { *y1 += (int)(m * (maxdim - *x1)); *x1 = maxdim; } return 1; } if (*x0 > maxdim) { /* start of line is right of window - complement of above */ if (*x1 > maxdim) { /* as is the end, so the line misses the window */ return 0; } m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ *y0 += (int)(m * (maxdim - *x0)); /* adjust so point is on the right boundary */ *x0 = maxdim; /* now, perhaps, adjust the end of the line */ if (*x1 < 0) { *y1 -= (int)(m * *x1); *x1 = 0; } return 1; } /* the final case - the start of the line is inside the window */ if (*x1 > maxdim) { /* other end is outside to the right */ m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ *y1 += (int)(m * (maxdim - *x1)); *x1 = maxdim; return 1; } if (*x1 < 0) { /* other end is outside to the left */ m = (*y1 - *y0)/(double)(*x1 - *x0); /* calculate the slope of the line */ *y1 -= (int)(m * *x1); *x1 = 0; return 1; } /* only get here if both points are inside the window */ return 1;}void gdImageSetPixel (gdImagePtr im, int x, int y, int color){ int p; switch (color) { case gdStyled: if (!im->style) { /* Refuse to draw if no style is set. */ return; } else { p = im->style[im->stylePos++]; } if (p != gdTransparent) { gdImageSetPixel(im, x, y, p); } im->stylePos = im->stylePos % im->styleLength; break; case gdStyledBrushed: if (!im->style) { /* Refuse to draw if no style is set. */ return; } p = im->style[im->stylePos++]; if (p != gdTransparent && p != 0) { gdImageSetPixel(im, x, y, gdBrushed); } im->stylePos = im->stylePos % im->styleLength; break; case gdBrushed: gdImageBrushApply(im, x, y); break; case gdTiled: gdImageTileApply(im, x, y); break; case gdAntiAliased: gdImageAntiAliasedApply(im, x, y); break; default: if (gdImageBoundsSafe(im, x, y)) { if (im->trueColor) { switch (im->alphaBlendingFlag) { default: case gdEffectReplace: im->tpixels[y][x] = color; break; case gdEffectAlphaBlend: im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color); break; case gdEffectNormal: im->tpixels[y][x] = gdAlphaBlend(im->tpixels[y][x], color); break; case gdEffectOverlay : im->tpixels[y][x] = gdLayerOverlay(im->tpixels[y][x], color); break; } } else { im->pixels[y][x] = color; } } break; }}int gdImageGetTrueColorPixel (gdImagePtr im, int x, int y){ int p = gdImageGetPixel(im, x, y); if (!im->trueColor) { return gdTrueColorAlpha(im->red[p], im->green[p], im->blue[p], (im->transparent == p) ? gdAlphaTransparent : gdAlphaOpaque); } else { return p; }}static void gdImageBrushApply (gdImagePtr im, int x, int y){ int lx, ly; int hy, hx; int x1, y1, x2, y2; int srcx, srcy; if (!im->brush) { return; } hy = gdImageSY(im->brush) / 2; y1 = y - hy; y2 = y1 + gdImageSY(im->brush); hx = gdImageSX(im->brush) / 2; x1 = x - hx; x2 = x1 + gdImageSX(im->brush); srcy = 0; if (im->trueColor) { if (im->brush->trueColor) { for (ly = y1; ly < y2; ly++) { srcx = 0; for (lx = x1; (lx < x2); lx++) { int p; p = gdImageGetTrueColorPixel(im->brush, srcx, srcy); /* 2.0.9, Thomas Winzig: apply simple full transparency */ if (p != gdImageGetTransparent(im->brush)) { gdImageSetPixel(im, lx, ly, p); } srcx++; } srcy++; } } else { /* 2.0.12: Brush palette, image truecolor (thanks to Thorben Kundinger for pointing out the issue) */ for (ly = y1; ly < y2; ly++) { srcx = 0; for (lx = x1; lx < x2; lx++) { int p, tc; p = gdImageGetPixel(im->brush, srcx, srcy); tc = gdImageGetTrueColorPixel(im->brush, srcx, srcy); /* 2.0.9, Thomas Winzig: apply simple full transparency */ if (p != gdImageGetTransparent(im->brush)) { gdImageSetPixel(im, lx, ly, tc); } srcx++; } srcy++; } } } else { for (ly = y1; ly < y2; ly++) { srcx = 0; for (lx = x1; lx < x2; lx++) { int p; p = gdImageGetPixel(im->brush, srcx, srcy); /* Allow for non-square brushes! */ if (p != gdImageGetTransparent(im->brush)) { /* Truecolor brush. Very slow on a palette destination. */ if (im->brush->trueColor) { gdImageSetPixel(im, lx, ly, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p), gdTrueColorGetGreen(p), gdTrueColorGetBlue(p), gdTrueColorGetAlpha(p))); } else { gdImageSetPixel(im, lx, ly, im->brushColorMap[p]); } } srcx++; } srcy++; } }}static void gdImageTileApply (gdImagePtr im, int x, int y){ int srcx, srcy; int p; if (!im->tile) { return; } srcx = x % gdImageSX(im->tile); srcy = y % gdImageSY(im->tile); if (im->trueColor) { p = gdImageGetTrueColorPixel(im->tile, srcx, srcy); gdImageSetPixel(im, x, y, p); } else { p = gdImageGetPixel(im->tile, srcx, srcy); /* Allow for transparency */ if (p != gdImageGetTransparent(im->tile)) { if (im->tile->trueColor) { /* Truecolor tile. Very slow on a palette destination. */ gdImageSetPixel(im, x, y, gdImageColorResolveAlpha(im, gdTrueColorGetRed(p), gdTrueColorGetGreen(p), gdTrueColorGetBlue(p), gdTrueColorGetAlpha(p))); } else { gdImageSetPixel(im, x, y, im->tileColorMap[p]); } } }}static int gdImageTileGet (gdImagePtr im, int x, int y){ int srcx, srcy; int tileColor,p; if (!im->tile) { return -1; } srcx = x % gdImageSX(im->tile); srcy = y % gdImageSY(im->tile); p = gdImageGetPixel(im->tile, srcx, srcy); if (im->trueColor) { if (im->tile->trueColor) { tileColor = p; } else { tileColor = gdTrueColorAlpha( gdImageRed(im->tile,p), gdImageGreen(im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p)); } } else { if (im->tile->trueColor) { tileColor = gdImageColorResolveAlpha(im, gdTrueColorGetRed (p), gdTrueColorGetGreen (p), gdTrueColorGetBlue (p), gdTrueColorGetAlpha (p)); } else { tileColor = p; tileColor = gdImageColorResolveAlpha(im, gdImageRed (im->tile,p), gdImageGreen (im->tile,p), gdImageBlue (im->tile,p), gdImageAlpha (im->tile,p)); } } return tileColor;}static void gdImageAntiAliasedApply (gdImagePtr im, int px, int py){ float p_dist, p_alpha; unsigned char opacity; /* * Find the perpendicular distance from point C (px, py) to the line * segment AB that is being drawn. (Adapted from an algorithm from the * comp.graphics.algorithms FAQ.) */ int LAC_2, LBC_2; int Ax_Cx = im->AAL_x1 - px; int Ay_Cy = im->AAL_y1 - py; int Bx_Cx = im->AAL_x2 - px; int By_Cy = im->AAL_y2 - py; /* 2.0.13: bounds check! AA_opacity is just as capable of * overflowing as the main pixel array. Arne Jorgensen. * 2.0.14: typo fixed. 2.0.15: moved down below declarations * to satisfy non-C++ compilers. */ if (!gdImageBoundsSafe(im, px, py)) { return; } /* Get the squares of the lengths of the segemnts AC and BC. */ LAC_2 = (Ax_Cx * Ax_Cx) + (Ay_Cy * Ay_Cy); LBC_2 = (Bx_Cx * Bx_Cx) + (By_Cy * By_Cy); if (((im->AAL_LAB_2 + LAC_2) >= LBC_2) && ((im->AAL_LAB_2 + LBC_2) >= LAC_2)) { /* The two angles are acute. The point lies inside the portion of the * plane spanned by the line segment. */ p_dist = fabs ((float) ((Ay_Cy * im->AAL_Bx_Ax) - (Ax_Cx * im->AAL_By_Ay)) / im->AAL_LAB); } else { /* The point is past an end of the line segment. It's length from the * segment is the shorter of the lengths from the endpoints, but call * the distance -1, so as not to compute the alpha nor draw the pixel. */ p_dist = -1; } if ((p_dist >= 0) && (p_dist <= (float) (im->thick))) { p_alpha = pow (1.0 - (p_dist / 1.5), 2); if (p_alpha > 0) { if (p_alpha >= 1) { opacity = 255; } else { opacity = (unsigned char) (p_alpha * 255.0); } if (!im->AA_polygon || (im->AA_opacity[py][px] < opacity)) { im->AA_opacity[py][px] = opacity; } } }}int gdImageGetPixel (gdImagePtr im, int x, int y){ if (gdImageBoundsSafe(im, x, y)) { if (im->trueColor) { return im->tpixels[y][x]; } else { return im->pixels[y][x]; } } else { return 0; }}void gdImageAABlend (gdImagePtr im){ float p_alpha, old_alpha; int color = im->AA_color, color_red, color_green, color_blue; int old_color, old_red, old_green, old_blue; int p_color, p_red, p_green, p_blue; int px, py; color_red = gdImageRed(im, color); color_green = gdImageGreen(im, color); color_blue = gdImageBlue(im, color); /* Impose the anti-aliased drawing on the image. */ for (py = 0; py < im->sy; py++) { for (px = 0; px < im->sx; px++) { if (im->AA_opacity[py][px] != 0) { old_color = gdImageGetPixel(im, px, py); if ((old_color != color) && ((old_color != im->AA_dont_blend) || (im->AA_opacity[py][px] == 255))) { /* Only blend with different colors that aren't the dont_blend color. */ p_alpha = (float) (im->AA_opacity[py][px]) / 255.0; old_alpha = 1.0 - p_alpha; if (p_alpha >= 1.0) { p_color = color; } else { old_red = gdImageRed(im, old_color); old_green = gdImageGreen(im, old_color); old_blue = gdImageBlue(im, old_color); p_red = (int) (((float) color_red * p_alpha) + ((float) old_red * old_alpha)); p_green = (int) (((float) color_green * p_alpha) + ((float) old_green * old_alpha)); p_blue = (int) (((float) color_blue * p_alpha) + ((float) old_blue * old_alpha)); p_color = gdImageColorResolve(im, p_red, p_green, p_blue); } gdImageSetPixel(im, px, py, p_color); } } } /* Clear the AA_opacity array behind us. */ memset(im->AA_opacity[py], 0, im->sx); }}/* Bresenham as presented in Foley & Van Dam */void gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color){ int t; int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; int wid; int w, wstart; int thick = im->thick; /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn */ if (!clip_1d(&x1,&y1,&x2,&y2,gdImageSX(im)) || !clip_1d(&y1,&x1,&y2,&x2,gdImageSY(im))) { return; } /* Vertical */ if (x1==x2) { if (y2 < y1) { t = y2; y2 = y1; y1 = t; } for (;y1 <= y2; y1++) { gdImageSetPixel(im, x1,y1, color); } return; } /* Horizontal */ if (y1==y2) { if (x2 < x1) { t = x2; x2 = x1; x1 = t; } for (;x1 <= x2; x1++) { gdImageSetPixel(im, x1,y1, color); } return; } /* gdAntiAliased passed as color: set anti-aliased line (AAL) global vars. */ if (color == gdAntiAliased) { im->AAL_x1 = x1; im->AAL_y1 = y1; im->AAL_x2 = x2; im->AAL_y2 = y2; /* Compute what we can for point-to-line distance calculation later. */ im->AAL_Bx_Ax = x2 - x1; im->AAL_By_Ay = y2 - y1; im->AAL_LAB_2 = (im->AAL_Bx_Ax * im->AAL_Bx_Ax) + (im->AAL_By_Ay * im->AAL_By_Ay); im->AAL_LAB = sqrt (im->AAL_LAB_2); /* For AA, we must draw pixels outside the width of the line. Keep in * mind that this will be curtailed by cos/sin of theta later. */ thick += 4; } dx = abs(x2 - x1); dy = abs(y2 - y1); if (dy <= dx) { /* More-or-less horizontal. use wid for vertical stroke */ /* Doug Claar: watch out for NaN in atan2 (2.0.5) */ if ((dx == 0) && (dy == 0)) { wid = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -