gd.c
来自「Linux/Unix下的绘图函数库(Graphic Drawing Librar」· C语言 代码 · 共 2,941 行 · 第 1/5 页
C
2,941 行
}; /* Optimization: no gdImageSetPixel */ to->pixels[y][x] = xlate[p]; }; }; for (i = 0; (i < (from->colorsTotal)); i++) { /*printf("Copying color %d (%d, %d, %d, %d)\n", i, from->red[i], from->blue[i], from->green[i], from->alpha[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) *//* 2.0.26, TBB: we now have to respect a clipping rectangle, it won't necessarily start at 0. */static intclip_1d (int *x0, int *y0, int *x1, int *y1, int mindim, int maxdim){ double m; /* gradient of line */ if (*x0 < mindim) { /* start of line is left of window */ if (*x1 < mindim) /* 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 -= m * (*x0 - mindim); *x0 = mindim; /* now, perhaps, adjust the far end of the line as well */ if (*x1 > maxdim) { *y1 += 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 += m * (maxdim - *x0); /* adjust so point is on the right boundary */ *x0 = maxdim; /* now, perhaps, adjust the end of the line */ if (*x1 < mindim) { *y1 -= m * (*x1 - mindim); *x1 = mindim; } 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 += m * (maxdim - *x1); *x1 = maxdim; return 1; } if (*x1 < mindim) { /* other end is outside to the left */ m = (*y1 - *y0) / (double) (*x1 - *x0); /* calculate the slope of the line */ *y1 -= m * (*x1 - mindim); *x1 = mindim; return 1; } /* only get here if both points are inside the window */ return 1;}/* end of line clipping code */BGD_DECLARE(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: /* This shouldn't happen (2.0.26) because we just call gdImageAALine now, but do something sane. */ gdImageSetPixel(im, x, y, im->AA_color); break; default: if (gdImageBoundsSafeMacro (im, x, y)) { if (im->trueColor) { if (im->alphaBlendingFlag) { im->tpixels[y][x] = gdAlphaBlend (im->tpixels[y][x], color); } else { im->tpixels[y][x] = color; } } else { im->pixels[y][x] = color; } } break; }}static voidgdImageBrushApply (gdImagePtr im, int x, int y){ int lx, ly; int hy; int 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 voidgdImageTileApply (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]); } } }}BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y){ if (gdImageBoundsSafeMacro (im, x, y)) { if (im->trueColor) { return im->tpixels[y][x]; } else { return im->pixels[y][x]; } } else { return 0; }}BGD_DECLARE(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; }}BGD_DECLARE(void) gdImageAABlend (gdImagePtr im){ /* NO-OP, kept for library compatibility. */}static void gdImageAALine (gdImagePtr im, int x1, int y1, int x2, int y2, int col);/* Bresenham as presented in Foley & Van Dam */BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color){ int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; int wid; int w, wstart; int thick; if (color == gdAntiAliased) { /* gdAntiAliased passed as color: use the much faster, much cheaper and equally attractive gdImageAALine implementation. That clips too, so don't clip twice. */ gdImageAALine(im, x1, y1, x2, y2, im->AA_color); return; } /* 2.0.10: Nick Atty: clip to edges of drawing rectangle, return if no points need to be drawn. 2.0.26, TBB: clip to edges of clipping rectangle. We were getting away with this because gdImageSetPixel is used for actual drawing, but this is still more efficient and opens the way to skip per-pixel bounds checking in the future. */ if (clip_1d (&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0) return; if (clip_1d (&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0) return; thick = im->thick; 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; } else { /* 2.0.12: Michael Schwartz: divide rather than multiply; TBB: but watch out for /0! */ double ac = cos (atan2 (dy, dx)); if (ac != 0) { wid = thick / ac; } else { wid = 1; } if (wid == 0) { wid = 1; } } d = 2 * dy - dx; incr1 = 2 * dy; incr2 = 2 * (dy - dx); if (x1 > x2) { x = x2; y = y2; ydirflag = (-1); xend = x1; } else { x = x1; y = y1; ydirflag = 1; xend = x2; } /* Set up line thickness */ wstart = y - wid / 2; for (w = wstart; w < wstart + wid; w++) gdImageSetPixel (im, x, w, color); if (((y2 - y1) * ydirflag) > 0) { while (x < xend) { x++; if (d < 0) { d += incr1; } else { y++; d += incr2; } wstart = y - wid / 2; for (w = wstart; w < wstart + wid; w++) gdImageSetPixel (im, x, w, color); } } else { while (x < xend) { x++; if (d < 0) { d += incr1; } else { y--; d += incr2; } wstart = y - wid / 2; for (w = wstart; w < wstart + wid; w++) gdImageSetPixel (im, x, w, color); } } } else { /* More-or-less vertical. use wid for horizontal stroke */ /* 2.0.12: Michael Schwartz: divide rather than multiply; TBB: but watch out for /0! */ double as = sin (atan2 (dy, dx)); if (as != 0) { wid = thick / as; } else { wid = 1; } if (wid == 0) wid = 1; d = 2 * dx - dy; incr1 = 2 * dx; incr2 = 2 * (dx - dy); if (y1 > y2) { y = y2; x = x2; yend = y1; xdirflag = (-1); } else { y = y1; x = x1; yend = y2; xdirflag = 1; } /* Set up line thickness */ wstart = x - wid / 2; for (w = wstart; w < wstart + wid; w++) gdImageSetPixel (im, w, y, color); if (((x2 - x1) * xdirflag) > 0) { while (y < yend) { y++; if (d < 0) { d += incr1; } else { x++; d += incr2; } wstart = x - wid / 2; for (w = wstart; w < wstart + wid; w++) gdImageSetPixel (im, w, y, color); } } else { while (y < yend) { y++; if (d < 0) { d += incr1; } else { x--; d += incr2; } wstart = x - wid / 2; for (w = wstart; w < wstart + wid; w++) gdImageSetPixel (im, w, y, color); } } }}static void dashedSet (gdImagePtr im, int x, int y, int color, int *onP, int *dashStepP, int wid, int vert);BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color){ int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag; int dashStep = 0; int on = 1; int wid; int vert; int thick = im->thick; dx = abs (x2 - x1); dy = abs (y2 - y1); if (dy <= dx) { /* More-or-less horizontal. use wid for vertical stroke */ /* 2.0.12: Michael Schwartz: divide rather than multiply; TBB: but watch out for /0! */ double as = sin (atan2 (dy, dx)); if (as != 0) { wid = thick / as; } else { wid = 1; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?