/************************************************************* GD.c - Ruby extension library to use Boutell's gd library. Originally written: Yukihiro Matsumoto (matz@ruby-lang.org) Current maintainer: Ryuichi Tamura (tam@kais.kyoto-u.ac.jp) $Date: 2001/05/30 14:06:40 $ $Revision: 1.6.2.3 $ **************************************************************/ #include "ruby.h" #include "rubyio.h" #include "version.h" #include "gd.h" #include "gdfontg.h" /* giant */ #include "gdfontl.h" /* large */ #include "gdfontmb.h" /* medium bold */ #include "gdfonts.h" /* small */ #include "gdfontt.h" /* tiny */ #define RUBY_GD_VERSION "0.7.4" #ifndef StringValueCStr #define StringValueCStr(s) STR2CSTR(s) #endif #ifndef StringValuePtr #define StringValuePtr(s) STR2CSTR(s) #endif extern VALUE rb_io_binmode(VALUE io); extern gdImagePtr gdImageCreateFromXpm(char* ); static VALUE mGD, cImage, cFont, cPolygon; #ifndef GetReadFile #define GetReadFile(fptr) rb_io_stdio_file(fptr) #endif #ifndef GetWriteFile #define GetWriteFile(fptr) rb_io_stdio_file(fptr) #endif #ifdef ENABLE_GD_2_0 static VALUE is_truecolor(im) gdImagePtr im; { return im->trueColor ? Qtrue : Qfalse; } #endif /* ENABLE_GD_2_0 */ static OpenFile * get_fptr(iop) volatile VALUE *iop; { OpenFile *fptr; VALUE io = rb_convert_type(*iop, T_FILE, "IO", "to_io"); *iop = io; rb_io_binmode(io); GetOpenFile(io, fptr); return fptr; } static OpenFile * open_fptr(fname, mode) volatile VALUE *fname; const char *mode; { *fname = rb_funcall(rb_cObject, rb_intern("open"), 2, *fname, rb_str_new2(mode)); return get_fptr(fname); } static FILE * readable_fptr(fptr) OpenFile *fptr; { rb_io_check_readable(fptr); return GetReadFile(fptr); } static FILE * writable_fptr(fptr) OpenFile *fptr; { rb_io_check_writable(fptr); return GetWriteFile(fptr); } static void free_img(iptr) gdImagePtr iptr; { if (iptr) { gdImageDestroy(iptr); } } static VALUE alloc_img(klass, iptr) VALUE klass; gdImagePtr iptr; { return Data_Wrap_Struct(klass,0,free_img,iptr); } static VALUE img_destroy(img) VALUE img; { if (DATA_PTR(img)) { gdImageDestroy(DATA_PTR(img)); DATA_PTR(img) = 0; } return Qnil; } static VALUE img_init(klass, iptr) VALUE klass; gdImagePtr iptr; { VALUE img = alloc_img(klass, iptr); rb_obj_call_init(img, 0, 0); if (rb_block_given_p()) { return rb_ensure(rb_yield, img, img_destroy, img); } return img; } static gdImagePtr get_iptr(img) VALUE img; { gdImagePtr im; if (TYPE(img) != T_DATA || RDATA(img)->dfree != free_img) { rb_raise(rb_eTypeError, "wrong argument type %s (expected GD::Image)", rb_obj_classname(img)); } im = DATA_PTR(img); if (!im) { rb_raise(rb_eTypeError, "uninitialized GD::Image"); } return im; } static VALUE img_s_alloc(klass) VALUE klass; { return alloc_img(klass, 0); } static VALUE img_s_new(klass, w, h) VALUE klass, w, h; { gdImagePtr iptr; int ww = NUM2INT(w), hh = NUM2INT(h); if (ww < 0 || hh < 0) rb_raise(rb_eArgError, "Negative width/height not allowed"); iptr = gdImageCreate(ww, hh); return img_init(klass, iptr); } static VALUE img_from_pngfname(klass, fname) VALUE klass, fname; { OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); iptr = gdImageCreateFromPng(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid PNG File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_png(klass, f) VALUE klass, f; { OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); iptr = gdImageCreateFromPng(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid PNG File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_gdfname(klass, fname) VALUE klass, fname; { OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); iptr = gdImageCreateFromGd(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Gd File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_gd(klass, f) VALUE klass, f; { OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); iptr = gdImageCreateFromGd(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Gd File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_gd2fname(klass, fname) VALUE klass, fname; { OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); iptr = gdImageCreateFromGd2(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Gd2 File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_gd2(klass, f) VALUE klass, f; { OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); iptr = gdImageCreateFromGd2(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Gd2 File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_gd2_partfname(klass, fname, srcx, srcy, srcw, srch) VALUE klass, fname, srcx, srcy, srcw, srch; { int x = NUM2INT(srcx), y = NUM2INT(srcy), w = NUM2INT(srcw), h = NUM2INT(srch); OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); iptr = gdImageCreateFromGd2Part(readable_fptr(fptr), x, y, w, h); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Gd2 File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_gd2_part(klass, f, srcx, srcy, srcw, srch) VALUE klass, f, srcx, srcy, srcw, srch; { int x = NUM2INT(srcx), y = NUM2INT(srcy), w = NUM2INT(srcw), h = NUM2INT(srch); OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); iptr = gdImageCreateFromGd2Part(readable_fptr(fptr), x, y, w, h); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Gd2 File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_xbm(klass, f) VALUE klass, f; { OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); iptr = gdImageCreateFromXbm(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Xbm File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_xbmfname(klass, fname) VALUE klass, fname; { OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); iptr = gdImageCreateFromXbm(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Xbm File", fptr->path); return img_init(klass, iptr); } #ifdef HAVE_GDIMAGECREATEFROMXPM static VALUE img_from_xpm(klass, f) VALUE klass, f; { OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); rb_io_check_readable(fptr); /* need cast, and the argument is char* type */ iptr = (gdImagePtr)gdImageCreateFromXpm(fptr->path); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid XPM File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_xpmfname(klass, fname) VALUE klass, fname; { OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); rb_io_check_readable(fptr); /* need cast, and the argument is char* type */ iptr = (gdImagePtr)gdImageCreateFromXpm(fptr->path); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid XPM File", fptr->path); return img_init(klass, iptr); } #endif #ifdef HAVE_GDIMAGECREATEFROMJPEG static VALUE img_from_jpeg(klass, f) VALUE klass, f; { OpenFile *fptr; gdImagePtr iptr; fptr = get_fptr(&f); iptr = gdImageCreateFromJpeg(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Jpeg File", fptr->path); return img_init(klass, iptr); } static VALUE img_from_jpegfname(klass, fname) VALUE klass, fname; { OpenFile *fptr; gdImagePtr iptr; fptr = open_fptr(&fname, "r"); iptr = gdImageCreateFromJpeg(readable_fptr(fptr)); if (!iptr) rb_raise(rb_eArgError, "%s is not a valid Jpeg File", fptr->path); return img_init(klass, iptr); } #endif static void hex2triplet(hex, tri) VALUE hex; unsigned int tri[3]; { StringValue(hex); if (RSTRING(hex)->len != 7 || sscanf(RSTRING(hex)->ptr, "#%2x%2x%2x", &tri[0], &tri[1], &tri[2]) != 3) rb_raise(rb_eArgError, "Invalid format: %s", RSTRING(hex)->ptr); } static VALUE img_color_allocate_tri(img, r, g, b) VALUE img, r, g, b; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b); c = gdImageColorAllocate(get_iptr(img), rr, gg, bb); return INT2FIX(c); } static VALUE img_color_allocate_str(img, rgbstr) VALUE img, rgbstr; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdImageColorAllocate(get_iptr(img), rgb[0], rgb[1], rgb[2]); return INT2FIX(c); } static VALUE img_color_allocate(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, retval; if (!(argc == 1 || argc == 3)) rb_raise(rb_eArgError, "Wrong # of arguments (1 or 3 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "10", &rgbstr); retval = img_color_allocate_str(img, rgbstr); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "30", &r, &g, &b); retval = img_color_allocate_tri(img, r, g, b); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_color_deallocate(img, color) VALUE img, color; { int c = NUM2INT(color); gdImageColorDeallocate(get_iptr(img), c); return img; } #ifdef HAVE_GDIMAGECOLORRESOLVE static VALUE img_color_resolve_tri(img, r, g, b) VALUE img, r, g, b; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b); c = gdImageColorResolve(get_iptr(img), rr, gg, bb); return INT2FIX(c); } static VALUE img_color_resolve_str(img, rgbstr) VALUE img, rgbstr; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdImageColorResolve(get_iptr(img), rgb[0], rgb[1], rgb[2]); return INT2FIX(c); } static VALUE img_color_resolve(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, retval; if (!(argc == 1 || argc == 3)) rb_raise(rb_eArgError, "Wrong # of arguments (1 or 3 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "10", &rgbstr); retval = img_color_resolve_str(img, rgbstr); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "30", &r, &g, &b); retval = img_color_resolve_tri(img, r, g, b); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } #endif /* HAVE_GDIMAGECOLORRESOLVE */ static VALUE img_color_closest_tri(img, r, g, b) VALUE img, r, g, b; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b); c = gdImageColorClosest(get_iptr(img), rr, gg, bb); return INT2FIX(c); } static VALUE img_color_closest_str(img, rgbstr) VALUE img, rgbstr; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdImageColorClosest(get_iptr(img), rgb[0], rgb[1], rgb[2]); return INT2FIX(c); } static VALUE img_color_closest(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, retval; if (!(argc == 1 || argc == 3)) rb_raise(rb_eArgError, "Wrong # of arguments (1 or 3 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "10", &rgbstr); retval = img_color_closest_str(img, rgbstr); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "30", &r, &g, &b); retval = img_color_closest_tri(img, r, g, b); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } extern int gdImageColorClosestHWB(gdImagePtr, int, int, int); static VALUE img_color_closestHWB_tri(img, r, g, b) VALUE img, r, g, b; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b); c = gdImageColorClosestHWB(get_iptr(img), rr, gg, bb); return INT2FIX(c); } static VALUE img_color_closestHWB_str(img, rgbstr) VALUE img, rgbstr; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdImageColorClosestHWB(get_iptr(img), rgb[0], rgb[1], rgb[2]); return INT2FIX(c); } static VALUE img_color_closestHWB(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, retval; if (!(argc == 1 || argc == 3)) rb_raise(rb_eArgError, "Wrong # of arguments (1 or 3 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "10", &rgbstr); retval = img_color_closestHWB_str(img, rgbstr); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "30", &r, &g, &b); retval = img_color_closestHWB_tri(img, r, g, b); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_color_exact_tri(img, r, g, b) VALUE img, r, g, b; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b); c = gdImageColorExact(get_iptr(img), rr, gg, bb); return INT2FIX(c); } static VALUE img_color_exact_str(img, rgbstr) VALUE img, rgbstr; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdImageColorExact(get_iptr(img), rgb[0], rgb[1], rgb[2]); return INT2FIX(c); } static VALUE img_color_exact(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, retval; if (!(argc == 1 || argc == 3)) rb_raise(rb_eArgError, "Wrong # of arguments (1 or 3 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "10", &rgbstr); retval = img_color_exact_str(img, rgbstr); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "30", &r, &g, &b); retval = img_color_exact_tri(img, r, g, b); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_colors_total(img) VALUE img; { int c; c = gdImageColorsTotal(get_iptr(img)); return INT2FIX(c); } static VALUE img_get_pixel(img, x, y) VALUE img, x, y; { int c, xx = NUM2INT(x), yy = NUM2INT(y); c = gdImageGetPixel(get_iptr(img), xx, yy); return INT2FIX(c); } static VALUE img_set_pixel(img, x, y, color) VALUE img, x, y, color; { int xx = NUM2INT(x), yy = NUM2INT(y), c = NUM2INT(color); gdImageSetPixel(get_iptr(img), xx, yy, c); return img; } static VALUE img_red(img, idx) VALUE img, idx; { int i,c; i = NUM2INT(idx); c = gdImageRed(get_iptr(img), i); return INT2FIX(c); } static VALUE img_green(img, idx) VALUE img, idx; { int i,c; i = NUM2INT(idx); c = gdImageGreen(get_iptr(img), i); return INT2FIX(c); } static VALUE img_blue(img, idx) VALUE img, idx; { int i,c; i = NUM2INT(idx); c = gdImageBlue(get_iptr(img), i); return INT2FIX(c); } static VALUE img_rgb(img, idx) VALUE img, idx; { gdImagePtr im; VALUE ary = rb_ary_new2(3); int i, c; i = NUM2INT(idx); im = get_iptr(img); c = gdImageRed(im, i); rb_ary_push(ary, INT2FIX(c)); c = gdImageGreen(im, i); rb_ary_push(ary, INT2FIX(c)); c = gdImageBlue(im, i); rb_ary_push(ary, INT2FIX(c)); return ary; } static VALUE img_transparent(img, idx) VALUE img, idx; { int i = NUM2INT(idx); gdImageColorTransparent(get_iptr(img), i); return img; } static VALUE img_set_blush(img, brush) VALUE img, brush; { gdImagePtr im, br; im = get_iptr(img); br = get_iptr(brush); gdImageSetBrush(im, br); return img; } static VALUE img_set_style(argc, argv, img) int argc; VALUE *argv; VALUE img; { int *style; int i; style = ALLOCA_N(int, argc); for (i = 0; i < argc; i++) { style[i] = NUM2INT(argv[i]); } gdImageSetStyle(get_iptr(img), style, argc); return img; } static VALUE img_set_tile(img, tile) VALUE img, tile; { gdImagePtr im, ti; im = get_iptr(img); ti = get_iptr(tile); gdImageSetTile(im, ti); return img; } static VALUE img_line(img, x1, y1, x2, y2, c) VALUE img, x1, y1, x2, y2, c; { int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1); int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2); int ic = NUM2INT(c); gdImageLine(get_iptr(img), ix1, iy1, ix2, iy2, ic); return img; } static VALUE img_dashed_line(img, x1, y1, x2, y2, c) VALUE img, x1, y1, x2, y2, c; { int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1); int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2); int ic = NUM2INT(c); gdImageDashedLine(get_iptr(img), ix1, iy1, ix2, iy2, ic); return img; } static VALUE img_rectangle(img, x1, y1, x2, y2, c) VALUE img, x1, y1, x2, y2, c; { int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1); int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2); int ic = NUM2INT(c); gdImageRectangle(get_iptr(img), ix1, iy1, ix2, iy2, ic); return img; } static VALUE img_filled_rectangle(img, x1, y1, x2, y2, c) VALUE img, x1, y1, x2, y2, c; { int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1); int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2); int ic = NUM2INT(c); gdImageFilledRectangle(get_iptr(img), ix1, iy1, ix2, iy2, ic); return img; } struct polygon { int capa; int len; gdPoint pnt[1]; }; static void poly_free(ptr) void *ptr; { } #define is_poly(ply) (TYPE(ply) == T_DATA && RDATA(ply)->dfree == poly_free) static struct polygon * get_poly(ply) VALUE ply; { if (!is_poly(ply)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected GD::Polygon)", rb_obj_classname(ply)); } return DATA_PTR(ply); } static VALUE img_polygon(img, ply, c) VALUE img; VALUE ply; VALUE c; { int col = NUM2INT(c); struct polygon *ptr = get_poly(ply); if (ptr && ptr->len) { gdImagePolygon(get_iptr(img), ptr->pnt, ptr->len, col); } return img; } static VALUE img_filled_polygon(img, ply, c) VALUE img; VALUE ply; VALUE c; { int col = NUM2INT(c); struct polygon *ptr = get_poly(ply); if (ptr && ptr->len) { gdImageFilledPolygon(get_iptr(img), ptr->pnt, ptr->len, col); } return img; } static VALUE img_arc(img, cx, cy, w, h, s, e, c) VALUE img, cx, cy, w, h, s, e, c; { int icx = NUM2INT(cx), icy = NUM2INT(cy), iw = NUM2INT(w), ih = NUM2INT(h); int is = NUM2INT(s), ie = NUM2INT(e), ic = NUM2INT(c); gdImageArc(get_iptr(img), icx, icy, iw, ih, is, ie, ic); return img; } static VALUE img_fill(img, x, y, c) VALUE img, x, y, c; { int ix = NUM2INT(x), iy = NUM2INT(y), ic = NUM2INT(c); gdImageFill(get_iptr(img), ix, iy, ic); return img; } static VALUE img_fill_to_border(img, x, y, b, c) VALUE img, x, y, b, c; { int ix = NUM2INT(x), iy = NUM2INT(y), ib = NUM2INT(b), ic = NUM2INT(c); gdImageFillToBorder(get_iptr(img), ix, iy, ib, ic); return img; } static VALUE img_copy(img, img2, dx, dy, sx, sy, w, h) VALUE img, img2, dx, dy, sx, sy, w, h; { gdImagePtr im, im2; int idx = NUM2INT(dx), idy = NUM2INT(dy); int isx = NUM2INT(sx), isy = NUM2INT(sy); int iw = NUM2INT(w), ih = NUM2INT(h); im = get_iptr(img); im2 = get_iptr(img2); #ifdef ENABLE_GD_2_0 if (is_truecolor(im) && (!is_truecolor(im2))){ rb_raise(rb_eRuntimeError, "Copying truecolor image to palette image is not permitted"); } #endif gdImageCopy(im2, im, idx, idy, isx, isy, iw, ih); return img; } static VALUE img_copy_resized(img, img2, dx, dy, sx, sy, dw, dh, sw, sh) VALUE img, img2, dx, dy, sx, sy, dw, dh, sw, sh; { gdImagePtr im, im2; int idx = NUM2INT(dx), idy = NUM2INT(dy); int isx = NUM2INT(sx), isy = NUM2INT(sy); int idw = NUM2INT(dw), idh = NUM2INT(dh); int isw = NUM2INT(sw), ish = NUM2INT(sh); im = get_iptr(img); im2 = get_iptr(img2); #ifdef ENABLE_GD_2_0 if (is_truecolor(im) && (!is_truecolor(im2))){ rb_raise(rb_eRuntimeError, "Copying truecolor image to palette image is not permitted"); } #endif gdImageCopyResized(im2, im, idx, idy, isx, isy, idw, idh, isw, ish); return img; } static VALUE img_copy_merge(img, img_dest, dx, dy, sx, sy, w, h, pct) VALUE img, img_dest, dx, dy, sx, sy, w, h, pct; { gdImagePtr im, im_dest; int idx = NUM2INT(dx), idy = NUM2INT(dy); int isx = NUM2INT(sx), isy = NUM2INT(sy); int iw = NUM2INT(w), ih = NUM2INT(h), p = NUM2INT(pct); im = get_iptr(img); im_dest = get_iptr(img_dest); #ifdef ENABLE_GD_2_0 if (is_truecolor(im) && (!is_truecolor(im_dest))){ rb_raise(rb_eRuntimeError, "Copying truecolor image to palette image is not permitted"); } #endif gdImageCopyMerge(im_dest, im, idx, idy, isx, isy, iw, ih, p); return img; } static VALUE img_copy_merge_gray(img, img_dest, dx, dy, sx, sy, w, h, pct) VALUE img, img_dest, dx, dy, sx, sy, w, h, pct; { gdImagePtr im, im_dest; int idx = NUM2INT(dx), idy = NUM2INT(dy); int isx = NUM2INT(sx), isy = NUM2INT(sy); int iw = NUM2INT(w), ih = NUM2INT(h), p = NUM2INT(pct); im = get_iptr(img); im_dest = get_iptr(img_dest); #ifdef ENABLE_GD_2_0 if (is_truecolor(im) && (!is_truecolor(im_dest))){ rb_raise(rb_eRuntimeError, "Copying truecolor image to palette image is not permitted"); } #endif gdImageCopyMergeGray(im_dest, im, idx, idy, isx, isy, iw, ih, p); return img; } static VALUE img_palette_copy(img, img2) VALUE img, img2; { gdImagePaletteCopy(get_iptr(img), get_iptr(img2)); return img; } static void fnt_free(ptr) void *ptr; { } static gdFontPtr check_font(fnt) VALUE fnt; { if (TYPE(fnt) != T_DATA || RDATA(fnt)->dfree != fnt_free) { rb_raise(rb_eTypeError, "wrong argument type %s (expected GD::Font)", rb_obj_classname(fnt)); } return DATA_PTR(fnt); } static gdFontPtr get_font(fnt) VALUE fnt; { gdFontPtr f = check_font(fnt); if (!f) { rb_raise(rb_eTypeError, "uninitialized GD::Font"); } return f; } static VALUE img_string(img, fnt, x, y, str, c) VALUE img, fnt, x, y, str, c; { int xx = NUM2INT(x), yy = NUM2INT(y), cc = NUM2INT(c); char *s = StringValueCStr(str); gdImageString(get_iptr(img), get_font(fnt), xx, yy, s, cc); return img; } static VALUE img_string_up(img, fnt, x, y, str, c) VALUE img, fnt, x, y, str, c; { int xx = NUM2INT(x), yy = NUM2INT(y), cc = NUM2INT(c); char *s = StringValueCStr(str); gdImageStringUp(get_iptr(img), get_font(fnt), xx, yy, s, cc); return img; } #if defined HAVE_GDIMAGESTRINGTTF || defined HAVE_GDIMAGESTRINGFT struct image_string_arg { int fgcolor; int x; int y; double ptsize; double angle; char *fontname; char *string; }; static void image_string_prepare(arg, fgcolor, fontname, ptsize, angle, x, y, string) struct image_string_arg *arg; VALUE fgcolor, *fontname, ptsize, angle, x, y, *string; { arg->fgcolor = NUM2INT(fgcolor); arg->ptsize = NUM2DBL(ptsize); arg->angle = NUM2DBL(angle); arg->x = NUM2INT(x); arg->y = NUM2INT(y); StringValueCStr(*fontname); arg->string = StringValuePtr(*string); arg->fontname = RSTRING(*fontname)->ptr; } static VALUE bound_rect(brect) int brect[8]; { VALUE ary = rb_ary_new2(8); int i; for (i=0; i<8; i++) { rb_ary_push(ary, INT2FIX(brect[i])); } return ary; } #endif #ifdef HAVE_GDIMAGESTRINGTTF static VALUE img_s_string_ttf(klass, fgcolor, fontname, ptsize, angle, x, y, string) VALUE klass, fgcolor, fontname, ptsize, angle, x, y, string; { struct image_string_arg arg; int brect[8]; char *msg; image_string_prepare(&arg, fgcolor, &fontname, ptsize, angle, x, y, &string); msg = gdImageStringTTF(NULL, brect, arg.fgcolor, arg.fontname, arg.ptsize, arg.angle, arg.x, arg.y, arg.string); if (msg) rb_raise(rb_eRuntimeError, msg); return bound_rect(brect); } static VALUE img_string_ttf(img, fgcolor, fontname, ptsize, angle, x, y, string) VALUE img, fgcolor, fontname, ptsize, angle, x, y, string; { struct image_string_arg arg; int brect[8]; char *msg; image_string_prepare(&arg, fgcolor, &fontname, ptsize, angle, x, y, &string); msg = gdImageStringTTF(get_iptr(img), brect, arg.fgcolor, arg.fontname, arg.ptsize, arg.angle, arg.x, arg.y, arg.string); if (msg) rb_raise(rb_eRuntimeError, msg); return bound_rect(brect); } #endif /* HAVE_GDIMAGESTRINGTTF */ #ifdef HAVE_GDIMAGESTRINGFT static VALUE img_s_string_ft(klass, fgcolor, fontname, ptsize, angle, x, y, string) VALUE klass, fgcolor, fontname, ptsize, angle, x, y, string; { struct image_string_arg arg; int brect[8]; char *msg; image_string_prepare(&arg, fgcolor, &fontname, ptsize, angle, x, y, &string); msg = gdImageStringFT(NULL, brect, arg.fgcolor, arg.fontname, arg.ptsize, arg.angle, arg.x, arg.y, arg.string); if (msg) rb_raise(rb_eRuntimeError, msg); return bound_rect(brect); } static VALUE img_string_ft(img, fgcolor, fontname, ptsize, angle, x, y, string) VALUE img, fgcolor, fontname, ptsize, angle, x, y, string; { struct image_string_arg arg; int brect[8]; char *msg; image_string_prepare(&arg, fgcolor, &fontname, ptsize, angle, x, y, &string); msg = gdImageStringFT(get_iptr(img), brect, arg.fgcolor, arg.fontname, arg.ptsize, arg.angle, arg.x, arg.y, arg.string); if (msg) rb_raise(rb_eRuntimeError, msg); return bound_rect(brect); } #endif /* HAVE_GDIMAGESTRINGFT */ static VALUE img_char(img, fnt, x, y, ch, c) VALUE img, fnt, x, y, ch, c; { int ix = NUM2INT(x), iy = NUM2INT(y), ich = NUM2CHR(ch), ic = NUM2INT(c); gdImageChar(get_iptr(img), get_font(fnt), ix, iy, ich, ic); return img; } static VALUE img_char_up(img, fnt, x, y, ch, c) VALUE img, fnt, x, y, ch, c; { int ix = NUM2INT(x), iy = NUM2INT(y), ich = NUM2CHR(ch), ic = NUM2INT(c); gdImageCharUp(get_iptr(img), get_font(fnt), ix, iy, ich, ic); return img; } static VALUE img_get_interlace(img) VALUE img; { if (gdImageGetInterlaced(get_iptr(img))) { return Qtrue; } return Qfalse; } static VALUE img_set_interlace(img, val) { gdImageInterlace(get_iptr(img), RTEST(val)); return img; } static VALUE img_bounds(img) VALUE img; { gdImagePtr im; VALUE ary = rb_ary_new2(2); int x, y; im = get_iptr(img); x = gdImageSX(im); y = gdImageSY(im); rb_ary_push(ary, INT2FIX(x)); rb_ary_push(ary, INT2FIX(y)); return ary; } static VALUE img_bounds_safe(img, x, y) VALUE img, x, y; { int ix = NUM2INT(x), iy = NUM2INT(y); if (gdImageBoundsSafe(get_iptr(img), ix, iy)) { return Qtrue; } else { return Qfalse; } } static VALUE img_get_transparent(img) VALUE img; { int t = gdImageGetTransparent(get_iptr(img)); return INT2NUM(t); } static VALUE img_width(img) VALUE img; { int i = gdImageSX(get_iptr(img)); return INT2FIX(i); } static VALUE img_height(img) VALUE img; { int i = gdImageSY(get_iptr(img)); return INT2FIX(i); } static VALUE img_png(img, out) VALUE img, out; { FILE *f; f = writable_fptr(get_fptr(&out)); gdImagePng(get_iptr(img), f); return img; } static VALUE img_png_str(img) VALUE img; { int size; void *ptr; VALUE imageString; ptr = gdImagePngPtr(get_iptr(img), &size); imageString = rb_str_new(ptr, size); #ifdef ENABLE_GD_2_0 gdFree(ptr); #else free(ptr); #endif return imageString; } static VALUE img_gd(img, out) VALUE img, out; { FILE *f; f = writable_fptr(get_fptr(&out)); gdImageGd(get_iptr(img), f); return img; } static VALUE img_gd2(img, out, cs, fmt) VALUE img, out, cs, fmt; { FILE *f; int ics = NUM2INT(cs), ifmt = NUM2INT(fmt); f = writable_fptr(get_fptr(&out)); gdImageGd2(get_iptr(img), f, ics, ifmt); return img; } #ifdef HAVE_GDIMAGECREATEFROMJPEG static VALUE img_jpeg(img, out, quality) VALUE img, out, quality; { FILE *f; int q = NUM2INT(quality); f = writable_fptr(get_fptr(&out)); gdImageJpeg(get_iptr(img), f, q); return img; } static VALUE img_jpeg_str(img, quality) VALUE img, quality; { int size, q = NUM2INT(quality); void *ptr; VALUE imageString; ptr = gdImageJpegPtr(get_iptr(img), &size, q); imageString = rb_str_new(ptr, size); #ifdef ENABLE_GD_2_0 gdFree(ptr); #else free(ptr); #endif return imageString; } #endif static VALUE img_wbmp(img, fg, out) VALUE img, out, fg; { FILE *f; int c = NUM2INT(fg); f = writable_fptr(get_fptr(&out)); gdImageWBMP(get_iptr(img), c, f); return img; } /* * * Poligon * */ static VALUE ply_s_alloc(klass) VALUE klass; { return Data_Wrap_Struct(cPolygon, 0, poly_free, 0); } #if !HAVE_RB_DEFINE_ALLOC_FUNC static VALUE ply_new(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE ply = ply_s_alloc(klass); rb_obj_call_init(ply, argc, argv); return ply; } #endif static struct polygon * ply_resize(ptr, size) struct polygon *ptr; int size; { int ns, len, x0, y0, i; gdPointPtr p; if (!ptr && !size) return ptr; if (!size) { xfree(ptr); return 0; } if (ptr) { if (ptr->capa >= size && ptr->capa - size < 1024) return ptr; len = ptr->len; } else { len = 0; } if (size > 1024) { ns = (size + 1023 / 1024) * 1024; } else { for (ns = 16; ns < size; ns <<= 1); } ptr = xrealloc(ptr, offsetof(struct polygon, pnt) + ns * sizeof(gdPoint)); if (len) { x0 = ptr->pnt[0].x; y0 = ptr->pnt[0].y; } else { x0 = y0 = 0; } for (i = len; i < size; i++) { p = &ptr->pnt[i]; p->x = x0; p->y = y0; } ptr->capa = ns; ptr->len = size; return ptr; } static VALUE xy_value(ary) VALUE ary; { ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); if (RARRAY(ary)->len != 2) { rb_raise(rb_eArgError, "wrong number of coordinate"); } return ary; } static VALUE ply_insert_pts(argc, argv, ply, pos) int argc; VALUE *argv; VALUE ply; int pos; { struct polygon *ptr; VALUE ary, vx, vy; int i, x, y; if (pos < 0) pos += ptr ? ptr->len + 1 : 1; DATA_PTR(ply) = ptr = ply_resize(ptr, pos + argc); for (i = 0; i < argc; ++i) { ary = xy_value(argv[i]); vx = RARRAY(ary)->ptr[0]; vy = RARRAY(ary)->ptr[1]; x = NUM2INT(vx); y = NUM2INT(vy); if (!(ptr = DATA_PTR(ply)) || pos >= ptr->capa) { DATA_PTR(ply) = ptr = ply_resize(ptr, pos + argc - i); } ptr->pnt[pos].x = x; ptr->pnt[pos].y = y; ptr->len = ++pos; } return ply; } static VALUE ply_to_pts(argc, argv, ply) int argc; VALUE *argv; VALUE ply; { struct polygon *ptr = get_poly(ply); VALUE ary, vx, vy; int i, pos = 0, x = 0, y = 0; if (ptr) pos = ptr->len; DATA_PTR(ply) = ptr = ply_resize(ptr, pos + argc); if (ptr && ptr->len) { x = ptr->pnt[0].x; y = ptr->pnt[0].y; } for (i = 0; i < argc; ++i) { ary = xy_value(argv[i]); vx = RARRAY(ary)->ptr[0]; vy = RARRAY(ary)->ptr[1]; x += NUM2INT(vx); y += NUM2INT(vy); if (!(ptr = DATA_PTR(ply)) || pos >= ptr->capa) { DATA_PTR(ply) = ptr = ply_resize(ptr, pos + argc - i); } ptr->pnt[pos].x = x; ptr->pnt[pos].y = y; ptr->len = ++pos; } return ply; } static VALUE ply_init_copy(ply, orig) VALUE ply, orig; { struct polygon *ptr = get_poly(ply), *ptr2 = get_poly(orig); if (ply == orig || ptr == ptr2) { /* nothing to do */ } if (!ptr2 || !ptr2->len) { xfree(ptr); DATA_PTR(ply) = 0; } else { DATA_PTR(ply) = ptr = ply_resize(ptr, ptr2->len); memcpy(ptr, ptr2, offsetof(struct polygon, pnt) + ptr2->len * sizeof(gdPoint)); } return ply; } static VALUE ply_init(argc, argv, ply) int argc; VALUE *argv; VALUE ply; { if (argc == 1 && is_poly(argv[0])) { ply_init_copy(ply, argv[0]); } else if (argc) { ply_insert_pts(argc, argv, ply, 0); } return ply; } static VALUE ply_add_pts(argc, argv, ply) int argc; VALUE *argv; VALUE ply; { return ply_insert_pts(argc, argv, ply, -1); } static VALUE ply_add_pt(ply, x, y) VALUE ply, x, y; { int n = 0, xx = NUM2INT(x), yy = NUM2INT(y); struct polygon *ptr = get_poly(ply); gdPointPtr p; if (!ptr || (n = ptr->len) >= ptr->capa) { DATA_PTR(ply) = ptr = ply_resize(ptr, n + 1); } p = &ptr->pnt[n]; p->x = xx; p->y = yy; ptr->len++; return ply; } static VALUE ply_add(ply, pt) VALUE ply, pt; { pt = xy_value(pt); return ply_add_pt(ply, RARRAY(pt)->ptr[0], RARRAY(pt)->ptr[1]); } static VALUE ply_to_pt(ply, dx, dy) VALUE ply, dx, dy; { int n = 0, xx = NUM2INT(dx), yy = NUM2INT(dy); struct polygon *ptr = get_poly(ply); gdPointPtr p; if (!ptr || (n = ptr->len) >= ptr->capa) { DATA_PTR(ply) = ptr = ply_resize(ptr, n + 1); } if (n > 0) { xx += ptr->pnt[n - 1].x; yy += ptr->pnt[n - 1].y; } p = &ptr->pnt[n]; p->x = xx; p->y = yy; ptr->len++; return ply; } static VALUE ply_move(ply, pt) VALUE ply, pt; { pt = xy_value(pt); return ply_to_pt(ply, RARRAY(pt)->ptr[0], RARRAY(pt)->ptr[1]); } static VALUE ply_get_pt(ply, idx) VALUE ply, idx; { int i = NUM2INT(idx); struct polygon *ptr = get_poly(ply); gdPointPtr p; if (!ptr || i >= ptr->len) return Qnil; p = &ptr->pnt[i]; return rb_assoc_new(INT2FIX(p->x), INT2FIX(p->y)); } static VALUE ply_subseq(ply, beg, len) VALUE ply, beg, len; { VALUE ply2; struct polygon *ptr = get_poly(ply), *ptr2; if (beg > ptr->len) return Qnil; if (beg < 0 || len < 0) return Qnil; if (beg + len > ptr->len) { len = ptr->len - beg; if (len < 0) len = 0; } ply2 = ply_s_alloc(rb_obj_class(ply)); if (len > 0) { DATA_PTR(ply2) = ptr2 = ply_resize(0, len); ptr2->len = len; MEMCPY(ptr2->pnt, ptr->pnt + beg, gdPoint, len); } return ply2; } static VALUE ply_aref(argc, argv, ply) int argc; VALUE *argv; VALUE ply; { VALUE arg; long beg, len; if (argc == 2) { beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); if (beg < 0) { beg += get_poly(ply)->len; } return ply_subseq(ply, beg, len); } if (argc != 1) { rb_scan_args(argc, argv, "11", 0, 0); } arg = argv[0]; /* special case - speeding up */ if (FIXNUM_P(arg)) { return ply_get_pt(ply, arg); } /* check if idx is Range */ switch (rb_range_beg_len(arg, &beg, &len, get_poly(ply)->len, 0)) { case Qfalse: break; case Qnil: return Qnil; default: return ply_subseq(ply, beg, len); } return ply_get_pt(ply, arg); } static VALUE ply_set(ply, i, x, y) VALUE ply; int i, x, y; { struct polygon *ptr = get_poly(ply); gdPointPtr p; if (!ptr || i >= ptr->capa) { DATA_PTR(ply) = ptr = ply_resize(ptr, i); } p = &ptr->pnt[i]; p->x = x; p->y = y; ptr->len = i + 1; return ply; } static VALUE ply_set_pt(ply, idx, x, y) VALUE ply, idx, x, y; { int i = NUM2INT(idx), xx = NUM2INT(x), yy = NUM2INT(y); return ply_set(ply, i, xx, yy); } static VALUE ply_aset(argc, argv, ply) int argc; VALUE *argv; VALUE ply; { long offset, beg, len, i, n, plen = -1; VALUE pt, x, y, ary; gdPointPtr rhs; struct polygon *ptr; if (argc == 3) { beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); pt = argv[2]; } else if (argc != 2) { rb_scan_args(argc, argv, "2", 0, 0); } else if (FIXNUM_P(argv[0])) { offset = FIX2LONG(argv[0]); fixnum: pt = xy_value(argv[1]); x = RARRAY(pt)->ptr[0]; y = RARRAY(pt)->ptr[1]; return ply_set(ply, offset, NUM2INT(x), NUM2INT(y)); } else { plen = 0; if (ptr = get_poly(ply)) plen = ptr->len; if (!rb_range_beg_len(argv[0], &beg, &len, plen, 2)) { offset = NUM2LONG(argv[0]); goto fixnum; } } ary = rb_convert_type(argv[1], T_ARRAY, "Array", "to_ary"); n = RARRAY(ary)->len; rhs = ALLOCA_N(gdPoint, n); for (i = 0; i < n && i < RARRAY(ary)->len; i++) { pt = xy_value(RARRAY(ary)->ptr[i]); x = RARRAY(pt)->ptr[0]; y = RARRAY(pt)->ptr[1]; rhs[i].x = NUM2INT(x); rhs[i].y = NUM2INT(y); } ptr = get_poly(ply); n = plen; plen = ptr ? ptr->len : 0; if (n >= 0 && n != plen) { rb_range_beg_len(argv[0], &beg, &len, plen, 2); } if (len < i) { DATA_PTR(ply) = ptr = ply_resize(ptr, plen + i - len); MEMMOVE(&ptr->pnt[beg+len], &ptr->pnt[beg+i], gdPoint, plen - len - beg); ptr->len += i - len; } MEMCPY(&ptr->pnt[beg], rhs, gdPoint, i); return argv[1]; } static VALUE ply_delete_pt(ply, idx) VALUE ply, idx; { int i = NUM2INT(idx); struct polygon *ptr = get_poly(ply); if (ptr && i < ptr->len) { MEMCPY(&ptr->pnt[i], &ptr->pnt[i+1], gdPoint, --ptr->len - i); DATA_PTR(ply) = ptr = ply_resize(ptr, ptr->len); } return ply; } static VALUE ply_inspect(ply) VALUE ply; { struct polygon *ptr = get_poly(ply); VALUE str = rb_call_super(0, 0); int i; char buf[50]; if (ptr) { RSTRING(str)->ptr[RSTRING(str)->len-1] = ' '; snprintf(buf, sizeof(buf), "[%d, %d]", ptr->pnt[i].x, ptr->pnt[i].y); rb_str_cat2(str, buf); for (i = 1; i < ptr->len; ++i) { snprintf(buf, sizeof(buf), ", [%d, %d]", ptr->pnt[i].x, ptr->pnt[i].y); rb_str_cat2(str, buf); } rb_str_cat2(str, ">"); } return str; } static VALUE ply_length(ply) VALUE ply; { struct polygon *ptr = get_poly(ply); if (!ptr) return INT2FIX(0); return INT2FIX(ptr->len); } static VALUE ply_vertices(ply) VALUE ply; { int i; struct polygon *ptr = get_poly(ply); VALUE ary; ary = rb_ary_new2(ptr ? ptr->len : 0); for (i = 0; (ptr = DATA_PTR(ply)) && i < ptr->len; i++) { int x = ptr->pnt[i].x, y = ptr->pnt[i].y; rb_ary_push(ary, rb_assoc_new(INT2FIX(x), INT2FIX(y))); } return ary; } static VALUE ply_bounds(ply) VALUE ply; { int i, l, t, r, b; int nx, ny; struct polygon *ptr = get_poly(ply); if (!ptr || !ptr->len) { l = t = r = b = 0; } else { l = r = ptr->pnt[0].x; t = b = ptr->pnt[0].y; } for (i = 1; i < ptr->len; i++) { nx = ptr->pnt[i].x; ny = ptr->pnt[i].y; if (nx < l) l = nx; if (nx > r) r = nx; if (ny < t) t = ny; if (ny > b) b = ny; } return rb_ary_new3(4, INT2FIX(l), INT2FIX(t), INT2FIX(r), INT2FIX(b)); } static VALUE ply_offset(ply, vx, vy) VALUE ply; VALUE vx, vy; { int i; int x = NUM2INT(vx); int y = NUM2INT(vy); struct polygon *ptr = get_poly(ply); if (!ptr) return ply; for (i = 0; i < ptr->len; i++) { ptr->pnt[i].x += x; ptr->pnt[i].y += y; } return ply; } static VALUE ply_map(argc, argv, ply) int argc; VALUE *argv; VALUE ply; { VALUE sl, st, sr, sb, dl, dt, dr, db; int sx, sy, dx, dy; double xmag, ymag; int i, nx, ny; struct polygon *ptr; i = rb_scan_args(argc,argv,"44",&sl,&st,&sr,&sb, &dl,&dt,&dr,&db); if (i == 4) { int l, t, r, b; dx = NUM2INT(sl); dy = NUM2INT(st); xmag = (double)(NUM2INT(sr) - NUM2INT(sl)); ymag = (double)(NUM2INT(sb) - NUM2INT(st)); ptr = get_poly(ply); if (!ptr || !ptr->len) return ply; l = r = ptr->pnt[0].x; t = b = ptr->pnt[0].y; for (i = 1; i < ptr->len; i++) { nx = ptr->pnt[i].x; ny = ptr->pnt[i].y; if (nx < l) l = nx; if (nx > r) r = nx; if (ny < t) t = ny; if (ny > b) b = ny; } sx = l; sy = t; xmag /= r - l; ymag /= b - t; } else if (i == 8) { sx = NUM2INT(sl); sy = NUM2INT(st); dx = NUM2INT(dl); dy = NUM2INT(dt); xmag = (double)(NUM2INT(dr) - NUM2INT(dl))/ (double)(NUM2INT(sr) - NUM2INT(sl)); ymag = (double)(NUM2INT(db) - NUM2INT(dt))/ (double)(NUM2INT(sb) - NUM2INT(st)); ptr = get_poly(ply); if (!ptr || !ptr->len) return ply; } else { rb_raise(rb_eArgError, "wrong # of arguments (%d for 4 or 8)", argc); } for (i = 0; i < ptr->len; i++) { gdPointPtr p = &ptr->pnt[i]; p->x = (p->x - sx) * xmag + dx; p->y = (p->y - sy) * ymag + dy; } return ply; } static VALUE ply_transform0(ply, a, b, c, d, tx, ty) VALUE ply; double a, b, c, d; int tx, ty; { int i, x, y; struct polygon *ptr = get_poly(ply); if (!ptr || !ptr->len) return ply; for (i = 0; i < ptr->len; i++) { gdPointPtr p = &ptr->pnt[i]; x = p->x; y = p->y; p->x = a * x + c * y + tx; p->y = b * x + d * y + ty; } return ply; } static VALUE ply_transform(ply, a, b, c, d, tx, ty) VALUE ply, a, b, c, d, tx, ty; { return ply_transform0(ply, NUM2DBL(a), NUM2DBL(b), NUM2DBL(c), NUM2DBL(d), NUM2INT(tx), NUM2INT(ty)); } static VALUE ply_scale(ply, sx, sy) VALUE ply, sx, sy; { double dx = NUM2DBL(sx), dy = NUM2DBL(sy); struct polygon *ptr = get_poly(ply); int i; if (!ptr || !ptr->len) return ply; for (i = 0; i < ptr->len; i++) { gdPointPtr p = &ptr->pnt[i]; p->x *= dx; p->y *= dy; } return ply; } static VALUE fnt_s_alloc(klass) VALUE klass; { return Data_Wrap_Struct(klass, 0, fnt_free, 0); } static VALUE fnt_create(f) gdFontPtr f; { return Data_Wrap_Struct(cFont, 0, fnt_free, f); } static gdFontPtr fnt_map(name) char *name; { switch (*name) { case 'G': if (strcmp(name+1, "iant") == 0) { return gdFontGiant; } break; case 'L': if (strcmp(name+1, "arge") == 0) { return gdFontLarge; } break; case 'M': if (strcmp(name+1, "edium") == 0) { return gdFontMediumBold; } break; case 'S': if (strcmp(name+1, "mall") == 0) { return gdFontSmall; } break; case 'T': if (strcmp(name+1, "iny") == 0) { return gdFontTiny; } break; } rb_raise(rb_eArgError, "undefined font name `%s'", name); } static VALUE fnt_init(fnt, name) VALUE fnt, name; { check_font(fnt); DATA_PTR(fnt) = fnt_map(StringValuePtr(name)); return fnt; } static VALUE fnt_init_copy(fnt, fnt2) VALUE fnt, fnt2; { check_font(fnt); DATA_PTR(fnt) = get_font(fnt2); return fnt; } #if !HAVE_RB_DEFINE_ALLOC_FUNC static VALUE fnt_s_new(argc, argv, klass) int argc; VALUE *argv; VALUE klass; { VALUE fnt = fnt_s_alloc(klass); rb_obj_call_init(fnt, argc, argv); return fnt; } #endif static VALUE fnt_nchars(fnt) VALUE fnt; { gdFontPtr fp = get_font(fnt); return INT2FIX(fp->nchars); } static VALUE fnt_offset(fnt) VALUE fnt; { gdFontPtr fp = get_font(fnt); return INT2FIX(fp->offset); } static VALUE fnt_width(fnt) VALUE fnt; { gdFontPtr fp = get_font(fnt); return INT2FIX(fp->w); } static VALUE fnt_height(fnt) VALUE fnt; { gdFontPtr fp = get_font(fnt); return INT2FIX(fp->h); } /* * * gd-2.0.x features : experimental * */ #ifdef ENABLE_GD_2_0 static VALUE img_s_new_tc(klass, sx, sy) VALUE klass, sx, sy; { gdImagePtr iptr; int x = NUM2INT(sx), y = NUM2INT(sy); if (x<0 || y<0) rb_raise(rb_eArgError, "Negative width/height not allowed"); iptr = gdImageCreateTrueColor(x, y); if (!iptr) rb_raise(rb_eRuntimeError, "Unable to allocate the new image"); return img_init(klass, iptr); } static VALUE img_color_allocate_alpha_tri(img, r, g, b, a) VALUE img, r, g, b, a; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b), aa = NUM2INT(a); c = gdImageColorAllocateAlpha(get_iptr(img), rr, gg, bb, aa); return INT2NUM(c); } static VALUE img_color_allocate_alpha_str(img, rgbstr, a) VALUE img, rgbstr, a; { int c, aa; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); aa = NUM2INT(a); c = gdImageColorAllocateAlpha(get_iptr(img), rgb[0], rgb[1], rgb[2], aa); return INT2NUM(c); } static VALUE img_color_allocate_alpha(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, a, retval; if (!(argc == 2 || argc == 4)) rb_raise(rb_eArgError, "Wrong # of arguments (2 or 4 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "20", &rgbstr, &a); retval = img_color_allocate_alpha_str(img, rgbstr, a); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "40", &r, &g, &b, &a); retval = img_color_allocate_alpha_tri(img, r, g, b, a); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_color_resolve_alpha_tri(img, r, g, b, a) VALUE img, r, g, b, a; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b), aa = NUM2INT(a); c = gdImageColorResolveAlpha(get_iptr(img), rr, gg, bb, aa); return INT2NUM(c); } static VALUE img_color_resolve_alpha_str(img, rgbstr, a) VALUE img, rgbstr, a; { int c, aa; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); aa = NUM2INT(a); c = gdImageColorResolveAlpha(get_iptr(img), rgb[0], rgb[1], rgb[2], aa); return INT2NUM(c); } static VALUE img_color_resolve_alpha(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, a, retval; if (!(argc == 2 || argc == 4)) rb_raise(rb_eArgError, "Wrong # of arguments (2 or 4 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "20", &rgbstr, &a); retval = img_color_resolve_alpha_str(img, rgbstr, a); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "40", &r, &g, &b, &a); retval = img_color_resolve_alpha_tri(img, r, g, b, a); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_color_closest_alpha_tri(img, r, g, b, a) VALUE img, r, g, b, a; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b), aa = NUM2INT(a); c = gdImageColorClosestAlpha(get_iptr(img), rr, gg, bb, aa); return INT2NUM(c); } static VALUE img_color_closest_alpha_str(img, rgbstr, a) VALUE img, rgbstr, a; { int c, aa; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); aa = NUM2INT(a); c = gdImageColorClosestAlpha(get_iptr(img), rgb[0], rgb[1], rgb[2], aa); return INT2NUM(c); } static VALUE img_color_closest_alpha(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, a, retval; if (!(argc == 2 || argc == 4)) rb_raise(rb_eArgError, "Wrong # of arguments (2 or 4 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "20", &rgbstr, &a); retval = img_color_closest_alpha_str(img, rgbstr, a); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "40", &r, &g, &b, &a); retval = img_color_closest_alpha_tri(img, r, g, b, a); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_color_exact_alpha_tri(img, r, g, b, a) VALUE img, r, g, b, a; { int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b), aa = NUM2INT(a); c = gdImageColorExactAlpha(get_iptr(img), rr, gg, bb, aa); return INT2NUM(c); } static VALUE img_color_exact_alpha_str(img, rgbstr, a) VALUE img, rgbstr, a; { int c, aa; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); aa = NUM2INT(a); c = gdImageColorExactAlpha(get_iptr(img), rgb[0], rgb[1], rgb[2], aa); return INT2NUM(c); } static VALUE img_color_exact_alpha(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, a, retval; if (!(argc == 2 || argc == 4)) rb_raise(rb_eArgError, "Wrong # of arguments (2 or 4 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "20", &rgbstr, &a); retval = img_color_exact_alpha_str(img, rgbstr, a); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "40", &r, &g, &b, &a); retval = img_color_exact_alpha_tri(img, r, g, b, a); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_alpha_blending(img, blending_mode) VALUE img, blending_mode; { gdImageAlphaBlending(get_iptr(img), RTEST(blending_mode)); return img; } static VALUE img_alpha(img, color) VALUE img, color; { int a = gdImageAlpha(get_iptr(img), NUM2INT(color)); return INT2NUM(a); } static VALUE img_s_truecolor_str(rgbstr) VALUE rgbstr; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdTrueColor(rgb[0], rgb[1], rgb[2]); return INT2NUM(c); } static VALUE img_s_truecolor_tri(r, g, b) VALUE r, g, b; { int c; c = gdTrueColor(NUM2INT(r), NUM2INT(g), NUM2INT(b)); return INT2NUM(c); } static VALUE img_s_truecolor(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, retval; if (!(argc == 1 || argc == 3)) rb_raise(rb_eArgError, "Wrong # of arguments (1 or 3 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "10", &rgbstr); retval = img_s_truecolor_str(rgbstr); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "30", &r, &g, &b); retval = img_s_truecolor_tri(r, g, b); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_s_truecolor_alpha_str(rgbstr, a) VALUE rgbstr, a; { int c; unsigned int rgb[3]; hex2triplet(rgbstr, rgb); c = gdTrueColorAlpha(rgb[0], rgb[1], rgb[2], NUM2INT(a)); return INT2NUM(c); } static VALUE img_s_truecolor_alpha_tri(r, g, b, a) VALUE r, g, b, a; { int c; c = gdTrueColorAlpha(NUM2INT(r), NUM2INT(g), NUM2INT(b), NUM2INT(a)); return INT2NUM(c); } static VALUE img_s_truecolor_alpha(argc, argv, img) int argc; VALUE *argv; VALUE img; { int i; VALUE rgbstr, r, g, b, a, retval; if (!(argc == 2 || argc == 4)) rb_raise(rb_eArgError, "Wrong # of arguments (2 or 4 for %d)", argc); switch(TYPE(argv[0])) { case T_STRING: i = rb_scan_args(argc, argv, "20", &rgbstr, &a); retval = img_s_truecolor_alpha_str(rgbstr, a); break; case T_FIXNUM: i = rb_scan_args(argc, argv, "40", &r, &g, &b, &a); retval = img_s_truecolor_alpha_tri(r, g, b, a); break; default: rb_raise(rb_eTypeError, "String or Fixnum expected"); break; } return retval; } static VALUE img_copy_resampled(img, img2, dx, dy, sx, sy, dw, dh, sw, sh) VALUE img, img2, dx, dy, sx, sy, dw, dh, sw, sh; { gdImagePtr im, im2; int idx = NUM2INT(dx), idy = NUM2INT(dy); int isx = NUM2INT(sx), isy = NUM2INT(sy); int idw = NUM2INT(dw), idh = NUM2INT(dh); int isw = NUM2INT(sw), ish = NUM2INT(sh); im = get_iptr(img); im2 = get_iptr(img2); if (is_truecolor(im) && (!is_truecolor(im2))){ rb_raise(rb_eRuntimeError, "Copying truecolor image to palette image is not permitted"); } gdImageCopyResampled(im2, im, idx, idy, isx, isy, idw, idh, isw, ish); return img; } static VALUE img_filled_ellipse(img, cx, cy, w, h, start, end, color) VALUE img, cx, cy, w, h, start, end, color; { int icx = NUM2INT(cx), icy = NUM2INT(cy), iw = NUM2INT(w), ih = NUM2INT(h), icolor = NUM2INT(color); gdImageFilledEllipse(get_iptr(img), icx, icy, iw, ih, icolor); return img; } static VALUE img_filled_arc(img, cx, cy, w, h, start, end, color, style) VALUE img, cx, cy, w, h, start, end, color, style; { int icx = NUM2INT(cx), icy = NUM2INT(cy), iw = NUM2INT(w), ih = NUM2INT(h); int istart = NUM2INT(start), iend = NUM2INT(end); int icolor = NUM2INT(color), istyle = NUM2INT(style); gdImageFilledArc(get_iptr(img), icx, icy, iw, ih, istart, iend, icolor, istyle); return img; } static VALUE img_is_truecolor_image(img) VALUE img; { return is_truecolor(get_iptr(img)) ? Qtrue : Qfalse; } static VALUE img_is_palette_image(img) VALUE img; { return is_truecolor(get_iptr(img)) ? Qfalse : Qtrue; } static VALUE img_to_palette_image(img, dither_flag, max_colors) VALUE img, dither_flag, max_colors; { int n = NUM2INT(max_colors); gdImageTrueColorToPalette(get_iptr(img), dither_flag, n); return img; } static VALUE img_set_thickness(img, thickness) VALUE img, thickness; { int t = NUM2INT(thickness); gdImageSetThickness(get_iptr(img), t); return img; } #endif /* ENABLE_GD_2_0 */ void Init_GD() { VALUE v; mGD = rb_define_module("GD"); v = rb_str_new2(RUBY_GD_VERSION); OBJ_FREEZE(v); rb_define_const(mGD, "VERSION", v); cImage = rb_define_class_under(mGD, "Image", rb_cObject); #if HAVE_RB_DEFINE_ALLOC_FUNC rb_define_alloc_func(cImage, img_s_alloc); #endif rb_define_singleton_method(cImage, "new", img_s_new, 2); rb_define_singleton_method(cImage, "newPalette", img_s_new, 2); rb_define_singleton_method(cImage, "newFromPng", img_from_png, 1); rb_define_singleton_method(cImage, "new_from_png", img_from_pngfname, 1); rb_define_singleton_method(cImage, "newFromXbm", img_from_xbm, 1); rb_define_singleton_method(cImage, "new_from_xbm", img_from_xbmfname, 1); rb_define_singleton_method(cImage, "newFromGd", img_from_gd, 1); rb_define_singleton_method(cImage, "new_from_gd", img_from_gdfname, 1); #ifdef HAVE_GDIMAGECREATEFROMXPM rb_define_singleton_method(cImage, "newFromXpm", img_from_xpm, 1); rb_define_singleton_method(cImage, "new_from_xpm", img_from_xpmfname, 1); #endif /* HAVE_GDIMAGECREATEFROMXPM */ rb_define_singleton_method(cImage, "newFromGd2", img_from_gd2, 1); rb_define_singleton_method(cImage, "new_from_gd2", img_from_gd2fname, 1); rb_define_singleton_method(cImage, "newFromGd2Part", img_from_gd2_part, 5); rb_define_singleton_method(cImage, "new_from_gd2_Part", img_from_gd2_partfname, 5); #ifdef HAVE_GDIMAGECREATEFROMJPEG rb_define_singleton_method(cImage, "newFromJpeg", img_from_jpeg, 1); rb_define_singleton_method(cImage, "new_from_jpeg", img_from_jpegfname, 1); #endif /* HAVE_GDIMAGECREATEFROMJPEG */ rb_define_method(cImage, "destroy", img_destroy, 0); rb_define_method(cImage, "colorAllocate", img_color_allocate, -1); rb_define_method(cImage, "colorDeallocate", img_color_deallocate, 1); rb_define_method(cImage, "colorClosest", img_color_closest, -1); rb_define_method(cImage, "colorClosestHWB", img_color_closestHWB, -1); rb_define_method(cImage, "colorExact", img_color_exact, -1); #ifdef HAVE_GDIMAGECOLORRESOLVE rb_define_method(cImage, "colorResolve", img_color_resolve, -1); #endif /* HAVE_GDIMAGECOLORRESOLVE */ rb_define_method(cImage, "colorsTotal", img_colors_total, 0); rb_define_method(cImage, "getPixel", img_get_pixel, 2); rb_define_method(cImage, "red", img_red, 1); rb_define_method(cImage, "green", img_green, 1); rb_define_method(cImage, "blue", img_blue, 1); rb_define_method(cImage, "rgb", img_rgb, 1); rb_define_method(cImage, "transparent", img_transparent, 1); rb_define_method(cImage, "setBrush", img_set_blush, 1); rb_define_const(mGD, "Brushed", INT2FIX(gdBrushed)); rb_define_method(cImage, "setStyle", img_set_style, -1); rb_define_const(mGD, "Styled", INT2FIX(gdStyled)); rb_define_const(mGD, "StyledBrushed", INT2FIX(gdStyledBrushed)); rb_define_method(cImage, "setTile", img_set_tile, 1); rb_define_const(mGD, "Tiled", INT2FIX(gdTiled)); rb_define_const(mGD, "Transparent", INT2FIX(gdTransparent)); rb_define_const(mGD, "GD2_FMT_COMPRESSED", INT2FIX(GD2_FMT_COMPRESSED)); rb_define_const(mGD, "GD2_FMT_RAW", INT2FIX(GD2_FMT_RAW)); rb_define_method(cImage, "setPixel", img_set_pixel, 3); rb_define_method(cImage, "line", img_line, 5); rb_define_method(cImage, "dashedLine", img_dashed_line, 5); rb_define_method(cImage, "rectangle", img_rectangle, 5); rb_define_method(cImage, "filledRectangle", img_filled_rectangle, 5); rb_define_method(cImage, "polygon", img_polygon, 2); rb_define_method(cImage, "filledPolygon", img_filled_polygon, 2); rb_define_method(cImage, "arc", img_arc, 7); rb_define_method(cImage, "fill", img_fill, 3); rb_define_method(cImage, "fillToBorder", img_fill_to_border, 4); rb_define_method(cImage, "line", img_line, 5); rb_define_method(cImage, "copy", img_copy, 7); rb_define_method(cImage, "copyResized", img_copy_resized, 9); rb_define_method(cImage, "copyMerge", img_copy_merge, 8); rb_define_method(cImage, "copyMergeGray", img_copy_merge_gray, 8); rb_define_method(cImage, "paletteCopy", img_palette_copy, 1); rb_define_method(cImage, "string", img_string, 5); rb_define_method(cImage, "stringUp", img_string_up, 5); #ifdef HAVE_GDIMAGESTRINGTTF rb_define_singleton_method(cImage, "stringTTF", img_s_string_ttf, 7); rb_define_method(cImage, "stringTTF", img_string_ttf, 7); #endif #ifdef HAVE_GDIMAGESTRINGFT rb_define_singleton_method(cImage, "stringFT", img_s_string_ft, 7); rb_define_method(cImage, "stringFT", img_string_ft, 7); #endif rb_define_method(cImage, "char", img_char, 5); rb_define_method(cImage, "charUp", img_char_up, 5); rb_define_method(cImage, "interlace", img_get_interlace, 0); rb_define_method(cImage, "interlace=", img_set_interlace, 1); rb_define_method(cImage, "getTransparent", img_get_transparent, 0); rb_define_method(cImage, "bounds", img_bounds, 0); rb_define_method(cImage, "boundsSafe", img_bounds_safe, 2); rb_define_method(cImage, "width", img_width, 0); rb_define_method(cImage, "height", img_height, 0); rb_define_method(cImage, "png", img_png, 1); rb_define_method(cImage, "pngStr", img_png_str, 0); rb_define_method(cImage, "gd2", img_gd2, 3); rb_define_method(cImage, "gd", img_gd, 1); #ifdef HAVE_GDIMAGECREATEFROMJPEG rb_define_method(cImage, "jpeg", img_jpeg, 2); rb_define_method(cImage, "jpegStr", img_jpeg_str, 1); #endif /* HAVE_GDIMAGECREATEFROMJPEG */ rb_define_method(cImage, "wbmp", img_wbmp, 2); cPolygon = rb_define_class_under(mGD, "Polygon", rb_cObject); #if HAVE_RB_DEFINE_ALLOC_FUNC rb_define_alloc_func(cPolygon, ply_s_alloc); #else rb_define_singleton_method(cPolygon, "new", ply_new, 0); #endif rb_define_method(cPolygon, "initialize", ply_init, -1); rb_define_method(cPolygon, "initialize_copy", ply_init_copy, 1); rb_define_method(cPolygon, "add", ply_add_pts, -1); rb_define_method(cPolygon, "to", ply_to_pts, -1); rb_define_method(cPolygon, "get", ply_get_pt, 1); rb_define_method(cPolygon, "[]", ply_aref, -1); rb_define_method(cPolygon, "[]=", ply_aset, -1); rb_define_method(cPolygon, "<<", ply_add, 1); rb_define_method(cPolygon, ">>", ply_move, 1); rb_define_method(cPolygon, "addPt", ply_add_pt, 2); rb_define_method(cPolygon, "toPt", ply_to_pt, 2); rb_define_method(cPolygon, "getPt", ply_get_pt, 1); rb_define_method(cPolygon, "setPt", ply_set_pt, 3); rb_define_method(cPolygon, "deletePt", ply_delete_pt, 1); rb_define_method(cPolygon, "length", ply_length, 0); rb_define_method(cPolygon, "vertices", ply_vertices, 0); rb_define_method(cPolygon, "bounds", ply_bounds, 0); rb_define_method(cPolygon, "offset", ply_offset, 2); rb_define_method(cPolygon, "map", ply_map, -1); rb_define_method(cPolygon, "transform", ply_transform, 6); rb_define_method(cPolygon, "scale", ply_scale, 2); rb_define_method(cPolygon, "inspect", ply_inspect, 0); cFont = rb_define_class_under(mGD, "Font", rb_cObject); #if HAVE_RB_DEFINE_ALLOC_FUNC rb_define_alloc_func(cFont, fnt_s_alloc); #else rb_define_singleton_method(cFont, "new", fnt_s_new, 1); #endif rb_define_method(cFont, "initialize", fnt_init, 1); rb_define_method(cFont, "initialize_copy", fnt_init_copy, 1); rb_define_const(cFont, "GiantFont", fnt_create(gdFontGiant)); rb_define_const(cFont, "SmallFont", fnt_create(gdFontSmall)); rb_define_const(cFont, "LargeFont", fnt_create(gdFontLarge)); rb_define_const(cFont, "MediumFont", fnt_create(gdFontMediumBold)); rb_define_const(cFont, "MediumBoldFont", fnt_create(gdFontMediumBold)); rb_define_const(cFont, "TinyFont", fnt_create(gdFontTiny)); rb_define_method(cFont, "nchars", fnt_nchars, 0); rb_define_method(cFont, "offset", fnt_offset, 0); rb_define_method(cFont, "width", fnt_width, 0); rb_define_method(cFont, "height", fnt_height, 0); #ifdef ENABLE_GD_2_0 rb_define_singleton_method(cImage, "newTrueColor", img_s_new_tc, 2); rb_define_method(cImage, "colorAllocateAlpha", img_color_allocate_alpha, -1); rb_define_method(cImage, "colorResolveAlpha", img_color_resolve_alpha, -1); rb_define_method(cImage, "colorClosestAlpha", img_color_closest_alpha, -1); rb_define_method(cImage, "colorExactAlpha", img_color_exact_alpha, -1); rb_define_method(cImage, "alphaBlending=", img_alpha_blending, 1); rb_define_method(cImage, "alpha", img_alpha, 1); rb_define_singleton_method(cImage, "trueColor", img_s_truecolor, -1); rb_define_singleton_method(cImage, "trueColorAlpha", img_s_truecolor_alpha, -1); rb_define_method(cImage, "copyResampled", img_copy_resampled, 9); rb_define_method(cImage, "filledEllipse", img_filled_ellipse, 7); rb_define_method(cImage, "filledArc", img_filled_arc, 8); rb_define_method(cImage, "is_trueColor?", img_is_truecolor_image, 0); rb_define_method(cImage, "is_palette?", img_is_palette_image, 0); rb_define_method(cImage, "to_paletteImage", img_to_palette_image, 2); rb_define_method(cImage, "thickness=", img_set_thickness, 1); rb_define_const(mGD, "AlphaTransparent", INT2FIX(gdAlphaTransparent)); rb_define_const(mGD, "AlphaOpaque", INT2FIX(gdAlphaOpaque)); rb_define_const(mGD, "Arc", INT2FIX(gdArc)); rb_define_const(mGD, "Chord", INT2FIX(gdChord)); rb_define_const(mGD, "Pie", INT2FIX(gdPie)); rb_define_const(mGD, "NoFill", INT2FIX(gdNoFill)); rb_define_const(mGD, "Edged", INT2FIX(gdEdged)); #endif /* ENABLE_GD_2_0 */ }