diff -rp -U2 ruby-GD-0.7.4/GD.c ruby-GD/GD.c
--- ruby-GD-0.7.4/GD.c	2001-05-30 23:14:17.000000000 +0900
+++ ruby-GD/GD.c	2004-12-26 11:25:50.000000000 +0900
@@ -4,7 +4,7 @@
 
   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 $
@@ -21,4 +21,13 @@
 #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* );
@@ -26,4 +35,11 @@ extern gdImagePtr gdImageCreateFromXpm(c
 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
@@ -35,4 +51,42 @@ is_truecolor(im)
 #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)
@@ -45,14 +99,72 @@ free_img(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 (NUM2INT(w)<0 || NUM2INT(h)<0)
+    if (ww < 0 || hh < 0)
     	rb_raise(rb_eArgError, "Negative width/height not allowed");
 
-    iptr = gdImageCreate(NUM2INT(w), NUM2INT(h));
-    return Data_Wrap_Struct(klass,0,free_img,iptr);
+    iptr = gdImageCreate(ww, hh);
+    return img_init(klass, iptr);
 }
 
@@ -62,20 +174,13 @@ img_from_pngfname(klass, fname)
     VALUE klass, fname;
 {
-    VALUE f;
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
 
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromPng(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -88,14 +193,10 @@ img_from_png(klass, f)
     gdImagePtr iptr;
 
-    Check_Type(f, T_FILE); 
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromPng(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -104,20 +205,13 @@ img_from_gdfname(klass, fname)
     VALUE klass, fname;
 {
-    VALUE f;
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
 
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromGd(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -129,13 +223,10 @@ img_from_gd(klass, f)
     gdImagePtr iptr;
 
-    Check_Type(f, T_FILE); 
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromGd(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -144,20 +235,13 @@ img_from_gd2fname(klass, fname)
     VALUE klass, fname;
 {
-    VALUE f;
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
 
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromGd2(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -169,57 +253,42 @@ img_from_gd2(klass, f)
     gdImagePtr iptr;
 
-    Check_Type(f, T_FILE);
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromGd2(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
 static VALUE
-img_from_gd2_partfname(klass, fname, srcx, srcy, w, h)
-    VALUE klass, fname, srcx, srcy, w, h;
+img_from_gd2_partfname(klass, fname, srcx, srcy, srcw, srch)
+    VALUE klass, fname, srcx, srcy, srcw, srch;
 {
-    VALUE f;
+    int x = NUM2INT(srcx), y = NUM2INT(srcy), w = NUM2INT(srcw), h = NUM2INT(srch);
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
 
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromGd2Part(fptr->f, NUM2INT(srcx),
-                                    NUM2INT(srcy), NUM2INT(w), NUM2INT(h));
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
 static VALUE
-img_from_gd2_part(klass, f, srcx, srcy, w, h)
-    VALUE klass, f, srcx, srcy, w, h;
+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;
 
-    Check_Type(f, T_FILE);
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromGd2Part(fptr->f, NUM2INT(srcx),
-                                   NUM2INT(srcy), NUM2INT(w), NUM2INT(h));
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -232,14 +301,10 @@ img_from_xbm(klass, f)
     gdImagePtr iptr;
 
-    Check_Type(f, T_FILE); 
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromXbm(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+    return img_init(klass, iptr);
 }
 
@@ -248,20 +313,13 @@ img_from_xbmfname(klass, fname)
     VALUE klass, fname;
 {
-    VALUE f;
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
-
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
 
-    iptr = gdImageCreateFromXbm(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -274,7 +332,5 @@ img_from_xpm(klass, f)
     gdImagePtr iptr;
 
-    Check_Type(f, T_FILE);
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
+    fptr = get_fptr(&f);
     rb_io_check_readable(fptr);
 
@@ -284,5 +340,5 @@ img_from_xpm(klass, f)
         rb_raise(rb_eArgError, "%s is not a valid XPM File", fptr->path);
 
-    return Data_Wrap_Struct(klass,0,free_img,iptr);
+    return img_init(klass, iptr);
 }
 
@@ -291,13 +347,8 @@ img_from_xpmfname(klass, fname)
     VALUE klass, fname;
 {
-    VALUE f;
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
 
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
+    fptr = open_fptr(&fname, "r");
     rb_io_check_readable(fptr);
 
@@ -306,6 +357,6 @@ img_from_xpmfname(klass, fname)
     if (!iptr)
         rb_raise(rb_eArgError, "%s is not a valid XPM File", fptr->path);
-                 
-    return Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -320,14 +371,10 @@ img_from_jpeg(klass, f)
     gdImagePtr iptr;
 
-    Check_Type(f, T_FILE);
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-    
-    iptr = gdImageCreateFromJpeg(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+    return img_init(klass, iptr);
 }
 
@@ -336,58 +383,26 @@ img_from_jpegfname(klass, fname)
     VALUE klass, fname;
 {
-    VALUE f;
     OpenFile *fptr;
     gdImagePtr iptr;
-    
-    Check_Type(fname, T_STRING);
 
-    f = rb_file_open(STR2CSTR(fname), "r");
-    rb_io_binmode(f);
-    GetOpenFile(f, fptr);
-    rb_io_check_readable(fptr);
-
-    iptr = gdImageCreateFromJpeg(fptr->f);
+    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 Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 #endif
 
 
-static VALUE
-img_destroy(img)
-    struct RData *img;
-{
-    if (img->data) {
-	gdImageDestroy((gdImagePtr)img->data);
-	img->data = 0;
-    }
-    return Qnil;
-}
-
-static VALUE
-hex2triplet(hex)
+static void
+hex2triplet(hex, tri)
     VALUE hex;
+    unsigned int tri[3];
 {
-    VALUE rstr, gstr, bstr;
-    VALUE ret_ary;
-
-    Check_Type(hex, T_STRING);
-    
-    if (RSTRING(hex)->len != 7)
+    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);
-
-    rstr = rb_str_new(RSTRING(hex)->ptr + 1, 2);
-    gstr = rb_str_new(RSTRING(hex)->ptr + 3, 2);
-    bstr = rb_str_new(RSTRING(hex)->ptr + 5, 2);
-
-    ret_ary = rb_ary_new();
-	
-    rb_ary_push(ret_ary, rb_funcall(rstr, rb_intern("hex"), 0));
-    rb_ary_push(ret_ary, rb_funcall(gstr, rb_intern("hex"), 0));
-    rb_ary_push(ret_ary, rb_funcall(bstr, rb_intern("hex"), 0));
-
-    return ret_ary;
 }
 
@@ -396,10 +411,8 @@ img_color_allocate_tri(img, r, g, b)
     VALUE img, r, g, b;
 {
-    gdImagePtr im;
-    int c;
-    
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorAllocate(im, NUM2INT(r), NUM2INT(g), NUM2INT(b));
-    
+    int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b);
+
+    c = gdImageColorAllocate(get_iptr(img), rr, gg, bb);
+
     return INT2FIX(c);
 }
@@ -409,15 +422,10 @@ img_color_allocate_str(img, rgbstr)
     VALUE img, rgbstr;
 {
-    gdImagePtr im;
     int c;
-    VALUE ary;
+    unsigned int rgb[3];
+
+    hex2triplet(rgbstr, rgb);
+    c = gdImageColorAllocate(get_iptr(img), rgb[0], rgb[1], rgb[2]);
 
-    Data_Get_Struct(img, gdImage, im);
-    
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorAllocate(im,
-                             NUM2INT(*(RARRAY(ary)->ptr)),
-                             NUM2INT(*(RARRAY(ary)->ptr+1)),
-                             NUM2INT(*(RARRAY(ary)->ptr+2)));
     return INT2FIX(c);
 }
@@ -434,5 +442,5 @@ img_color_allocate(argc, argv, img)
     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:
@@ -448,5 +456,5 @@ img_color_allocate(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -456,8 +464,7 @@ img_color_deallocate(img, color)
     VALUE img, color;
 {
-    gdImagePtr im;
+    int c = NUM2INT(color);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageColorDeallocate(im, NUM2INT(color));
+    gdImageColorDeallocate(get_iptr(img), c);
 
     return img;
@@ -469,9 +476,7 @@ img_color_resolve_tri(img, r, g, b)
     VALUE img, r, g, b;
 {
-    gdImagePtr im;
-    int c;
+    int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b);
 
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorResolve(im, NUM2INT(r), NUM2INT(g), NUM2INT(b));
+    c = gdImageColorResolve(get_iptr(img), rr, gg, bb);
 
     return INT2FIX(c);
@@ -482,15 +487,9 @@ img_color_resolve_str(img, rgbstr)
     VALUE img, rgbstr;
 {
-    gdImagePtr im;
     int c;
-    VALUE ary;
-    
-    Data_Get_Struct(img, gdImage, im);
+    unsigned int rgb[3];
 
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorResolve(im,
-                            NUM2INT(*(RARRAY(ary)->ptr)),
-                            NUM2INT(*(RARRAY(ary)->ptr+1)),
-                            NUM2INT(*(RARRAY(ary)->ptr+2)));
+    hex2triplet(rgbstr, rgb);
+    c = gdImageColorResolve(get_iptr(img), rgb[0], rgb[1], rgb[2]);
 
     return INT2FIX(c);
@@ -522,5 +521,5 @@ img_color_resolve(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -532,10 +531,8 @@ img_color_closest_tri(img, r, g, b)
     VALUE img, r, g, b;
 {
-    gdImagePtr im;
-    int c;
+    int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b);
+
+    c = gdImageColorClosest(get_iptr(img), rr, gg, bb);
 
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorClosest(im, NUM2INT(r), NUM2INT(g), NUM2INT(b));
-                
     return INT2FIX(c);
 }
@@ -545,15 +542,10 @@ img_color_closest_str(img, rgbstr)
     VALUE img, rgbstr;
 {
-    gdImagePtr im;
     int c;
-    VALUE ary;
+    unsigned int rgb[3];
 
-    Data_Get_Struct(img, gdImage, im);
+    hex2triplet(rgbstr, rgb);
+    c = gdImageColorClosest(get_iptr(img), rgb[0], rgb[1], rgb[2]);
 
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorClosest(im,
-                            NUM2INT(*(RARRAY(ary)->ptr)),
-                            NUM2INT(*(RARRAY(ary)->ptr+1)),
-                            NUM2INT(*(RARRAY(ary)->ptr+2)));
     return INT2FIX(c);
 }
@@ -584,5 +576,5 @@ img_color_closest(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -594,10 +586,8 @@ img_color_closestHWB_tri(img, r, g, b)
     VALUE img, r, g, b;
 {
-    gdImagePtr im;
-    int c;
+    int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b);
+
+    c = gdImageColorClosestHWB(get_iptr(img), rr, gg, bb);
 
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorClosestHWB(im, NUM2INT(r), NUM2INT(g), NUM2INT(b));
-                
     return INT2FIX(c);
 }
@@ -607,15 +597,10 @@ img_color_closestHWB_str(img, rgbstr)
     VALUE img, rgbstr;
 {
-    gdImagePtr im;
     int c;
-    VALUE ary;
+    unsigned int rgb[3];
 
-    Data_Get_Struct(img, gdImage, im);
+    hex2triplet(rgbstr, rgb);
+    c = gdImageColorClosestHWB(get_iptr(img), rgb[0], rgb[1], rgb[2]);
 
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorClosestHWB(im,
-                               NUM2INT(*(RARRAY(ary)->ptr)),
-                               NUM2INT(*(RARRAY(ary)->ptr+1)),
-                               NUM2INT(*(RARRAY(ary)->ptr+2)));
     return INT2FIX(c);
 }
@@ -646,5 +631,5 @@ img_color_closestHWB(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -654,10 +639,8 @@ img_color_exact_tri(img, r, g, b)
     VALUE img, r, g, b;
 {
-    gdImagePtr im;
-    int c;
+    int c, rr = NUM2INT(r), gg = NUM2INT(g), bb = NUM2INT(b);
+
+    c = gdImageColorExact(get_iptr(img), rr, gg, bb);
 
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorExact(im, NUM2INT(r), NUM2INT(g), NUM2INT(b));
-                
     return INT2FIX(c);
 }
@@ -667,15 +650,10 @@ img_color_exact_str(img, rgbstr)
     VALUE img, rgbstr;
 {
-    gdImagePtr im;
     int c;
-    VALUE ary;
+    unsigned int rgb[3];
 
-    Data_Get_Struct(img, gdImage, im);
+    hex2triplet(rgbstr, rgb);
+    c = gdImageColorExact(get_iptr(img), rgb[0], rgb[1], rgb[2]);
 
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorExact(im,
-                          NUM2INT(*(RARRAY(ary)->ptr)),
-                          NUM2INT(*(RARRAY(ary)->ptr+1)),
-                          NUM2INT(*(RARRAY(ary)->ptr+2)));
     return INT2FIX(c);
 }
@@ -706,5 +684,5 @@ img_color_exact(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -714,9 +692,7 @@ img_colors_total(img)
     VALUE img;
 {
-    gdImagePtr im;
     int c;
 
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorsTotal(im);
+    c = gdImageColorsTotal(get_iptr(img));
 
     return INT2FIX(c);
@@ -727,9 +703,7 @@ img_get_pixel(img, x, y)
     VALUE img, x, y;
 {
-    gdImagePtr im;
-    int c;
+    int c, xx = NUM2INT(x), yy = NUM2INT(y);
 
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageGetPixel(im, NUM2INT(x), NUM2INT(y));
+    c = gdImageGetPixel(get_iptr(img), xx, yy);
 
     return INT2FIX(c);
@@ -740,9 +714,8 @@ img_set_pixel(img, x, y, color)
     VALUE img, x, y, color;
 {
-    gdImagePtr im;
+    int xx = NUM2INT(x), yy = NUM2INT(y), c = NUM2INT(color);
+
+    gdImageSetPixel(get_iptr(img), xx, yy, c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageSetPixel(im, NUM2INT(x), NUM2INT(y), NUM2INT(color));
-                
     return img;
 }
@@ -752,11 +725,8 @@ img_red(img, idx)
     VALUE img, idx;
 {
-    gdImagePtr im;
     int i,c;
 
-    Data_Get_Struct(img, gdImage, im);
     i = NUM2INT(idx);
-    
-    c = gdImageRed(im, i);
+    c = gdImageRed(get_iptr(img), i);
 
     return INT2FIX(c);
@@ -767,11 +737,8 @@ img_green(img, idx)
     VALUE img, idx;
 {
-    gdImagePtr im;
     int i,c;
 
-    Data_Get_Struct(img, gdImage, im);
     i = NUM2INT(idx);
-    
-    c = gdImageGreen(im, i);
+    c = gdImageGreen(get_iptr(img), i);
 
     return INT2FIX(c);
@@ -782,11 +749,8 @@ img_blue(img, idx)
     VALUE img, idx;
 {
-    gdImagePtr im;
     int i,c;
 
-    Data_Get_Struct(img, gdImage, im);
     i = NUM2INT(idx);
-    
-    c = gdImageBlue(im, i);
+    c = gdImageBlue(get_iptr(img), i);
 
     return INT2FIX(c);
@@ -801,7 +765,7 @@ img_rgb(img, idx)
     int i, c;
 
-    Data_Get_Struct(img, gdImage, im);
     i = NUM2INT(idx);
 
+    im = get_iptr(img);
     c = gdImageRed(im, i);
     rb_ary_push(ary, INT2FIX(c));
@@ -818,22 +782,10 @@ img_transparent(img, idx)
     VALUE img, idx;
 {
-    gdImagePtr im;
-
-    Data_Get_Struct(img, gdImage, im);
-
-    gdImageColorTransparent(im, NUM2INT(idx));
+    int i = NUM2INT(idx);
+    gdImageColorTransparent(get_iptr(img), i);
 
     return img;
 }
 
-static void
-image_req(img)
-    VALUE img;
-{
-    if (!rb_obj_is_kind_of(img, cImage)) {
-	rb_raise(rb_eTypeError, "GD::Image required");
-    }
-}
-
 static VALUE
 img_set_blush(img, brush)
@@ -842,7 +794,6 @@ img_set_blush(img, brush)
     gdImagePtr im, br;
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(brush);
-    Data_Get_Struct(brush, gdImage, br);
+    im = get_iptr(img);
+    br = get_iptr(brush);
     gdImageSetBrush(im, br);
 
@@ -856,15 +807,12 @@ img_set_style(argc, argv, img)
     VALUE img;
 {
-    gdImagePtr im;
     int *style;
     int i;
 
-    Data_Get_Struct(img, gdImage, im);
     style = ALLOCA_N(int, argc);
-    for (i=0; i<argc; i++) {
+    for (i = 0; i < argc; i++) {
 	style[i] = NUM2INT(argv[i]);
     }
-
-    gdImageSetStyle(im, style, argc);
+    gdImageSetStyle(get_iptr(img), style, argc);
 
     return img;
@@ -877,7 +825,6 @@ img_set_tile(img, tile)
     gdImagePtr im, ti;
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(tile);
-    Data_Get_Struct(tile, gdImage, ti);
+    im = get_iptr(img);
+    ti = get_iptr(tile);
     gdImageSetTile(im, ti);
 
@@ -889,8 +836,9 @@ img_line(img, x1, y1, x2, y2, c)
     VALUE img, x1, y1, x2, y2, c;
 {
-    gdImagePtr im;
+    int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1);
+    int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2);
+    int ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageLine(im,NUM2INT(x1),NUM2INT(y1),NUM2INT(x2),NUM2INT(y2),NUM2INT(c));
+    gdImageLine(get_iptr(img), ix1, iy1, ix2, iy2, ic);
 
     return img;
@@ -901,8 +849,9 @@ img_dashed_line(img, x1, y1, x2, y2, c)
     VALUE img, x1, y1, x2, y2, c;
 {
-    gdImagePtr im;
+    int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1);
+    int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2);
+    int ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageDashedLine(im,NUM2INT(x1),NUM2INT(y1),NUM2INT(x2),NUM2INT(y2),NUM2INT(c));
+    gdImageDashedLine(get_iptr(img), ix1, iy1, ix2, iy2, ic);
 
     return img;
@@ -914,8 +863,9 @@ img_rectangle(img, x1, y1, x2, y2, c)
     VALUE img, x1, y1, x2, y2, c;
 {
-    gdImagePtr im;
+    int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1);
+    int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2);
+    int ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageRectangle(im,NUM2INT(x1),NUM2INT(y1),NUM2INT(x2),NUM2INT(y2),NUM2INT(c));
+    gdImageRectangle(get_iptr(img), ix1, iy1, ix2, iy2, ic);
 
     return img;
@@ -927,19 +877,36 @@ img_filled_rectangle(img, x1, y1, x2, y2
     VALUE img, x1, y1, x2, y2, c;
 {
-    gdImagePtr im;
+    int ix1 = NUM2INT(x1), iy1 = NUM2INT(y1);
+    int ix2 = NUM2INT(x2), iy2 = NUM2INT(y2);
+    int ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageFilledRectangle(im,NUM2INT(x1),NUM2INT(y1),NUM2INT(x2),NUM2INT(y2),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_req(ply)
+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 (!rb_obj_is_kind_of(ply, cPolygon) || TYPE(ply) != T_ARRAY) {
-	rb_raise(rb_eTypeError, "GD::Polygon required");
+    if (!is_poly(ply)) {
+	rb_raise(rb_eTypeError, "wrong argument type %s (expected GD::Polygon)",
+                 rb_obj_classname(ply));
     }
+    return DATA_PTR(ply);
 }
 
@@ -947,23 +914,14 @@ static VALUE
 img_polygon(img, ply, c)
     VALUE img;
-    struct RArray *ply;
+    VALUE ply;
     VALUE c;
 {
-    gdImagePtr im;
-    gdPointPtr pnt;
-    int i, len;
+    int col = NUM2INT(c);
+    struct polygon *ptr = get_poly(ply);
 
-    Data_Get_Struct(img, gdImage, im);
-
-    poly_req(ply);
-    len = ply->len/2;
-    pnt = ALLOCA_N(gdPoint, len);
-    for (i=0; i<len; i++) {
-	pnt[i].x = NUM2INT(ply->ptr[i*2]);
-	pnt[i].y = NUM2INT(ply->ptr[i*2+1]);
+    if (ptr && ptr->len) {
+	gdImagePolygon(get_iptr(img), ptr->pnt, ptr->len, col);
     }
 
-    gdImagePolygon(im, pnt, len, NUM2INT(c));
-
     return img;
 }
@@ -972,23 +930,14 @@ static VALUE
 img_filled_polygon(img, ply, c)
     VALUE img;
-    struct RArray *ply;
+    VALUE ply;
     VALUE c;
 {
-    gdImagePtr im;
-    gdPointPtr pnt;
-    int i, len;
+    int col = NUM2INT(c);
+    struct polygon *ptr = get_poly(ply);
 
-    Data_Get_Struct(img, gdImage, im);
-
-    poly_req(ply);
-    len = ply->len/2;
-    pnt = ALLOCA_N(gdPoint, len);
-    for (i=0; i<len; i++) {
-	pnt[i].x = NUM2INT(ply->ptr[i*2]);
-	pnt[i].y = NUM2INT(ply->ptr[i*2+1]);
+    if (ptr && ptr->len) {
+	gdImageFilledPolygon(get_iptr(img), ptr->pnt, ptr->len, col);
     }
 
-    gdImageFilledPolygon(im, pnt, len, NUM2INT(c));
-
     return img;
 }
@@ -998,8 +947,8 @@ img_arc(img, cx, cy, w, h, s, e, c)
     VALUE img, cx, cy, w, h, s, e, c;
 {
-    gdImagePtr im;
+    int icx = NUM2INT(cx), icy = NUM2INT(cy), iw = NUM2INT(w), ih = NUM2INT(h);
+    int is = NUM2INT(s), ie = NUM2INT(e), ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageArc(im,NUM2INT(cx),NUM2INT(cy),NUM2INT(w),NUM2INT(h),NUM2INT(s),NUM2INT(e),NUM2INT(c));
+    gdImageArc(get_iptr(img), icx, icy, iw, ih, is, ie, ic);
 
     return img;
@@ -1010,8 +959,7 @@ img_fill(img, x, y, c)
     VALUE img, x, y, c;
 {
-    gdImagePtr im;
+    int ix = NUM2INT(x), iy = NUM2INT(y), ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageFill(im,NUM2INT(x),NUM2INT(y),NUM2INT(c));
+    gdImageFill(get_iptr(img), ix, iy, ic);
 
     return img;
@@ -1022,8 +970,7 @@ img_fill_to_border(img, x, y, b, c)
     VALUE img, x, y, b, c;
 {
-    gdImagePtr im;
+    int ix = NUM2INT(x), iy = NUM2INT(y), ib = NUM2INT(b), ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageFillToBorder(im,NUM2INT(x),NUM2INT(y),NUM2INT(b),NUM2INT(c));
+    gdImageFillToBorder(get_iptr(img), ix, iy, ib, ic);
 
     return img;
@@ -1035,10 +982,12 @@ img_copy(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);
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(img2);
-    Data_Get_Struct(img2, gdImage, im2);
+    im = get_iptr(img);
+    im2 = get_iptr(img2);
 
-#ifdef ENABLE_GD_2_0    
+#ifdef ENABLE_GD_2_0
     if (is_truecolor(im) && (!is_truecolor(im2))){
         rb_raise(rb_eRuntimeError,
@@ -1046,9 +995,6 @@ img_copy(img, img2, dx, dy, sx, sy, w, h
     }
 #endif
-        
-    gdImageCopy(im2, im,
-                NUM2INT(dx), NUM2INT(dy),
-                NUM2INT(sx), NUM2INT(sy),
-                NUM2INT(w),NUM2INT(h));
+
+    gdImageCopy(im2, im, idx, idy, isx, isy, iw, ih);
 
     return img;
@@ -1060,10 +1006,13 @@ img_copy_resized(img, img2, dx, dy, sx, 
 {
     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);
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(img2);
-    Data_Get_Struct(img2, gdImage, im2);
+    im = get_iptr(img);
+    im2 = get_iptr(img2);
 
-#ifdef ENABLE_GD_2_0    
+#ifdef ENABLE_GD_2_0
     if (is_truecolor(im) && (!is_truecolor(im2))){
         rb_raise(rb_eRuntimeError,
@@ -1072,5 +1021,5 @@ img_copy_resized(img, img2, dx, dy, sx, 
 #endif
 
-    gdImageCopyResized(im2,im,NUM2INT(dx),NUM2INT(dy),NUM2INT(sx),NUM2INT(sy),NUM2INT(dw),NUM2INT(dh),NUM2INT(sw),NUM2INT(sh));
+    gdImageCopyResized(im2, im, idx, idy, isx, isy, idw, idh, isw, ish);
 
     return img;
@@ -1082,10 +1031,12 @@ img_copy_merge(img, img_dest, dx, dy, sx
 {
     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);
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(img_dest);
-    Data_Get_Struct(img_dest, gdImage, im_dest);
+    im = get_iptr(img);
+    im_dest = get_iptr(img_dest);
 
-#ifdef ENABLE_GD_2_0    
+#ifdef ENABLE_GD_2_0
     if (is_truecolor(im) && (!is_truecolor(im_dest))){
         rb_raise(rb_eRuntimeError,
@@ -1093,6 +1044,6 @@ img_copy_merge(img, img_dest, dx, dy, sx
     }
 #endif
-    
-    gdImageCopyMerge(im_dest,im,NUM2INT(dx),NUM2INT(dy),NUM2INT(sx),NUM2INT(sy),NUM2INT(w),NUM2INT(h), NUM2INT(pct));
+
+    gdImageCopyMerge(im_dest, im, idx, idy, isx, isy, iw, ih, p);
 
     return img;
@@ -1104,10 +1055,12 @@ img_copy_merge_gray(img, img_dest, dx, d
 {
     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);
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(img_dest);
-    Data_Get_Struct(img_dest, gdImage, im_dest);
+    im = get_iptr(img);
+    im_dest = get_iptr(img_dest);
 
-#ifdef ENABLE_GD_2_0    
+#ifdef ENABLE_GD_2_0
     if (is_truecolor(im) && (!is_truecolor(im_dest))){
         rb_raise(rb_eRuntimeError,
@@ -1115,21 +1068,15 @@ img_copy_merge_gray(img, img_dest, dx, d
     }
 #endif
-    
-    gdImageCopyMergeGray(im_dest,im,NUM2INT(dx),NUM2INT(dy),NUM2INT(sx),NUM2INT(sy),NUM2INT(w),NUM2INT(h), NUM2INT(pct));
+
+    gdImageCopyMergeGray(im_dest, im, idx, idy, isx, isy, iw, ih, p);
 
     return img;
 }
-    
+
 static VALUE
 img_palette_copy(img, img2)
     VALUE img, img2;
 {
-    gdImagePtr im, im2;
-
-    image_req(img2);
-    Data_Get_Struct(img, gdImage, im);
-    Data_Get_Struct(img2, gdImage, im2);
-    
-    gdImagePaletteCopy(im, im2);
+    gdImagePaletteCopy(get_iptr(img), get_iptr(img2));
 
     return img;
@@ -1137,10 +1084,30 @@ img_palette_copy(img, img2)
 
 static void
-font_req(fnt)
+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;
 {
-    if (!rb_obj_is_kind_of(fnt, cFont)) {
-	rb_raise(rb_eTypeError, "GD::Font required");
+    gdFontPtr f = check_font(fnt);
+
+    if (!f) {
+	rb_raise(rb_eTypeError, "uninitialized GD::Font");
     }
+    return f;
 }
 
@@ -1149,13 +1116,8 @@ img_string(img, fnt, x, y, str, c)
     VALUE img, fnt, x, y, str, c;
 {
-    gdImagePtr im;
-    gdFontPtr  f;
+    int xx = NUM2INT(x), yy = NUM2INT(y), cc = NUM2INT(c);
+    char *s = StringValueCStr(str);
 
-    Check_Type(str, T_STRING);
-    Data_Get_Struct(img, gdImage, im);
-    font_req(fnt);
-    Data_Get_Struct(fnt, gdFont, f);
-
-    gdImageString(im,f,NUM2INT(x),NUM2INT(y),RSTRING(str)->ptr,NUM2INT(c));
+    gdImageString(get_iptr(img), get_font(fnt), xx, yy, s, cc);
 
     return img;
@@ -1166,13 +1128,8 @@ img_string_up(img, fnt, x, y, str, c)
     VALUE img, fnt, x, y, str, c;
 {
-    gdImagePtr im;
-    gdFontPtr  f;
+    int xx = NUM2INT(x), yy = NUM2INT(y), cc = NUM2INT(c);
+    char *s = StringValueCStr(str);
 
-    Check_Type(str, T_STRING);
-    Data_Get_Struct(img, gdImage, im);
-    font_req(fnt);
-    Data_Get_Struct(fnt, gdFont, f);
-
-    gdImageStringUp(im,f,NUM2INT(x),NUM2INT(y),RSTRING(str)->ptr,NUM2INT(c));
+    gdImageStringUp(get_iptr(img), get_font(fnt), xx, yy, s, cc);
 
     return img;
@@ -1180,4 +1137,46 @@ img_string_up(img, fnt, x, y, str, c)
 
 
+#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
@@ -1185,28 +1184,13 @@ img_s_string_ttf(klass, fgcolor, fontnam
     VALUE klass, fgcolor, fontname, ptsize, angle, x, y, string;
 {
-    int brect[8], i;
+    struct image_string_arg arg;
+    int brect[8];
     char *msg;
-    VALUE ary = rb_ary_new2(8);
 
-    Check_Type(fontname, T_STRING);
-    Check_Type(string, T_STRING);
-
-    msg = gdImageStringTTF(NULL,
-                           &brect[0],
-                           NUM2INT(fgcolor),
-                           RSTRING(fontname)->ptr,
-                           NUM2DBL(ptsize),
-                           NUM2DBL(angle),
-                           NUM2INT(x),
-                           NUM2INT(y),
-                           RSTRING(string)->ptr);
-    for (i=0; i<8; i++) {
-        rb_ary_push(ary, INT2FIX(brect[i]));
-    }
-    if (msg) {
-        return rb_ary_new3(2, rb_str_new2(msg), ary);
-    } else {
-        return rb_ary_new3(2, Qnil, ary);
-    }
+    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);
 }
 
@@ -1215,30 +1199,13 @@ img_string_ttf(img, fgcolor, fontname, p
     VALUE img, fgcolor, fontname, ptsize, angle, x, y, string;
 {
-    gdImagePtr im;
-    int brect[8], i;
+    struct image_string_arg arg;
+    int brect[8];
     char *msg;
-    VALUE ary = rb_ary_new2(8);
 
-    Check_Type(fontname, T_STRING);
-    Check_Type(string, T_STRING);
-
-    Data_Get_Struct(img, gdImage, im);
-    msg = gdImageStringTTF(im,
-                           &brect[0],
-                           NUM2INT(fgcolor),
-                           RSTRING(fontname)->ptr,
-                           NUM2DBL(ptsize),
-                           NUM2DBL(angle),
-                           NUM2INT(x),
-                           NUM2INT(y),
-                           RSTRING(string)->ptr);
-    for (i=0; i<8; i++) {
-        rb_ary_push(ary, INT2FIX(brect[i]));
-    }
-    if (msg) {
-        return rb_ary_new3(2, rb_str_new2(msg), ary);
-    } else {
-        return rb_ary_new3(2, Qnil, ary);
-    }
+    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 */
@@ -1249,29 +1216,14 @@ img_s_string_ft(klass, fgcolor, fontname
     VALUE klass, fgcolor, fontname, ptsize, angle, x, y, string;
 {
-    int brect[8], i;
+    struct image_string_arg arg;
+    int brect[8];
     char *msg;
-    VALUE ary = rb_ary_new2(8);
 
-    Check_Type(fontname, T_STRING);
-    Check_Type(string, T_STRING);
-
-    msg = gdImageStringFT(NULL,
-                           &brect[0],
-                           NUM2INT(fgcolor),
-                           RSTRING(fontname)->ptr,
-                           NUM2DBL(ptsize),
-                           NUM2DBL(angle),
-                           NUM2INT(x),
-                           NUM2INT(y),
-                           RSTRING(string)->ptr);
-    for (i=0; i<8; i++) {
-        rb_ary_push(ary, INT2FIX(brect[i]));
-    }
-    if (msg) {
-        return rb_ary_new3(2, rb_str_new2(msg), ary);
-    } else {
-        return rb_ary_new3(2, Qnil, ary);
-    }
-}
+    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
@@ -1279,30 +1231,13 @@ img_string_ft(img, fgcolor, fontname, pt
     VALUE img, fgcolor, fontname, ptsize, angle, x, y, string;
 {
-    gdImagePtr im;
-    int brect[8], i;
+    struct image_string_arg arg;
+    int brect[8];
     char *msg;
-    VALUE ary = rb_ary_new2(8);
-
-    Check_Type(fontname, T_STRING);
-    Check_Type(string, T_STRING);
 
-    Data_Get_Struct(img, gdImage, im);
-    msg = gdImageStringFT(im,
-                           &brect[0],
-                           NUM2INT(fgcolor),
-                           RSTRING(fontname)->ptr,
-                           NUM2DBL(ptsize),
-                           NUM2DBL(angle),
-                           NUM2INT(x),
-                           NUM2INT(y),
-                           RSTRING(string)->ptr);
-    for (i=0; i<8; i++) {
-        rb_ary_push(ary, INT2FIX(brect[i]));
-    }
-    if (msg) {
-        return rb_ary_new3(2, rb_str_new2(msg), ary);
-    } else {
-        return rb_ary_new3(2, Qnil, ary);
-    }
+    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 */
@@ -1312,22 +1247,7 @@ img_char(img, fnt, x, y, ch, c)
     VALUE img, fnt, x, y, ch, c;
 {
-    gdImagePtr im;
-    gdFontPtr  f;
-    int ci;
+    int ix = NUM2INT(x), iy = NUM2INT(y), ich = NUM2CHR(ch), ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    font_req(fnt);
-    Data_Get_Struct(fnt, gdFont, f);
-    
-    if (TYPE(ch) == T_STRING) {
-	if (RSTRING(ch)->len != 1) {
-	    rb_raise(rb_eArgError, "string must be 1 byte(%d bytes)", RSTRING(ch)->len);
-	}
-	ci = RSTRING(ch)->ptr[0];
-    }
-    else {
-	ci = NUM2INT(ch);
-    }
-    gdImageChar(im,f,NUM2INT(x),NUM2INT(y),ci,NUM2INT(c));
+    gdImageChar(get_iptr(img), get_font(fnt), ix, iy, ich, ic);
 
     return img;
@@ -1338,22 +1258,7 @@ img_char_up(img, fnt, x, y, ch, c)
     VALUE img, fnt, x, y, ch, c;
 {
-    gdImagePtr im;
-    gdFontPtr  f;
-    int ci;
+    int ix = NUM2INT(x), iy = NUM2INT(y), ich = NUM2CHR(ch), ic = NUM2INT(c);
 
-    Data_Get_Struct(img, gdImage, im);
-    font_req(fnt);
-    Data_Get_Struct(fnt, gdFont, f);
-
-    if (TYPE(ch) == T_STRING) {
-	if (RSTRING(ch)->len != 1) {
-	    rb_raise(rb_eArgError, "string must be 1 byte(%d bytes)", RSTRING(ch)->len);
-	}
-	ci = RSTRING(ch)->ptr[0];
-    }
-    else {
-	ci = NUM2INT(ch);
-    }
-    gdImageCharUp(im,f,NUM2INT(x),NUM2INT(y),ci,NUM2INT(c));
+    gdImageCharUp(get_iptr(img), get_font(fnt), ix, iy, ich, ic);
 
     return img;
@@ -1364,8 +1269,5 @@ img_get_interlace(img)
     VALUE img;
 {
-    gdImagePtr im;
-
-    Data_Get_Struct(img, gdImage, im);
-    if (gdImageGetInterlaced(im)) {
+    if (gdImageGetInterlaced(get_iptr(img))) {
 	return Qtrue;
     }
@@ -1376,8 +1278,5 @@ static VALUE
 img_set_interlace(img, val)
 {
-    gdImagePtr im;
-
-    Data_Get_Struct(img, gdImage, im);
-    gdImageInterlace(im, RTEST(val));
+    gdImageInterlace(get_iptr(img), RTEST(val));
 
     return img;
@@ -1390,26 +1289,26 @@ img_bounds(img)
     gdImagePtr im;
     VALUE ary = rb_ary_new2(2);
-    int i;
+    int x, y;
 
-    Data_Get_Struct(img, gdImage, im);
-    i = gdImageSX(im);
-    rb_ary_push(ary, INT2FIX(i));
-    i = gdImageSY(im);
-    rb_ary_push(ary, INT2FIX(i));
+    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;
 {
-    gdImagePtr im;
+    int ix = NUM2INT(x), iy = NUM2INT(y);
 
-    Data_Get_Struct(img, gdImage, im);
-    if ( gdImageBoundsSafe(im, NUM2INT(x), NUM2INT(y)) ) {
+    if (gdImageBoundsSafe(get_iptr(img), ix, iy)) {
        return Qtrue;
-    } else {
+    }
+    else {
        return Qfalse;
     }
@@ -1420,8 +1319,6 @@ img_get_transparent(img)
     VALUE img;
 {
-    gdImagePtr im;
-
-    Data_Get_Struct(img, gdImage, im);
-    return INT2NUM(gdImageGetTransparent(im));
+    int t = gdImageGetTransparent(get_iptr(img));
+    return INT2NUM(t);
 }
 
@@ -1431,9 +1328,5 @@ img_width(img)
     VALUE img;
 {
-    gdImagePtr im;
-    int i;
-
-    Data_Get_Struct(img, gdImage, im);
-    i = gdImageSX(im);
+    int i = gdImageSX(get_iptr(img));
     return INT2FIX(i);
 }
@@ -1443,9 +1336,5 @@ img_height(img)
     VALUE img;
 {
-    gdImagePtr im;
-    int i;
-
-    Data_Get_Struct(img, gdImage, im);
-    i = gdImageSY(im);
+    int i = gdImageSY(get_iptr(img));
     return INT2FIX(i);
 }
@@ -1455,16 +1344,8 @@ img_png(img, out)
     VALUE img, out;
 {
-    gdImagePtr im;
-    OpenFile *fptr;
     FILE *f;
 
-    Data_Get_Struct(img, gdImage, im);
-    Check_Type(out, T_FILE); 
-    rb_io_binmode(out);
-    GetOpenFile(out, fptr);
-    rb_io_check_writable(fptr);
-    f = (fptr->f2) ? fptr->f2 : fptr->f;
-
-    gdImagePng(im, f);
+    f = writable_fptr(get_fptr(&out));
+    gdImagePng(get_iptr(img), f);
 
     return img;
@@ -1477,11 +1358,9 @@ img_png_str(img)
     int size;
     void *ptr;
-    gdImagePtr im;
     VALUE imageString;
-    
-    Data_Get_Struct(img, gdImage, im);
-    ptr = gdImagePngPtr(im, &size);
+
+    ptr = gdImagePngPtr(get_iptr(img), &size);
     imageString = rb_str_new(ptr, size);
-    
+
 #ifdef ENABLE_GD_2_0
     gdFree(ptr);
@@ -1497,16 +1376,8 @@ img_gd(img, out)
     VALUE img, out;
 {
-    gdImagePtr im;
-    OpenFile *fptr;
     FILE *f;
 
-    Data_Get_Struct(img, gdImage, im);
-    Check_Type(out, T_FILE); 
-    rb_io_binmode(out);
-    GetOpenFile(out, fptr);
-    rb_io_check_writable(fptr);
-    f = (fptr->f2) ? fptr->f2 : fptr->f;
-
-    gdImageGd(im, f);
+    f = writable_fptr(get_fptr(&out));
+    gdImageGd(get_iptr(img), f);
 
     return img;
@@ -1517,16 +1388,9 @@ img_gd2(img, out, cs, fmt)
     VALUE img, out, cs, fmt;
 {
-    OpenFile *fptr;
-    gdImagePtr im;
     FILE *f;
+    int ics = NUM2INT(cs), ifmt = NUM2INT(fmt);
 
-    Check_Type(out, T_FILE);
-    rb_io_binmode(out);
-    GetOpenFile(out, fptr);
-    rb_io_check_writable(fptr);
-    f = (fptr->f2) ? fptr->f2 : fptr->f;
-
-    Data_Get_Struct(img, gdImage, im);
-    gdImageGd2(im, f, NUM2INT(cs), NUM2INT(fmt));
+    f = writable_fptr(get_fptr(&out));
+    gdImageGd2(get_iptr(img), f, ics, ifmt);
 
     return img;
@@ -1539,18 +1403,9 @@ img_jpeg(img, out, quality)
     VALUE img, out, quality;
 {
-    gdImagePtr im;
-    OpenFile *fptr;
     FILE *f;
+    int q = NUM2INT(quality);
 
-    Data_Get_Struct(img, gdImage, im);
-    
-    Check_Type(out, T_FILE);
-
-    rb_io_binmode(out);
-    GetOpenFile(out, fptr);
-    rb_io_check_writable(fptr);
-    f = (fptr->f2) ? fptr->f2 : fptr->f;
-
-    gdImageJpeg(im, f, FIX2INT(quality));
+    f = writable_fptr(get_fptr(&out));
+    gdImageJpeg(get_iptr(img), f, q);
 
     return img;
@@ -1561,13 +1416,11 @@ img_jpeg_str(img, quality)
     VALUE img, quality;
 {
-    int size;
+    int size, q = NUM2INT(quality);
     void *ptr;
-    gdImagePtr im;
     VALUE imageString;
-    
-    Data_Get_Struct(img, gdImage, im);
-    ptr = gdImageJpegPtr(im, &size, FIX2INT(quality));
+
+    ptr = gdImageJpegPtr(get_iptr(img), &size, q);
     imageString = rb_str_new(ptr, size);
-    
+
 #ifdef ENABLE_GD_2_0
     gdFree(ptr);
@@ -1584,18 +1437,9 @@ img_wbmp(img, fg, out)
     VALUE img, out, fg;
 {
-    gdImagePtr im;
-    OpenFile *fptr;
     FILE *f;
+    int c = NUM2INT(fg);
 
-    Data_Get_Struct(img, gdImage, im);
-
-    Check_Type(out, T_FILE);
-
-    rb_io_binmode(out);
-    GetOpenFile(out, fptr);
-    rb_io_check_writable(fptr);
-    f = (fptr->f2) ? fptr->f2 : fptr->f;
-
-    gdImageWBMP(im, FIX2INT(fg), f);
+    f = writable_fptr(get_fptr(&out));
+    gdImageWBMP(get_iptr(img), c, f);
 
     return img;
@@ -1608,12 +1452,188 @@ img_wbmp(img, fg, out)
  */
 
+
 static VALUE
-ply_new(klass)
+ply_s_alloc(klass)
     VALUE klass;
 {
-    VALUE self = rb_ary_new();
+    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;
+}
 
-    RBASIC(self)->klass = klass;
-    return self;
+static VALUE
+ply_add_pts(argc, argv, ply)
+    int argc;
+    VALUE *argv;
+    VALUE ply;
+{
+    return ply_insert_pts(argc, argv, ply, -1);
 }
 
@@ -1622,58 +1642,147 @@ ply_add_pt(ply, x, y)
     VALUE ply, x, y;
 {
-    /* type check */
-    NUM2INT(x);
-    NUM2INT(y);
-
-    rb_ary_push(ply, x);
-    rb_ary_push(ply, 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;
 {
-    VALUE x, y;
-
-    /* type check */
-    NUM2INT(dx);
-    NUM2INT(dy);
-
-    if (RARRAY(ply)->len > 0) {
-        x = rb_ary_entry(ply, RARRAY(ply)->len - 2);
-        y = rb_ary_entry(ply, RARRAY(ply)->len - 1);
-        rb_ary_push(ply, INT2NUM(NUM2INT(x) + NUM2INT(dx)));
-        rb_ary_push(ply, INT2NUM(NUM2INT(y) + NUM2INT(dy)));
-    } else {
-        ply_add_pt(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 (RARRAY(ply)->len < idx) return Qnil;
-    i *= 2;
+    if (!ptr || i >= ptr->len) return Qnil;
+    p = &ptr->pnt[i];
 
-    return rb_assoc_new(rb_ary_entry(ply, i), rb_ary_entry(ply, i+1));
+    return rb_assoc_new(INT2FIX(p->x), INT2FIX(p->y));
 }
 
 static VALUE
-ply_set_pt(ply, idx, x, y)
-    VALUE ply, idx, x, y;
+ply_subseq(ply, beg, len)
+    VALUE ply, beg, len;
 {
-    int i = NUM2INT(idx)*2;
+    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);
+    }
 
-    /* type check */
-    NUM2INT(x);
-    NUM2INT(y);
+    return ply2;
+}
 
-    rb_ary_store(ply, i,   x);
-    rb_ary_store(ply, i+1, y);
+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;
@@ -1681,11 +1790,83 @@ ply_set_pt(ply, idx, x, y)
 
 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)*2;
+    int i = NUM2INT(idx);
+    struct polygon *ptr = get_poly(ply);
 
-    rb_ary_delete_at(ply, INT2FIX(i));
-    rb_ary_delete_at(ply, INT2FIX(i+1));
+    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;
@@ -1693,19 +1874,50 @@ ply_delete_pt(ply, idx)
 
 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;
 {
-    return INT2FIX(RARRAY(ply)->len / 2);
+    struct polygon *ptr = get_poly(ply);
+
+    if (!ptr) return INT2FIX(0);
+    return INT2FIX(ptr->len);
 }
 
 static VALUE
 ply_vertices(ply)
-    struct RArray *ply;
+    VALUE ply;
 {
     int i;
-    VALUE ary = rb_ary_new2(ply->len/2);
+    struct polygon *ptr = get_poly(ply);
+    VALUE ary;
 
-    for (i = 0; i<ply->len; i+=2) {
-	rb_ary_push(ary, rb_assoc_new(ply->ptr[i], ply->ptr[i+1]));
+    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;
@@ -1714,24 +1926,26 @@ ply_vertices(ply)
 static VALUE
 ply_bounds(ply)
-    struct RArray *ply;
+    VALUE ply;
 {
     int i, l, t, r, b;
     int nx, ny;
+    struct polygon *ptr = get_poly(ply);
 
-    if (ply->len == 0) {
+    if (!ptr || !ptr->len) {
 	l = t = r = b = 0;
     }
     else {
-	l = r = NUM2INT(ply->ptr[0]);
-	t = b = NUM2INT(ply->ptr[1]);
+	l = r = ptr->pnt[0].x;
+	t = b = ptr->pnt[0].y;
     }
-    for (i = 2; i<ply->len; i+=2) {
-	nx = NUM2INT(ply->ptr[i]);
+    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;
-	ny = NUM2INT(ply->ptr[i+1]);
 	if (ny < t) t = ny;
 	if (ny > b) b = ny;
     }
+
     return rb_ary_new3(4, INT2FIX(l), INT2FIX(t), INT2FIX(r), INT2FIX(b));
 }
@@ -1739,20 +1953,19 @@ ply_bounds(ply)
 static VALUE
 ply_offset(ply, vx, vy)
-    struct RArray *ply;
+    VALUE ply;
     VALUE vx, vy;
 {
-    int i, x, y, c;
-
-    x = NUM2INT(vx);
-    y = NUM2INT(vy);
-
-    for (i = 0; i<ply->len; i+=2) {
-	c = NUM2INT(ply->ptr[i]) + x;
-	ply->ptr[i] = INT2FIX(c);
-	c = NUM2INT(ply->ptr[i+1]) + y;
-	ply->ptr[i+1] = INT2FIX(c);
+    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 (VALUE)ply;
+    return ply;
 }
 
@@ -1761,29 +1974,30 @@ ply_map(argc, argv, ply)
     int argc;
     VALUE *argv;
-    struct RArray *ply;
+    VALUE ply;
 {
     VALUE sl, st, sr, sb, dl, dt, dr, db;
     int sx, sy, dx, dy;
     double xmag, ymag;
-    int i, c;
+    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 i, l, t, r, b;
-	int nx, ny;
+	int l, t, r, b;
 
-	if (ply->len == 0) {
-	    l = t = r = b = 0;
-	}
-	else {
-	    l = r = NUM2INT(ply->ptr[0]);
-	    t = b = NUM2INT(ply->ptr[1]);
-	}
-	for (i = 2; i<ply->len; i+=2) {
-	    nx = NUM2INT(ply->ptr[i]);
+	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;
-	    ny = NUM2INT(ply->ptr[i+1]);
 	    if (ny < t) t = ny;
 	    if (ny > b) b = ny;
@@ -1791,8 +2005,6 @@ ply_map(argc, argv, ply)
 	sx = l;
 	sy = t;
-	dx = NUM2INT(sl);
-	dy = NUM2INT(st);
-	xmag = (double)(NUM2INT(sr) - NUM2INT(sl))/(double)(r - l);
-	ymag = (double)(NUM2INT(sb) - NUM2INT(st))/(double)(b - t);
+	xmag /= r - l;
+	ymag /= b - t;
     }
     else if (i == 8) {
@@ -1805,4 +2017,6 @@ ply_map(argc, argv, ply)
 	ymag = (double)(NUM2INT(db) - NUM2INT(dt))/
 	    (double)(NUM2INT(sb) - NUM2INT(st));
+	ptr = get_poly(ply);
+	if (!ptr || !ptr->len) return ply;
     }
     else {
@@ -1810,15 +2024,32 @@ ply_map(argc, argv, ply)
     }
 
-    for (i = 0; i<ply->len; i+=2) {
-	c = NUM2INT(ply->ptr[i]);
-	c = (c-sx)*xmag+dx;
-	ply->ptr[i] = INT2FIX(c);
+    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);
 
-	c = NUM2INT(ply->ptr[i+1]);
-	c = (c-sy)*ymag+dy;
-	ply->ptr[i+1] = INT2FIX(c);
+    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 (VALUE)ply;
+    return ply;
 }
 
@@ -1827,51 +2058,70 @@ 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;
-    VALUE x, y;
 
-    for (i = 0; i < RARRAY(ply)->len / 2; i++) {
-/*      x = rb_ary_entry(ply, i * 2);
-        y = rb_ary_entry(ply, i * 2 + 1);*/
-        x = RARRAY(ply)->ptr[i * 2];
-        y = RARRAY(ply)->ptr[i * 2 + 1];
-        ply_set_pt(ply, INT2NUM(i),
-                INT2NUM(NUM2DBL(a) * NUM2INT(x) + NUM2DBL(c) * NUM2INT(y) + NUM2INT(tx)),
-                INT2NUM(NUM2DBL(b) * NUM2INT(x) + NUM2DBL(d) * NUM2INT(y) + NUM2INT(ty)));
+    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
-ply_scale(ply, sx, sy)
-    VALUE ply, sx, sy;
+fnt_s_alloc(klass)
+    VALUE klass;
 {
-    return ply_transform(ply, sx, INT2NUM(0), INT2NUM(0), sy, INT2NUM(0), INT2NUM(0));
+    return Data_Wrap_Struct(klass, 0, fnt_free, 0);
 }
 
 static VALUE
-fnt_create(fnt)
-    gdFontPtr fnt;
+fnt_create(f)
+    gdFontPtr f;
 {
-    return Data_Wrap_Struct(cFont, 0, 0, fnt);
+    return Data_Wrap_Struct(cFont, 0, fnt_free, f);
 }
 
-static VALUE
-fnt_new(name)
+static gdFontPtr
+fnt_map(name)
     char *name;
 {
-    if (strcmp(name, "Giant") == 0) {
-	return fnt_create(gdFontGiant);
-    }
-    if (strcmp(name, "Large") == 0) {
-	return fnt_create(gdFontLarge);
-    }
-    if (strcmp(name, "Medium") == 0) {
-	return fnt_create(gdFontMediumBold);
-    }
-    if (strcmp(name, "Small") == 0) {
-	return fnt_create(gdFontSmall);
-    }
-    if (strcmp(name, "Tiny") == 0) {
-	return fnt_create(gdFontTiny);
+    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);
@@ -1879,19 +2129,39 @@ fnt_new(name)
 
 static VALUE
-fnt_s_new(obj, name)
-    VALUE obj;
-    struct RString *name;
+fnt_init(fnt, name)
+    VALUE fnt, name;
 {
-    Check_Type(name, T_STRING);
-    return fnt_new(name->ptr);
+    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;
-
-    Data_Get_Struct(fnt,gdFont,fp);
+    gdFontPtr fp = get_font(fnt);
     return INT2FIX(fp->nchars);
 }
@@ -1901,7 +2171,5 @@ fnt_offset(fnt)
     VALUE fnt;
 {
-    gdFontPtr fp;
-
-    Data_Get_Struct(fnt,gdFont,fp);
+    gdFontPtr fp = get_font(fnt);
     return INT2FIX(fp->offset);
 }
@@ -1911,7 +2179,5 @@ fnt_width(fnt)
     VALUE fnt;
 {
-    gdFontPtr fp;
-
-    Data_Get_Struct(fnt,gdFont,fp);
+    gdFontPtr fp = get_font(fnt);
     return INT2FIX(fp->w);
 }
@@ -1921,7 +2187,5 @@ fnt_height(fnt)
     VALUE fnt;
 {
-    gdFontPtr fp;
-
-    Data_Get_Struct(fnt,gdFont,fp);
+    gdFontPtr fp = get_font(fnt);
     return INT2FIX(fp->h);
 }
@@ -1940,13 +2204,14 @@ img_s_new_tc(klass, sx, sy)
 {
     gdImagePtr iptr;
+    int x = NUM2INT(sx), y = NUM2INT(sy);
 
-    if (NUM2INT(sx)<0 || NUM2INT(sy)<0)
+    if (x<0 || y<0)
     	rb_raise(rb_eArgError, "Negative width/height not allowed");
-    
-    iptr = gdImageCreateTrueColor(NUM2INT(sx), NUM2INT(sy));
+
+    iptr = gdImageCreateTrueColor(x, y);
     if (!iptr)
         rb_raise(rb_eRuntimeError, "Unable to allocate the new image");
-    
-    return Data_Wrap_Struct(klass,0,free_img,iptr);
+
+    return img_init(klass, iptr);
 }
 
@@ -1955,10 +2220,8 @@ img_color_allocate_alpha_tri(img, r, g, 
     VALUE img, r, g, b, a;
 {
-    gdImagePtr im;
-    int c;
-    
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorAllocateAlpha(im, NUM2INT(r), NUM2INT(g), NUM2INT(b), NUM2INT(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);
 }
@@ -1968,16 +2231,11 @@ img_color_allocate_alpha_str(img, rgbstr
     VALUE img, rgbstr, a;
 {
-    gdImagePtr im;
-    int c;
-    VALUE ary;
+    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);
 
-    Data_Get_Struct(img, gdImage, im);
-    
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorAllocateAlpha(im,
-                                  NUM2INT(*(RARRAY(ary)->ptr)),
-                                  NUM2INT(*(RARRAY(ary)->ptr+1)),
-                                  NUM2INT(*(RARRAY(ary)->ptr+2)),
-                                  NUM2INT(a));
     return INT2NUM(c);
 }
@@ -1994,5 +2252,5 @@ img_color_allocate_alpha(argc, argv, img
     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:
@@ -2008,5 +2266,5 @@ img_color_allocate_alpha(argc, argv, img
             break;
     }
-    
+
     return retval;
 }
@@ -2017,10 +2275,8 @@ img_color_resolve_alpha_tri(img, r, g, b
     VALUE img, r, g, b, a;
 {
-    gdImagePtr im;
-    int c;
-    
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorResolveAlpha(im, NUM2INT(r), NUM2INT(g), NUM2INT(b), NUM2INT(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);
 }
@@ -2030,16 +2286,11 @@ img_color_resolve_alpha_str(img, rgbstr,
     VALUE img, rgbstr, a;
 {
-    gdImagePtr im;
-    int c;
-    VALUE ary;
+    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);
 
-    Data_Get_Struct(img, gdImage, im);
-    
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorResolveAlpha(im,
-                                 NUM2INT(*(RARRAY(ary)->ptr)),
-                                 NUM2INT(*(RARRAY(ary)->ptr+1)),
-                                 NUM2INT(*(RARRAY(ary)->ptr+2)),
-                                 NUM2INT(a));
     return INT2NUM(c);
 }
@@ -2056,5 +2307,5 @@ img_color_resolve_alpha(argc, argv, img)
     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:
@@ -2070,5 +2321,5 @@ img_color_resolve_alpha(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -2078,10 +2329,8 @@ img_color_closest_alpha_tri(img, r, g, b
     VALUE img, r, g, b, a;
 {
-    gdImagePtr im;
-    int c;
-    
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorClosestAlpha(im, NUM2INT(r), NUM2INT(g), NUM2INT(b), NUM2INT(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);
 }
@@ -2091,16 +2340,11 @@ img_color_closest_alpha_str(img, rgbstr,
     VALUE img, rgbstr, a;
 {
-    gdImagePtr im;
-    int c;
-    VALUE ary;
+    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);
 
-    Data_Get_Struct(img, gdImage, im);
-    
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorClosestAlpha(im,
-                                 NUM2INT(*(RARRAY(ary)->ptr)),
-                                 NUM2INT(*(RARRAY(ary)->ptr+1)),
-                                 NUM2INT(*(RARRAY(ary)->ptr+2)),
-                                 NUM2INT(a));
     return INT2NUM(c);
 }
@@ -2117,5 +2361,5 @@ img_color_closest_alpha(argc, argv, img)
     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:
@@ -2131,5 +2375,5 @@ img_color_closest_alpha(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -2140,10 +2384,8 @@ img_color_exact_alpha_tri(img, r, g, b, 
     VALUE img, r, g, b, a;
 {
-    gdImagePtr im;
-    int c;
-    
-    Data_Get_Struct(img, gdImage, im);
-    c = gdImageColorExactAlpha(im, NUM2INT(r), NUM2INT(g), NUM2INT(b), NUM2INT(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);
 }
@@ -2153,16 +2395,11 @@ img_color_exact_alpha_str(img, rgbstr, a
     VALUE img, rgbstr, a;
 {
-    gdImagePtr im;
-    int c;
-    VALUE ary;
+    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);
 
-    Data_Get_Struct(img, gdImage, im);
-    
-    ary = hex2triplet(rgbstr);
-    c = gdImageColorExactAlpha(im,
-                                 NUM2INT(*(RARRAY(ary)->ptr)),
-                                 NUM2INT(*(RARRAY(ary)->ptr+1)),
-                                 NUM2INT(*(RARRAY(ary)->ptr+2)),
-                                 NUM2INT(a));
     return INT2NUM(c);
 }
@@ -2179,5 +2416,5 @@ img_color_exact_alpha(argc, argv, img)
     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:
@@ -2193,5 +2430,5 @@ img_color_exact_alpha(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -2201,9 +2438,6 @@ img_alpha_blending(img, blending_mode)
     VALUE img, blending_mode;
 {
-    gdImagePtr im;
+    gdImageAlphaBlending(get_iptr(img), RTEST(blending_mode));
 
-    Data_Get_Struct(img, gdImage, im);
-    gdImageAlphaBlending(im, RTEST(blending_mode));
-    
     return img;
 }
@@ -2213,8 +2447,7 @@ img_alpha(img, color)
     VALUE img, color;
 {
-    gdImagePtr im;
+    int a = gdImageAlpha(get_iptr(img), NUM2INT(color));
 
-    Data_Get_Struct(img, gdImage, im);
-    return INT2NUM(gdImageAlpha(im, NUM2INT(color)));
+    return INT2NUM(a);
 }
 
@@ -2225,10 +2458,9 @@ img_s_truecolor_str(rgbstr)
 {
     int c;
-    VALUE ary;
-    ary = hex2triplet(rgbstr);
-    c = gdTrueColor(NUM2INT(*(RARRAY(ary)->ptr)),
-                    NUM2INT(*(RARRAY(ary)->ptr+1)),
-                    NUM2INT(*(RARRAY(ary)->ptr+2)));
-    
+    unsigned int rgb[3];
+
+    hex2triplet(rgbstr, rgb);
+    c = gdTrueColor(rgb[0], rgb[1], rgb[2]);
+
     return INT2NUM(c);
 }
@@ -2239,6 +2471,7 @@ img_s_truecolor_tri(r, g, b)
 {
     int c;
+
     c = gdTrueColor(NUM2INT(r), NUM2INT(g), NUM2INT(b));
-    
+
     return INT2NUM(c);
 }
@@ -2255,5 +2488,5 @@ img_s_truecolor(argc, argv, img)
     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:
@@ -2269,5 +2502,5 @@ img_s_truecolor(argc, argv, img)
             break;
     }
-    
+
     return retval;
 }
@@ -2279,10 +2512,9 @@ img_s_truecolor_alpha_str(rgbstr, a)
 {
     int c;
-    VALUE ary;
-    ary = hex2triplet(rgbstr);
-    c = gdTrueColorAlpha(NUM2INT(*(RARRAY(ary)->ptr)),
-                         NUM2INT(*(RARRAY(ary)->ptr+1)),
-                         NUM2INT(*(RARRAY(ary)->ptr+2)),
-                         NUM2INT(a));
+    unsigned int rgb[3];
+
+    hex2triplet(rgbstr, rgb);
+    c = gdTrueColorAlpha(rgb[0], rgb[1], rgb[2], NUM2INT(a));
+
     return INT2NUM(c);
 }
@@ -2293,6 +2525,7 @@ img_s_truecolor_alpha_tri(r, g, b, a)
 {
     int c;
+
     c = gdTrueColorAlpha(NUM2INT(r), NUM2INT(g), NUM2INT(b), NUM2INT(a));
-    
+
     return INT2NUM(c);
 }
@@ -2309,5 +2542,5 @@ img_s_truecolor_alpha(argc, argv, img)
     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:
@@ -2331,8 +2564,11 @@ img_copy_resampled(img, img2, dx, dy, sx
 {
     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);
 
-    Data_Get_Struct(img, gdImage, im);
-    image_req(img2);
-    Data_Get_Struct(img2, gdImage, im2);
+    im = get_iptr(img);
+    im2 = get_iptr(img2);
 
     if (is_truecolor(im) && (!is_truecolor(im2))){
@@ -2340,10 +2576,7 @@ img_copy_resampled(img, img2, dx, dy, sx
                  "Copying truecolor image to palette image is not permitted");
     }
-    
-    gdImageCopyResampled(im2, im,
-                         NUM2INT(dx), NUM2INT(dy),
-                         NUM2INT(sx), NUM2INT(sy),
-                         NUM2INT(dw), NUM2INT(dh),
-                         NUM2INT(sw), NUM2INT(sh));
+
+    gdImageCopyResampled(im2, im, idx, idy, isx, isy, idw, idh, isw, ish);
+
     return img;
 }
@@ -2353,7 +2586,8 @@ img_filled_ellipse(img, cx, cy, w, h, st
     VALUE img, cx, cy, w, h, start, end, color;
 {
-    gdImagePtr im;
-    Data_Get_Struct(img, gdImage, im);
-    gdImageFilledEllipse(im, NUM2INT(cx), NUM2INT(cy), NUM2INT(w), NUM2INT(h), NUM2INT(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;
 }
@@ -2363,8 +2597,10 @@ img_filled_arc(img, cx, cy, w, h, start,
     VALUE img, cx, cy, w, h, start, end, color, style;
 {
-    gdImagePtr im;
-    Data_Get_Struct(img, gdImage, im);
-    gdImageFilledArc(im, NUM2INT(cx), NUM2INT(cy), NUM2INT(w), NUM2INT(h),
-                         NUM2INT(start), NUM2INT(end), NUM2INT(color), NUM2INT(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;
 }
@@ -2374,8 +2610,5 @@ img_is_truecolor_image(img)
     VALUE img;
 {
-    gdImagePtr im;
-    Data_Get_Struct(img, gdImage, im);
-
-    return is_truecolor(im);
+    return is_truecolor(get_iptr(img)) ? Qtrue : Qfalse;
 }
 
@@ -2384,8 +2617,5 @@ img_is_palette_image(img)
     VALUE img;
 {
-    gdImagePtr im;
-    Data_Get_Struct(img, gdImage, im);
-
-    return is_truecolor(im) ? Qfalse : Qtrue;
+    return is_truecolor(get_iptr(img)) ? Qfalse : Qtrue;
 }
 
@@ -2394,8 +2624,7 @@ img_to_palette_image(img, dither_flag, m
     VALUE img, dither_flag, max_colors;
 {
-    gdImagePtr im;
-    Data_Get_Struct(img, gdImage, im);
+    int n = NUM2INT(max_colors);
 
-    gdImageTrueColorToPalette(im, dither_flag, FIX2INT(max_colors));
+    gdImageTrueColorToPalette(get_iptr(img), dither_flag, n);
 
     return img;
@@ -2406,9 +2635,8 @@ img_set_thickness(img, thickness)
     VALUE img, thickness;
 {
-    gdImagePtr im;
-    Data_Get_Struct(img, gdImage, im);
+    int t = NUM2INT(thickness);
+
+    gdImageSetThickness(get_iptr(img), t);
 
-    gdImageSetThickness(im, FIX2INT(thickness));
-    
     return img;
 }
@@ -2421,6 +2649,15 @@ 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);
@@ -2430,5 +2667,5 @@ Init_GD()
     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);
@@ -2436,16 +2673,16 @@ Init_GD()
 #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);    
+    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);    
-    
+    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);    
+    rb_define_singleton_method(cImage, "new_from_jpeg", img_from_jpegfname, 1);
 #endif /* HAVE_GDIMAGECREATEFROMJPEG */
 
@@ -2455,8 +2692,8 @@ Init_GD()
     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, "colorClosestHWB", img_color_closestHWB, -1);
     rb_define_method(cImage, "colorExact", img_color_exact, -1);
 
-#ifdef HAVE_GDIMAGECOLORRESOLVE    
+#ifdef HAVE_GDIMAGECOLORRESOLVE
     rb_define_method(cImage, "colorResolve", img_color_resolve, -1);
 #endif /* HAVE_GDIMAGECOLORRESOLVE */
@@ -2481,5 +2718,5 @@ Init_GD()
     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);
@@ -2499,5 +2736,5 @@ Init_GD()
     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);
@@ -2506,10 +2743,10 @@ Init_GD()
     rb_define_singleton_method(cImage, "stringTTF", img_s_string_ttf, 7);
     rb_define_method(cImage, "stringTTF", img_string_ttf, 7);
-#endif    
+#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    
+#endif
 
     rb_define_method(cImage, "char", img_char, 5);
@@ -2519,5 +2756,5 @@ Init_GD()
     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);
@@ -2534,10 +2771,23 @@ Init_GD()
     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);
@@ -2552,14 +2802,21 @@ Init_GD()
     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_new("Giant"));
-    rb_define_const(cFont, "SmallFont", fnt_new("Small"));
-    rb_define_const(cFont, "LargeFont", fnt_new("Large"));
-    rb_define_const(cFont, "MediumFont", fnt_new("Medium"));
-    rb_define_const(cFont, "MediumBoldFont", fnt_new("Medium"));
-    rb_define_const(cFont, "TinyFont", fnt_new("Tiny"));
+    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);
@@ -2568,5 +2825,5 @@ Init_GD()
     rb_define_method(cFont, "height", fnt_height, 0);
 
-#ifdef ENABLE_GD_2_0    
+#ifdef ENABLE_GD_2_0
 
     rb_define_singleton_method(cImage, "newTrueColor", img_s_new_tc, 2);
@@ -2588,5 +2845,5 @@ Init_GD()
     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));
diff -rp -U2 ruby-GD-0.7.4/extconf.rb ruby-GD/extconf.rb
--- ruby-GD-0.7.4/extconf.rb	2003-01-31 13:59:50.000000000 +0900
+++ ruby-GD/extconf.rb	2004-12-26 11:26:41.000000000 +0900
@@ -16,62 +16,35 @@
 require 'mkmf'
 
-def delete_link(libname)
-  lib_ary = $libs.split
-  libname = '-l'+libname
-  lib_ary.delete libname
-  $libs = lib_ary.join " "
-end
-
-dir_config("gd", "/usr/local/include", "/usr/local/lib")
+dir_config("gd", "/usr/local")
+dir_config("X11", "/usr/X11R6")
+dir_config('xpm')
+dir_config('jpeg')
+dir_config('ttf')
+dir_config('freetype')
 
 
-
-if with_config("xpm")
-  dir_config("X11", "/usr/X11R6/include", "/usr/X11R6/lib")
+if with_config('xpm') and have_func('gdImageCreateFromXpm')
+  have_library('X11')
+  have_library('Xpm')
 end
 
-if with_config('jpeg')
+if with_config('jpeg') and have_func('gdImageCreateFromJpeg')
   have_library('jpeg')
 end
 
-if with_config('ttf')
+if with_config('ttf') and have_func('gdImageStringTTF')
   have_library('ttf')
 end
 
-if with_config('xpm')
-  have_library('X11')
-  have_library('Xpm')
-end
-
-if with_config('freetype')
+if with_config('freetype') and have_func('gdImageStringFT')
   have_library('freetype')
 end
 
-if have_library('z') and have_library('png') and 
-    have_library('gd', 'gdImagePng') and have_library('m')
-
-  if with_config('ttf') and not have_func('gdImageStringTTF')
-    delete_link('ttf')
-  end
-  
+if have_library('z') and have_library('png') and have_library('m') and
+    have_library('gd', 'gdImagePng')
   have_func('gdImageColorResolve')
 
-  if with_config('xpm') and not have_func('gdImageCreateFromXpm')
-    delete_link('Xpm')
-    delete_link('X11')
-  end
-
-  if with_config('jpeg') and not have_func('gdImageCreateFromJpeg')
-    delete_link('jpeg')
-  end
-  
-  if with_config('freetype') and not have_func('gdImageStringFT')
-    delete_link('freetype')
-  end
-  
-  if enable_config("gd2_0", false)
-    if have_func("gdImageAlphaBlending")
-      $CFLAGS += ' -DENABLE_GD_2_0'
-    end
+  if enable_config("gd2_0", have_func("gdImageAlphaBlending"))
+    $CPPFLAGS += ' -DENABLE_GD_2_0'
   end
 
diff -rp -U2 ruby-GD-0.7.4/sample/gdtestttf.rb ruby-GD/sample/gdtestttf.rb
--- ruby-GD-0.7.4/sample/gdtestttf.rb	2001-05-30 23:14:17.000000000 +0900
+++ ruby-GD/sample/gdtestttf.rb	2004-12-19 15:18:23.000000000 +0900
@@ -6,9 +6,10 @@
 =end
 
+begin
+  require 'optparse'
+rescue LoadError
+end
 require 'GD'
 
-# change this to be suitable for your Environment
-fontpath = "/mnt/windows/FONTS/times.ttf"
-
 def deg2rad(degree)
   degree*(Math::PI/180.0)
@@ -31,32 +32,42 @@ def miny(brect)
 end
 
-str = "Ruby/GD version 0.7.2"
-angle = deg2rad(20)
+# change this to be suitable for your Environment
+fontpath = "/usr/share/fonts/Windows/times.ttf"
+output = nil
+angle = 20
 sz = 36.0
-# obtain brect so that we can size the image
-err,brect = GD::Image.stringTTF(0, fontpath, sz, angle, 0, 0, str)
+str = "Ruby/GD version " + GD::VERSION
 
-if err
-  puts err
-  exit 1
-end
+ARGV.options do |opt|
+  opt.on("-f", "--fontpath=PATH") {|path|
+    File.open(path) {fontpath = path}
+  }
+  opt.on("-o", "--output=FILE") {|output|}
+  opt.on("-a", "--angle=DEGREE", Numeric) {|angle|}
+  opt.on("-s", "--size=POINT", Numeric) {|sz|}
+  opt.on("-m", "--message=STRING") {|str|}
+  opt.parse!
+end if defined?(ARGV.options)
+
+angle = deg2rad(angle)
+# obtain brect so that we can size the image
+brect = GD::Image.stringTTF(0, fontpath, sz, angle, 0, 0, str)
+p brect
 
 x = maxx(brect) - minx(brect) + 6
 y = maxy(brect) - miny(brect) + 6
-im = GD::Image.new(x,y)
-
-white = im.colorResolve(255,255,255)
-black = im.colorResolve(0,0,0)
-
-x = 0 - minx(brect) + 3
-y = 0 - miny(brect) + 3
-
-(err, brect) = im.stringTTF(black, fontpath, sz, angle, x, y, str)
-if err
-  puts err
-  exit 1
+GD::Image.new(x,y) do |im|
+  white = im.colorResolve(255,255,255)
+  black = im.colorResolve(0,0,0)
+
+  x = 0 - minx(brect) + 3
+  y = 0 - miny(brect) + 3
+
+  brect = im.stringTTF(black, fontpath, sz, angle, x, y, str)
+
+  if output
+    open(output, "w") {|f| im.png(f)}
+  else
+    im.png $stdout
+  end
 end
-
-im.png $stdout
-
-im.destroy
