static void gd_bezier(point* A, int n, int arrow_at_start, int arrow_at_end) { pointf p0, p1, V[4]; int i, j, step; int style[20]; int pen, width; gdImagePtr brush = NULL; if (cstk[SP].pen != P_NONE) { if (cstk[SP].pen == P_DASHED) { for (i = 0; i < 10; i++) style[i] = cstk[SP].pencolor; for (; i < 20; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 20); pen = gdStyled; } else if (cstk[SP].pen == P_DOTTED) { for (i = 0; i < 2; i++) style[i] = cstk[SP].pencolor; for (; i < 12; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 12); pen = gdStyled; } else { pen = cstk[SP].pencolor; } #if 0 if (cstk[SP].penwidth != WIDTH_NORMAL) { width=cstk[SP].penwidth; brush = gdImageCreate(width,width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0,0,width-1, width-1, cstk[SP].pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } #else width = cstk[SP].penwidth; gdImageSetThickness(im, width); #endif V[3].x = A[0].x; V[3].y = A[0].y; for (i = 0; i+3 < n; i += 3) { V[0] = V[3]; for (j = 1; j <= 3; j++) { V[j].x = A[i+j].x; V[j].y = A[i+j].y; } p0 = gdpt(V[0]); for (step = 1; step <= BEZIERSUBDIVISION; step++) { p1 = gdpt(Bezier(V, 3, (double)step/BEZIERSUBDIVISION, NULL, NULL)); gdImageLine(im, ROUND(p0.x), ROUND(p0.y), ROUND(p1.x), ROUND(p1.y), pen); p0 = p1; } } if (brush) gdImageDestroy(brush); } }
static void gd_polyline(point* A, int n) { pointf p, p1; int i; int style[20]; int pen, width; gdImagePtr brush = NULL; if (cstk[SP].pen != P_NONE) { if (cstk[SP].pen == P_DASHED) { for (i = 0; i < 10; i++) style[i] = cstk[SP].pencolor; for (; i < 20; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 20); pen = gdStyled; } else if (cstk[SP].pen == P_DOTTED) { for (i = 0; i < 2; i++) style[i] = cstk[SP].pencolor; for (; i < 12; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 12); pen = gdStyled; } else { pen = cstk[SP].pencolor; } #if 0 if (cstk[SP].penwidth != WIDTH_NORMAL) { width = cstk[SP].penwidth; brush = gdImageCreate(width,width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0,0,width-1,width-1,cstk[SP].pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } #else width = cstk[SP].penwidth; gdImageSetThickness(im, width); #endif p.x = A[0].x; p.y = A[0].y; p = gdpt(p); for (i = 1; i < n; i++) { p1.x = A[i].x; p1.y = A[i].y; p1 = gdpt(p1); gdImageLine(im, ROUND(p.x), ROUND(p.y), ROUND(p1.x), ROUND(p1.y), pen); p.x = p1.x; p.y = p1.y; } if (brush) gdImageDestroy(brush); } }
static void gd_ellipse(point p, int rx, int ry, int filled) { pointf mp; int i; int style[40]; /* need 2* size for arcs, I don't know why */ int pen, width; gdImagePtr brush = NULL; if (cstk[SP].pen != P_NONE) { if (cstk[SP].pen == P_DASHED) { for (i = 0; i < 20; i++) style[i] = cstk[SP].pencolor; for (; i < 40; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 40); pen = gdStyled; } else if (cstk[SP].pen == P_DOTTED) { for (i = 0; i < 2; i++) style[i] = cstk[SP].pencolor; for (; i < 24; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 24); pen = gdStyled; } else { pen = cstk[SP].pencolor; } #if 1 /* use brush instead of Thickness to improve outline appearance */ gdImageSetThickness(im, WIDTH_NORMAL); if (cstk[SP].penwidth != WIDTH_NORMAL) { width = cstk[SP].penwidth; brush = gdImageCreate(width,width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0,0,width-1, width-1, cstk[SP].pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } #else width = cstk[SP].penwidth; gdImageSetThickness(im, width); #endif if (Rot) {int t; t = rx; rx = ry; ry = t;} mp.x = p.x; mp.y = p.y; mp = gdpt(mp); if (filled) { gdImageFilledEllipse(im, ROUND(mp.x), ROUND(mp.y), ROUND(Zoom*(rx + rx)), ROUND(Zoom*(ry + ry)), cstk[SP].fillcolor); } gdImageArc(im, ROUND(mp.x), ROUND(mp.y), ROUND(Zoom*(rx + rx)), ROUND(Zoom*(ry + ry)), 0, 360, pen); if (brush) gdImageDestroy(brush); } }
static void gd_polygon(point *A, int n, int filled) { pointf p; int i; gdPoint *points; int style[20]; int pen, width; gdImagePtr brush = NULL; if (cstk[SP].pen != P_NONE) { if (cstk[SP].pen == P_DASHED) { for (i = 0; i < 10; i++) style[i] = cstk[SP].pencolor; for (; i < 20; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 20); pen = gdStyled; } else if (cstk[SP].pen == P_DOTTED) { for (i = 0; i < 2; i++) style[i] = cstk[SP].pencolor; for (; i < 12; i++) style[i] = gdTransparent; gdImageSetStyle(im, style, 12); pen = gdStyled; } else { pen = cstk[SP].pencolor; } #if 1 /* use brush instead of Thickness to improve end butts */ gdImageSetThickness(im, WIDTH_NORMAL); if (cstk[SP].penwidth != WIDTH_NORMAL) { width=cstk[SP].penwidth * Zoom; brush = gdImageCreate(width,width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0,0,width-1, width-1, cstk[SP].pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } #else width = cstk[SP].penwidth; gdImageSetThickness(im, width); #endif points = N_GNEW(n,gdPoint); for (i = 0; i < n; i++) { p.x = A[i].x; p.y = A[i].y; p = gdpt(p); points[i].x = ROUND(p.x); points[i].y = ROUND(p.y); } if (filled) gdImageFilledPolygon(im, points, n, cstk[SP].fillcolor); gdImagePolygon(im, points, n, pen); free(points); if (brush) gdImageDestroy(brush); } }
int main (int argc, char **argv) { gdImagePtr im; gdImagePtr pal; FILE *in, *out; if (argc != 3) { fprintf (stderr, "Usage: gd2copypal palettefile.gd2 filename.gd2\n"); exit (1); } in = fopen (argv[1], "rb"); if (!in) { fprintf (stderr, "Palette file does not exist!\n"); exit (1); } pal = gdImageCreateFromGd2 (in); fclose (in); if (!pal) { fprintf (stderr, "Palette is not in GD2 format!\n"); exit (1); } in = fopen (argv[2], "rb"); if (!in) { fprintf (stderr, "Input file does not exist!\n"); exit (1); } im = gdImageCreateFromGd2 (in); fclose (in); if (!im) { fprintf (stderr, "Input is not in GD2 format!\n"); exit (1); } gdImagePaletteCopy (im, pal); out = fopen (argv[2], "wb"); if (!out) { fprintf (stderr, "Output file cannot be written to!\n"); gdImageDestroy (im); exit (1); } gdImageGd2 (im, out, 128, 2); fclose (out); gdImageDestroy (pal); gdImageDestroy (im); return 0; }
/** * Function: gdImageCrop * Crops the src image using the area defined by the <crop> rectangle. * The result is returned as a new image. * * * Parameters: * src - Source image * crop - Rectangular region to crop * * Returns: * <gdImagePtr> on success or NULL */ gdImagePtr gdImageCrop(gdImagePtr src, const gdRectPtr crop) { gdImagePtr dst; int y; /* allocate the requested size (could be only partially filled) */ if (src->trueColor) { dst = gdImageCreateTrueColor(crop->width, crop->height); if (dst == NULL) { return NULL; } gdImageSaveAlpha(dst, 1); } else { dst = gdImageCreate(crop->width, crop->height); if (dst == NULL) { return NULL; } gdImagePaletteCopy(dst, src); } dst->transparent = src->transparent; /* check position in the src image */ if (crop->x < 0 || crop->x>=src->sx || crop->y<0 || crop->y>=src->sy) { return dst; } /* reduce size if needed */ if ((src->sx - crop->width) < crop->x) { crop->width = src->sx - crop->x; } if ((src->sy - crop->height) < crop->y) { crop->height = src->sy - crop->y; } #if 0 printf("rect->x: %i\nrect->y: %i\nrect->width: %i\nrect->height: %i\n", crop->x, crop->y, crop->width, crop->height); #endif y = crop->y; if (src->trueColor) { unsigned int dst_y = 0; while (y < (crop->y + (crop->height - 1))) { /* TODO: replace 4 w/byte per channel||pitch once available */ memcpy(dst->tpixels[dst_y++], src->tpixels[y++] + crop->x, crop->width * 4); } } else { int x; for (y = crop->y; y < (crop->y + (crop->height - 1)); y++) { for (x = crop->x; x < (crop->x + (crop->width - 1)); x++) { dst->pixels[y - crop->y][x - crop->x] = src->pixels[y][x]; } } } return dst; }
int getRasterBufferCopyGD(imageObj *img, rasterBufferObj *rb) { gdImagePtr gdImg = MS_IMAGE_GET_GDIMAGEPTR(img); int row; rb->type = MS_BUFFER_GD; rb->width = gdImg->sx; rb->height = gdImg->sy; rb->data.gd_img = gdImageCreate(gdImg->sx,gdImg->sy); rb->data.gd_img->transparent = gdImg->transparent; gdImagePaletteCopy(rb->data.gd_img,gdImg); for(row=0;row<gdImg->sy;row++) memcpy(rb->data.gd_img->pixels[row],gdImg->pixels[row],gdImg->sx); return MS_SUCCESS; }
void write_frame(int time) { if (rank != 0) { MPI_Send(u+1, nxl, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); } else { int source, i, j, count, global_index; MPI_Status status; im = gdImageCreate(nx*PWIDTH,PHEIGHT); if (time == 0) { for (j=0; j<MAXCOLORS; j++) colors[j] = gdImageColorAllocate (im, j, 0, MAXCOLORS-j-1); gdImageGifAnimBegin(im, file, 1, -1); } else { gdImagePaletteCopy(im, previm); } global_index = 0; for (source = 0; source < nprocs; source++) { if (source != 0) { MPI_Recv(buf, 1+nx/nprocs, MPI_DOUBLE, source, 0, MPI_COMM_WORLD, &status); MPI_Get_count(&status, MPI_DOUBLE, &count); } else { for (i = 1; i <= nxl; i++) buf[i-1] = u[i]; count = nxl; } for (i = 0; i < count; i++) { int color = (int)(buf[i]*MAXCOLORS/M); assert(color >= 0); if (color >= MAXCOLORS) color = MAXCOLORS-1; gdImageFilledRectangle (im, global_index*PWIDTH, 0, (global_index+1)*PWIDTH-1, PHEIGHT-1, colors[color]); global_index++; } } if (time == 0) { gdImageGifAnimAdd(im, file, 0, 0, 0, 0, gdDisposalNone, NULL); } else { gdImageGifAnimAdd(im, file, 0, 0, 0, 5, gdDisposalNone, previm); gdImageDestroy(previm); } previm=im; im=NULL; } #ifdef DEBUG write_plain(time); #endif }
result_t Image::rotate(int32_t dir) { if (dir != gd_base::_LEFT && dir != gd_base::_RIGHT) return CHECK_ERROR(CALL_E_INVALIDARG); int32_t sx = gdImageSX(m_image); int32_t sy = gdImageSY(m_image); int32_t i, j; gdImagePtr newImage; if (gdImageTrueColor(m_image)) newImage = gdImageCreateTrueColor(sy, sx); else { newImage = gdImageCreate(sy, sx); gdImagePaletteCopy(newImage, m_image); } gdImageColorTransparent(newImage, gdImageGetTransparent(m_image)); if (dir == gd_base::_LEFT) { for (i = 0; i < sx; i++) for (j = 0; j < sy; j++) gdImageSetPixel(newImage, j, sx - i - 1, gdImageGetPixel(m_image, i, j)); } else { for (i = 0; i < sx; i++) for (j = 0; j < sy; j++) gdImageSetPixel(newImage, sy - j - 1, i, gdImageGetPixel(m_image, i, j)); } setExtMemory(-1); gdImageDestroy(m_image); m_image = newImage; setExtMemory(); return 0; }
result_t Image::New(int32_t width, int32_t height, obj_ptr<Image> &retVal) { if (width <= 0 || height <= 0) return CHECK_ERROR(CALL_E_INVALIDARG); obj_ptr<Image> img = new Image(); if (gdImageTrueColor(m_image)) img->m_image = gdImageCreateTrueColor(width, height); else img->m_image = gdImageCreate(width, height); gdImagePaletteCopy(img->m_image, m_image); gdImageColorTransparent(img->m_image, gdImageGetTransparent(m_image)); img->setExtMemory(); retVal = img; return 0; }
static int set_penstyle(GVJ_t * job, gdImagePtr im, gdImagePtr brush) { obj_state_t *obj = job->obj; int i, pen, pencolor, transparent, width, dashstyle[40]; pen = pencolor = color_index(im, obj->pencolor); transparent = gdImageGetTransparent(im); if (obj->pen == PEN_DASHED) { for (i = 0; i < 20; i++) dashstyle[i] = pencolor; for (; i < 40; i++) dashstyle[i] = transparent; gdImageSetStyle(im, dashstyle, 20); pen = gdStyled; } else if (obj->pen == PEN_DOTTED) { for (i = 0; i < 2; i++) dashstyle[i] = pencolor; for (; i < 24; i++) dashstyle[i] = transparent; gdImageSetStyle(im, dashstyle, 24); pen = gdStyled; } width = obj->penwidth * job->scale.x; if (width < PENWIDTH_NORMAL) width = PENWIDTH_NORMAL; /* gd can't do thin lines */ gdImageSetThickness(im, width); /* use brush instead of Thickness to improve end butts */ if (width != PENWIDTH_NORMAL) { brush = gdImageCreate(width, width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0, 0, width - 1, width - 1, pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } return pen; }
result_t Image::getData(int32_t format, int32_t quality, obj_ptr<Buffer_base> &retVal, AsyncEvent *ac) { if (!m_image) return CHECK_ERROR(CALL_E_INVALID_CALL); if (!ac) return CHECK_ERROR(CALL_E_NOSYNC); int32_t size = 0; void *data = NULL; int32_t sx = gdImageSX(m_image); int32_t sy = gdImageSY(m_image); int32_t i, j; int32_t trans = -1; if (gdImageTrueColor(m_image)) { for (i = 0; i < sx && trans == -1; i ++) for (j = 0; j < sy && trans == -1; j++) if ((gdImageGetPixel(m_image, i, j) & 0xff000000) != 0) trans = 0; } else trans = gdImageGetTransparent(m_image); gdImagePtr nowImage = m_image; if (trans != -1) { if (format != gd_base::_PNG) { if (gdImageTrueColor(m_image)) nowImage = gdImageCreateTrueColor(sx, sy); else { nowImage = gdImageCreate(sx, sy); gdImagePaletteCopy(nowImage, m_image); } gdImageFilledRectangle(nowImage, 0, 0, sx, sy, gdImageColorAllocate(nowImage, 255, 255, 255)); gdImageCopy(nowImage, m_image, 0, 0, 0, 0, sx, sy); } else if (gdImageTrueColor(m_image)) gdImageSaveAlpha(m_image, 1); } switch (format) { case gd_base::_GIF: data = gdImageGifPtr(nowImage, &size); break; case gd_base::_PNG: data = gdImagePngPtr(nowImage, &size); break; case gd_base::_JPEG: { unsigned char *ed_data = NULL; uint32_t ed_size = 0; data = gdImageJpegPtr(nowImage, &size, quality, ed_data, ed_size); if (ed_data) free(ed_data); break; } case gd_base::_TIFF: data = gdImageTiffPtr(nowImage, &size); break; case gd_base::_BMP: data = gdImageBmpPtr(nowImage, &size, 1); break; case gd_base::_WEBP: data = gdImageWebpPtrEx(nowImage, &size, quality); break; } if (nowImage != m_image) gdImageDestroy(nowImage); if (data == NULL) return CHECK_ERROR(CALL_E_INVALIDARG); retVal = new Buffer(std::string((char *) data, size)); gdFree(data); return 0; }
/* Function: gdImageGifAnimAddCtx Adds an animation frame via a <gdIOCtxPtr>. See gdImageGifAnimAdd>. Parameters: im - The image to add. out - The output <gdIOCtxPtr>. LocalCM - Flag. If 1, use a local color map for this frame. LeftOfs - Left offset of image in frame. TopOfs - Top offset of image in frame. Delay - Delay before next frame (in 1/100 seconds) Disposal - MODE: How to treat this frame when the next one loads. previm - NULL or a pointer to the previous image written. Returns: Nothing. */ BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) { gdImagePtr pim = NULL, tim = im; int interlace, transparent, BitsPerPixel; interlace = im->interlace; transparent = im->transparent; /* Default is no local color map */ if(LocalCM < 0) { LocalCM = 0; } if(im->trueColor) { /* Expensive, but the only way that produces an acceptable result: mix down to a palette based temporary image. */ pim = gdImageCreatePaletteFromTrueColor(im, 1, 256); if (!pim) { return; } tim = pim; } if (previm) { /* create optimized animation. Compare this image to the previous image and crop the temporary copy of current image to include only changed rectangular area. Also replace unchanged pixels inside this area with transparent color. Transparent color needs to be already allocated! Preconditions: TopOfs, LeftOfs are assumed 0 Images should be of same size. If not, a temporary copy is made with the same size as previous image. */ gdImagePtr prev_pim = 0, prev_tim = previm; int x, y; int min_x = 0; int min_y = tim->sy; int max_x = 0; int max_y = 0; int colorMap[256]; if (previm->trueColor) { prev_pim = gdImageCreatePaletteFromTrueColor(previm, 1, 256); if (!prev_pim) { goto fail_end; } prev_tim = prev_pim; } for (x = 0; x < 256; ++x) { colorMap[x] = -2; } /* First find bounding box of changed areas. */ /* first find the top changed row */ for (y = 0; y < tim->sy; ++y) { for (x = 0; x < tim->sx; ++x) { if (!comparewithmap(prev_tim, tim, prev_tim->pixels[y][x], tim->pixels[y][x], colorMap)) { min_y = max_y = y; min_x = max_x = x; goto break_top; } } } break_top: if (tim->sy == min_y) { /* No changes in this frame!! Encode empty image. */ transparent = 0; min_x = min_y = 1; max_x = max_y = 0; } else { /* Then the bottom row */ for (y = tim->sy - 1; y > min_y; --y) { for (x = 0; x < tim->sx; ++x) { if (!comparewithmap (prev_tim, tim, prev_tim->pixels[y][x], tim->pixels[y][x], colorMap)) { max_y = y; if(x < min_x) { min_x = x; } if(x > max_x) { max_x = x; } goto break_bot; } } } break_bot: /* left side */ for (x = 0; x < min_x; ++x) { for (y = min_y; y <= max_y; ++y) { if (!comparewithmap (prev_tim, tim, prev_tim->pixels[y][x], tim->pixels[y][x], colorMap)) { min_x = x; goto break_left; } } } break_left: /* right side */ for (x = tim->sx - 1; x > max_x; --x) { for (y = min_y; y <= max_y; ++y) { if (!comparewithmap (prev_tim, tim, prev_tim->pixels[y][x], tim->pixels[y][x], colorMap)) { max_x = x; goto break_right; } } } break_right: ; } LeftOfs = min_x; TopOfs = min_y; Disposal = 1; /* Make a copy of the image with the new offsets. But only if necessary. */ if (min_x != 0 || max_x != tim->sx - 1 || min_y != 0 || max_y != tim->sy - 1 || transparent >= 0) { gdImagePtr pim2 = gdImageCreate(max_x-min_x + 1, max_y-min_y + 1); if (!pim2) { if (prev_pim) { gdImageDestroy(prev_pim); } goto fail_end; } gdImagePaletteCopy(pim2, LocalCM ? tim : prev_tim); gdImageCopy(pim2, tim, 0, 0, min_x, min_y, max_x - min_x + 1, max_y - min_y + 1); if (pim) { gdImageDestroy(pim); } tim = pim = pim2; } /* now let's compare pixels for transparent optimization. But only if transparent is set. */ if (transparent >= 0) { for(y = 0; y < tim->sy; ++y) { for (x = 0; x < tim->sx; ++x) { if(comparewithmap (prev_tim, tim, prev_tim->pixels[min_y + y][min_x + x], tim->pixels[y][x], 0)) { gdImageSetPixel(tim, x, y, transparent); break; } } } } if(prev_pim) { gdImageDestroy(prev_pim); } } BitsPerPixel = colorstobpp(tim->colorsTotal); /* All set, let's do it. */ GIFAnimEncode( out, tim->sx, tim->sy, LeftOfs, TopOfs, interlace, transparent, Delay, Disposal, BitsPerPixel, LocalCM ? tim->red : 0, tim->green, tim->blue, tim); fail_end: if(pim) { /* Destroy palette based temporary image. */ gdImageDestroy(pim); } }
static void gd_bezier(point * A, int n, int arrow_at_start, int arrow_at_end, int filled) { pointf p, p0, p1, V[4]; int i, j, step; int style[20]; int pen, width; gdImagePtr brush = NULL; gdPoint F[4]; if (!im) return; if (cstk[SP].pen != P_NONE) { if (cstk[SP].pen == P_DASHED) { for (i = 0; i < 10; i++) style[i] = cstk[SP].pencolor; for (; i < 20; i++) style[i] = transparent; gdImageSetStyle(im, style, 20); pen = gdStyled; } else if (cstk[SP].pen == P_DOTTED) { for (i = 0; i < 2; i++) style[i] = cstk[SP].pencolor; for (; i < 12; i++) style[i] = transparent; gdImageSetStyle(im, style, 12); pen = gdStyled; } else { pen = cstk[SP].pencolor; } width = cstk[SP].penwidth * CompScale; if (width < WIDTH_NORMAL) width = WIDTH_NORMAL; /* gd can't do thin lines */ gdImageSetThickness(im, width); if (width > WIDTH_NORMAL) { brush = gdImageCreate(width, width); gdImagePaletteCopy(brush, im); gdImageFilledRectangle(brush, 0, 0, width - 1, width - 1, cstk[SP].pencolor); gdImageSetBrush(im, brush); if (pen == gdStyled) pen = gdStyledBrushed; else pen = gdBrushed; } p.x = A[0].x; p.y = A[0].y; p = gdpt(p); F[0].x = ROUND(p.x); F[0].y = ROUND(p.y); p.x = A[n-1].x; p.y = A[n-1].y; p = gdpt(p); F[3].x = ROUND(p.x); F[3].y = ROUND(p.y); V[3].x = A[0].x; V[3].y = A[0].y; for (i = 0; i + 3 < n; i += 3) { V[0] = V[3]; for (j = 1; j <= 3; j++) { V[j].x = A[i + j].x; V[j].y = A[i + j].y; } p0 = gdpt(V[0]); for (step = 1; step <= BEZIERSUBDIVISION; step++) { p1 = gdpt(Bezier (V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL)); gdImageLine(im, ROUND(p0.x), ROUND(p0.y), ROUND(p1.x), ROUND(p1.y), pen); if (filled) { F[1].x = ROUND(p0.x); F[1].y = ROUND(p0.y); F[2].x = ROUND(p1.x); F[2].y = ROUND(p1.y); gdImageFilledPolygon(im, F, 4, cstk[SP].fillcolor); } p0 = p1; } } if (brush) gdImageDestroy(brush); } }