Imported GD library support code, which has yet to be completed soon
authorMatthew Mondor <mmondor@pulsar-zone.net>
Tue, 24 Oct 2006 12:42:51 +0000 (12:42 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Tue, 24 Oct 2006 12:42:51 +0000 (12:42 +0000)
mmsoftware/js/classes/js_gd.c [new file with mode: 0644]
mmsoftware/js/js-sh/src/js-sh.c

diff --git a/mmsoftware/js/classes/js_gd.c b/mmsoftware/js/classes/js_gd.c
new file mode 100644 (file)
index 0000000..58375cc
--- /dev/null
@@ -0,0 +1,2695 @@
+/* $Id: js_gd.c,v 1.1 2006/10/24 12:42:43 mmondor Exp $ */
+
+/*
+ * Copyright (c) 2006, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ */
+
+/*
+ * Refer to http://www.boutell.com/gd/manual2.0.33.html for more information.
+ *
+ * XXX TODO XXX
+ * - Implement GDIOCtx and related functions
+ * - gdImageSetBrush() and gdImageSetTile() functions documentation specify
+ *   that one should not use the special gdBrushed or gdTiled if no image was
+ *   set for them or if their image were destroyed.  It would be lame to have
+ *   to do this checking in this code, but we might have to.  Will have to try
+ *   or to check the code to see if a crash can occur.
+ */
+
+
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <jsapi.h>
+
+#include <gd.h>
+
+#include <js_gd.h>
+#include <js_file.h>
+
+
+
+#define QUEUE_EXCEPTION(s)     do {                                    \
+       JS_SetPendingException(cx,                                      \
+           STRING_TO_JSVAL(JS_NewStringCopyZ(cx, (s))));               \
+} while (/* CONSTCOND */0)
+
+struct property_spec {
+       const char      *name;
+       int             value;
+};
+
+#define SP(n) \
+    { #n, n }
+
+
+
+/*
+ * Static prototypes
+ */
+
+/* GD */
+static JSBool  gd_constructor(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static void    gd_finalize(JSContext *, JSObject *);
+
+static JSBool  gd_sm_create(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool  gd_sm_create_truecolor(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+
+static JSBool  gd_sm_create_from_file_i(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *, gdImagePtr (*)(FILE *), const char *);
+static JSBool  gd_sm_create_from_str_i(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *, gdImagePtr (*)(int, void *),
+                   const char *);
+
+static JSBool  gd_sm_create_from_jpeg(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_create_from_jpeg_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_png(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_create_from_png_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_gif(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_create_from_gif_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_gd(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_create_from_gd_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_gd2(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_create_from_gd2_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_gd2_part(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_gd2_part_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_wbmp(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_create_from_wbmp_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gd_sm_create_from_xbm(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+#ifdef HAVE_XPM
+static JSBool  gd_sm_create_from_xpm(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+#endif
+static JSBool  gd_sm_true_color(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gd_sm_true_color_alpha(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+
+/* GDImage */
+static JSObject *js_InitGDImageClass(JSContext *, JSObject *);
+static JSBool  gdimage_constructor(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static void    gdimage_finalize(JSContext *, JSObject *);
+
+static JSBool  gdimage_get_property(JSContext *, JSObject *, jsval id,
+                   jsval *);
+static JSBool  gdimage_set_property(JSContext *, JSObject *, jsval id,
+                   jsval *);
+
+static JSBool  gdimage_m_image_destroy(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_save_file_i0(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *, void (*)(gdImagePtr, FILE *));
+static JSBool  gdimage_m_save_file_i1(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *, void (*)(gdImagePtr, FILE *, int));
+static JSBool  gdimage_m_save_str_i0(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *, void *(*)(gdImagePtr, int *), const char *);
+static JSBool  gdimage_m_save_str_i1(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *, void *(*)(gdImagePtr, int *, int), const char *);
+static JSBool  gdimage_m_jpeg(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_jpeg_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gif(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gif_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gif_anim_begin(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_gif_anim_begin_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_gif_anim_add(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gif_anim_add_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_gif_anim_end(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gif_anim_end_str(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_png(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_png_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_png_ex(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_png_ex_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_wbmp(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_wbmp_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gd(JSContext *, JSObject *, uintN, jsval *, jsval *);
+static JSBool  gdimage_m_gd_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gd2(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_gd2_str(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_truecolor_to_palette(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_create_palette_from_truecolor(JSContext *,
+                   JSObject *, uintN, jsval *, jsval *);
+static JSBool  gdimage_m_set_pixel(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_primitive5_i(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *, void (*)(gdImagePtr, int, int, int, int, int));
+static JSBool  gdimage_m_line(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_dashed_line(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static gdPointPtr      array_to_gdpoints_i(JSContext *, jsval, int *);
+static int     *array_to_ints_i(JSContext *, jsval, int *);
+static JSBool  gdimage_m_polygon_i(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *, void (*)(gdImagePtr, gdPointPtr, int, int));
+static JSBool  gdimage_m_polygon(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_open_polygon(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_rectangle(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_filled_polygon(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_filled_rectangle(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_arc(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_filled_arc(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_filled_ellipse(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_fill_to_border(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_fill(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_set_antialiased(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_set_antialiaseddontblend(JSContext *, JSObject *,
+                   uintN, jsval *, jsval *);
+static JSBool  gdimage_m_set_brush(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_set_tile(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_set_style(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_set_thickness(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_alpha_blending(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+static JSBool  gdimage_m_save_alpha(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_set_clip(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+static JSBool  gdimage_m_get_clip(JSContext *, JSObject *, uintN, jsval *,
+                   jsval *);
+
+static JSBool  gdimage_m_color_allocate(JSContext *, JSObject *, uintN,
+                   jsval *, jsval *);
+
+
+
+/*
+ * Static globals
+ */
+
+/*
+ * GD
+ */
+
+static JSClass gd_class = {
+       "GD", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+       JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub,
+       JS_ConvertStub, gd_finalize
+};
+
+/* Static methods */
+static JSFunctionSpec gd_smethods[] = {
+       { "create", gd_sm_create, 2, 0, 0 },
+       { "createTrueColor", gd_sm_create_truecolor, 2, 0, 0 },
+       { "createFromJpeg", gd_sm_create_from_jpeg, 1, 0, 0 },
+       { "createFromJpegStr", gd_sm_create_from_jpeg_str, 1, 0, 0 },
+       { "createFromPng", gd_sm_create_from_png, 1, 0, 0 },
+       { "createFromPngStr", gd_sm_create_from_png_str, 1, 0, 0 },
+       { "createFromGif", gd_sm_create_from_gif, 1, 0, 0 },
+       { "createFromGifStr", gd_sm_create_from_gif_str, 1, 0, 0 },
+       { "createFromGd", gd_sm_create_from_gd, 1, 0, 0 },
+       { "createFromGdStr", gd_sm_create_from_gd_str, 1, 0, 0 },
+       { "createFromGd2", gd_sm_create_from_gd2, 1, 0, 0 },
+       { "createFromGd2Str", gd_sm_create_from_gd2_str, 1, 0, 0 },
+       { "createFromGd2Part", gd_sm_create_from_gd2_part, 5, 0, 0 },
+       { "createFromGd2PartStr", gd_sm_create_from_gd2_part_str, 5, 0, 0 },
+       { "createFromWBMP", gd_sm_create_from_wbmp, 1, 0, 0 },
+       { "createFromWBMPStr", gd_sm_create_from_wbmp_str, 1, 0, 0 },
+       { "createFromXbm", gd_sm_create_from_xbm, 1, 0, 0 },
+#ifdef HAVE_XPM
+       { "createFromXpm", gd_sm_create_from_xpm, 1, 0, 0 },
+#endif
+       { "trueColor", gd_sm_true_color, 3, 0, 0 },
+       { "trueColorAlpha", gd_sm_true_color_alpha, 4, 0, 0 },
+       { NULL, NULL, 0, 0, 0 }
+};
+
+/* Static properties */
+static struct property_spec    gd_sprops[] = {
+       SP(gdDisposalNone),
+       SP(gdDisposalUnknown),
+       SP(gdDisposalRestoreBackground),
+       SP(gdDisposalRestorePrevious),
+       SP(GD2_FMT_RAW),
+       SP(GD2_FMT_COMPRESSED),
+       SP(gdAntiAliased),
+       SP(gdBrushed),
+       SP(gdMaxColors),
+       SP(gdStyled),
+       SP(gdStyledBrushed),
+       SP(gdDashSize),
+       SP(gdTiled),
+       SP(gdTransparent),
+       SP(gdArc),
+       SP(gdChord),
+       SP(gdPie),
+       SP(gdNoFill),
+       SP(gdEdged),
+       SP(gdAlphaOpaque),
+       SP(gdAlphaTransparent),
+       { NULL, 0 }
+};
+
+
+
+/*
+ * GDImage
+ */
+
+/* Class */
+static JSClass gdimage_class = {
+       "GDImage", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub,
+       gdimage_get_property, gdimage_set_property, JS_EnumerateStub,
+       JS_ResolveStub, JS_ConvertStub, gdimage_finalize
+};
+
+/* Properties */
+enum gdimage_props {
+       GDIMAGE_P_SX,
+       GDIMAGE_P_SY,
+       GDIMAGE_P_MAX
+};
+
+static JSPropertySpec gdimage_properties[GDIMAGE_P_MAX + 1] = {
+       { "sx", GDIMAGE_P_SX, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL },
+       { "sy", GDIMAGE_P_SY, JSPROP_ENUMERATE | JSPROP_READONLY, NULL, NULL },
+       { NULL, 0, 0, NULL, NULL }
+};
+
+/* Methods */
+static JSFunctionSpec gdimage_methods[] = {
+       { "destroy", gdimage_m_image_destroy, 0, 0, 0 },
+       { "jpeg", gdimage_m_jpeg, 2, 0, 0 },
+       { "jpegStr", gdimage_m_jpeg_str, 1, 0, 0 },
+       { "gif", gdimage_m_gif, 1, 0, 0 },
+       { "gifStr", gdimage_m_gif_str, 0, 0, 0 },
+       { "gifAnimBegin", gdimage_m_gif_anim_begin, 3, 0, 0 },
+       { "gifAnimBeginStr", gdimage_m_gif_anim_begin_str, 2, 0, 0 },
+       { "gifAnimAdd", gdimage_m_gif_anim_add, 7, 0, 0 },
+       { "gifAnimAddStr", gdimage_m_gif_anim_add_str, 6, 0, 0 },
+       { "gifAnimEnd", gdimage_m_gif_anim_end, 1, 0, 0 },
+       { "gifAnimEndStr", gdimage_m_gif_anim_end_str, 0, 0, 0 },
+       { "png", gdimage_m_png, 1, 0, 0 },
+       { "pngStr", gdimage_m_png_str, 0, 0, 0 },
+       { "pngEx", gdimage_m_png_ex, 2, 0, 0 },
+       { "pngExStr", gdimage_m_png_ex_str, 1, 0, 0 },
+       { "wbmp", gdimage_m_wbmp, 2, 0, 0 },
+       { "wbmpStr", gdimage_m_wbmp_str, 1, 0, 0 },
+       { "gd", gdimage_m_gd, 1, 0, 0 },
+       { "gdStr", gdimage_m_gd_str, 0, 0, 0 },
+       { "gd2", gdimage_m_gd2, 3, 0, 0 },
+       { "gd2Str", gdimage_m_gd2_str, 2, 0, 0 },
+       { "trueColorToPalette", gdimage_m_truecolor_to_palette, 2, 0, 0 },
+       { "createPaletteFromTrueColor",
+           gdimage_m_create_palette_from_truecolor, 2, 0, 0 },
+       { "setPixel", gdimage_m_set_pixel, 3, 0, 0 },
+       { "line", gdimage_m_line, 5, 0, 0 },
+       { "dashedLine", gdimage_m_dashed_line, 5, 0, 0 },
+       { "polygon", gdimage_m_polygon, 2, 0, 0 },
+       { "openPolygon", gdimage_m_open_polygon, 2, 0, 0 },
+       { "rectangle", gdimage_m_rectangle, 5, 0, 0 },
+       { "filledPolygon", gdimage_m_filled_polygon, 2, 0, 0 },
+       { "filledRectangle", gdimage_m_filled_rectangle, 5, 0, 0 },
+       { "arc", gdimage_m_arc, 7, 0, 0 },
+       { "filledArc", gdimage_m_filled_arc, 8, 0, 0 },
+       { "filledEllipse", gdimage_m_filled_ellipse, 5, 0, 0 },
+       { "fillToBorder", gdimage_m_fill_to_border, 4, 0, 0 },
+       { "fill", gdimage_m_fill, 3, 0, 0 },
+       { "setAntiAliased", gdimage_m_set_antialiased, 1, 0, 0 },
+       { "setAntiAliasedDontBlend", gdimage_m_set_antialiaseddontblend,
+           2, 0, 0 },
+       { "setBrush", gdimage_m_set_brush, 1, 0, 0 },
+       { "setTile", gdimage_m_set_tile, 1, 0, 0 },
+       { "setStyle", gdimage_m_set_style, 1, 0, 0 },
+       { "setThickness", gdimage_m_set_thickness, 1, 0, 0 },
+       { "alphaBlending", gdimage_m_alpha_blending, 1, 0, 0 },
+       { "saveAlpha", gdimage_m_save_alpha, 1, 0, 0 },
+       { "setClip", gdimage_m_set_clip, 4, 0, 0 },
+       { "getClip", gdimage_m_get_clip, 0, 0, 0 },
+
+       { "colorAllocate", gdimage_m_color_allocate, 3, 0, 0 },
+       { NULL, NULL, 0, 0, 0 }
+};
+
+
+
+/*
+ * GD object control
+ */
+
+JSObject *
+js_InitGDClass(JSContext *cx, JSObject *obj)
+{
+       JSObject                *proto, *ctor;
+       struct property_spec    *sp;
+
+       if ((proto = JS_InitClass(cx, obj, NULL, &gd_class, gd_constructor,
+           0, NULL, NULL, NULL, gd_smethods)) == NULL) {
+               (void) fprintf(stderr, "Error initializing GD class\n");
+               goto err;
+       }
+
+       /* Create static properties. */
+       if ((ctor = JS_GetConstructor(cx, proto)) == NULL) {
+               (void) fprintf(stderr, "GD: JS_GetConstructor == NULL\n");
+               return NULL;
+       }
+       for (sp = gd_sprops; sp->name != NULL; sp++) {
+               if (JS_DefineProperty(cx, ctor, sp->name,
+                   INT_TO_JSVAL(sp->value), NULL, NULL,
+                   JSPROP_READONLY | JSPROP_PERMANENT) == JS_FALSE) {
+                       (void) fprintf(stderr,
+                           "GD: Error defining property %s\n", sp->name);
+                       return NULL;
+               }
+       }
+
+       /*
+        * Initialize GDImage class since we'll need to instanciate it from C
+        */
+       if (js_InitGDImageClass(cx, obj) == NULL) {
+               (void) fprintf(stderr, "GD: InitGDImageClass()\n");
+               goto err;
+       }
+
+       return proto;
+
+err:
+       return NULL;
+}
+
+/* ARGSUSED */
+static JSBool
+gd_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+       QUEUE_EXCEPTION("GD object not user-instanciable");
+
+       return JS_FALSE;
+}
+
+/* ARGSUSED */
+static void
+gd_finalize(JSContext *cx, JSObject *obj)
+{
+
+       /* NOOP */
+}
+
+
+
+/* GD static methods */
+static JSBool
+gd_sm_create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+
+       if ((img = gdImageCreate(JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]))) == NULL) {
+               QUEUE_EXCEPTION("gdImageCreate()");
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_truecolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+
+       if ((img = gdImageCreateTrueColor(JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]))) == NULL) {
+               QUEUE_EXCEPTION("gdImageCreate()");
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img != NULL)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_from_file_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, gdImagePtr (*funcptr)(FILE *), const char *funcname)
+{
+       FILE            *fh;
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               goto err;
+       }
+
+       if ((img = funcptr(fh)) == NULL) {
+               QUEUE_EXCEPTION(funcname);
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img != NULL)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+
+/*
+ * We replace gdImageCreateFrom*Ptr() by methods using a String.
+ */
+static JSBool
+gd_sm_create_from_str_i(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval, gdImagePtr (*funcptr)(int, void *),
+    const char *funcname)
+{
+       JSString        *str;
+       char            *bytes;
+       size_t          size;
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_STRING(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not a String");
+               goto err;
+       }
+
+       str = JSVAL_TO_STRING(argv[0]);
+       if ((bytes = JS_GetStringBytes(str)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       size = JS_GetStringLength(str);
+
+       if ((img = funcptr((int)size, bytes)) == NULL) {
+               QUEUE_EXCEPTION(funcname);
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img != NULL)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_from_jpeg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromJpeg, "gdImageCreateFromJpeg()");
+}
+
+static JSBool
+gd_sm_create_from_jpeg_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromJpegPtr, "gdImageCreateFromJpegPtr()");
+}
+
+static JSBool
+gd_sm_create_from_png(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromPng, "gdImageCreateFromPng()");
+}
+
+static JSBool
+gd_sm_create_from_png_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromPngPtr, "gdImageCreateFromPngPtr()");
+}
+
+static JSBool
+gd_sm_create_from_gif(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromGif, "gdImageCreateFromGif()");
+}
+
+static JSBool
+gd_sm_create_from_gif_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromGifPtr, "gdImageCreateFromGifPtr()");
+}
+
+static JSBool
+gd_sm_create_from_gd(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromGd, "gdImageCreateFromGd()");
+}
+
+static JSBool
+gd_sm_create_from_gd_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromGdPtr, "gdImageCreateFromGdPtr()");
+}
+
+static JSBool
+gd_sm_create_from_gd2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromGd2, "gdImageCreateFromGd2()");
+}
+
+static JSBool
+gd_sm_create_from_gd2_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromGd2Ptr, "gdImageCreateFromGd2Ptr()");
+}
+
+static JSBool
+gd_sm_create_from_gd2_part(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       FILE            *fh;
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 5) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[4])) {
+               QUEUE_EXCEPTION("Argument 5 not an Integer");
+               goto err;
+       }
+
+       if ((img = gdImageCreateFromGd2Part(fh, JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+           JSVAL_TO_INT(argv[4]))) == NULL) {
+               QUEUE_EXCEPTION("gdImageCreateFromGd2Part()");
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img != NULL)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+
+/*
+ * We replace gdImageCreateFrom*Ptr() by methods using a String.
+ */
+static JSBool
+gd_sm_create_from_gd2_part_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       JSString        *str;
+       char            *bytes;
+       size_t          size;
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 5) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_STRING(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not a String");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[4])) {
+               QUEUE_EXCEPTION("Argument 5 not an Integer");
+               goto err;
+       }
+
+       str = JSVAL_TO_STRING(argv[0]);
+       if ((bytes = JS_GetStringBytes(str)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       size = JS_GetStringLength(str);
+
+       if ((img = gdImageCreateFromGd2PartPtr((int)size, bytes,
+           JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]),
+           JSVAL_TO_INT(argv[3]), JSVAL_TO_INT(argv[4]))) == NULL) {
+               QUEUE_EXCEPTION("GdImageCreateFromGd2PartPtr()");
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img != NULL)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gd_sm_create_from_wbmp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromWBMP, "gdImageCreateFromWBMP()");
+}
+
+static JSBool
+gd_sm_create_from_wbmp_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gd_sm_create_from_str_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromWBMPPtr, "gdImageCreateFromWBMPPtr()");
+}
+
+static JSBool
+gd_sm_create_from_xbm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gd_sm_create_from_file_i(cx, obj, argc, argv, rval,
+               gdImageCreateFromXbm, "gdImageCreateFromXbm()");
+}
+
+#ifdef HAVE_XPM
+static JSBool
+gd_sm_create_from_xpm(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, gdImagePtr (*funcptr)(FILE *), const char *funcname)
+{
+       const char      *bytes;
+       gdImagePtr      img = NULL;
+       JSObject        *o;
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_STRING(argv[0]) ||
+           (bytes = JS_GetStringBytes(argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a String");
+               goto err;
+       }
+
+       /* XXX Perform path sanity/access checking */
+       if ((img = gdImageCreateFromXpm(bytes)) == NULL) {
+               QUEUE_EXCEPTION("gdImageCreateFromXpm()");
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img != NULL)
+               gdImageDestroy(img);
+
+       return JS_FALSE;
+}
+#endif
+
+static JSBool
+gd_sm_true_color(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       int     col, i1, i2, i3;
+
+       if (argc != 3) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+
+       /* Since gdTrueColor is a macro, avoid side-effects */
+       i1 = JSVAL_TO_INT(argv[0]);
+       i2 = JSVAL_TO_INT(argv[1]);
+       i3 = JSVAL_TO_INT(argv[2]);
+       col = gdTrueColor(i1, i2, i3);
+       *rval = INT_TO_JSVAL(col);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gd_sm_true_color_alpha(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       int     col, i1, i2, i3, i4;
+
+       if (argc != 4) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               goto err;
+       }
+
+       /* Since gdTrueColorAlpha() is a macro, avoid side-effects */
+       i1 = JSVAL_TO_INT(argv[0]);
+       i2 = JSVAL_TO_INT(argv[1]);
+       i3 = JSVAL_TO_INT(argv[2]);
+       i4 = JSVAL_TO_INT(argv[3]);
+       col = gdTrueColorAlpha(i1, i2, i3, i4);
+       *rval = INT_TO_JSVAL(col);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_FALSE;
+}
+
+
+/*
+ * GDImage object control
+ */
+
+static JSObject *
+js_InitGDImageClass(JSContext *cx, JSObject *obj)
+{
+
+       return (JS_InitClass(cx, obj, NULL, &gdimage_class,
+           gdimage_constructor, 0, gdimage_properties, gdimage_methods, NULL,
+           NULL));
+}
+
+/* ARGSUSED */
+static JSBool
+gdimage_constructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       QUEUE_EXCEPTION("GDImage class not user-instanciable");
+
+       return JS_FALSE;
+}
+
+static void
+gdimage_finalize(JSContext *cx, JSObject *obj)
+{
+       gdImagePtr      img;
+
+       if ((img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL))
+           != NULL) {
+               gdImageDestroy(img);
+               (void) JS_SetPrivate(cx, obj, NULL);
+       }
+}
+
+
+/* GDImage object property setters/getters */
+static JSBool
+gdimage_get_property(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+       jsint           p;
+       gdImagePtr      img;
+
+       if (!JSVAL_IS_INT(id))
+               return JS_TRUE;
+       p = (int)JSVAL_TO_INT(id);
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       switch (p) {
+       case GDIMAGE_P_SX:
+               *vp = INT_TO_JSVAL(img->sx);
+               break;
+       case GDIMAGE_P_SY:
+               *vp = INT_TO_JSVAL(img->sy);
+               break;
+       }
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_set_property(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+{
+       jsint           p;
+       gdImagePtr      img;
+
+       if (!JSVAL_IS_INT(id))
+               return JS_TRUE;
+       p = (int)JSVAL_TO_INT(id);
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       switch (p) {
+               /* XXX No writable property yet */
+       }
+
+       return JS_TRUE;
+}
+
+
+/*
+ * GDImage object properties
+ */
+
+/*
+ * GDImage object methods
+ */
+
+static JSBool
+gdimage_m_image_destroy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageDestroy(img);
+       (void) JS_SetPrivate(cx, obj, NULL);
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_TRUE;
+}
+
+/*
+ * Called by multiple similar functions
+ */
+static JSBool
+gdimage_m_save_file_i0(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, void (*funcptr)(gdImagePtr, FILE *))
+{
+       FILE            *fh;
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       funcptr(img, fh);
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_save_file_i1(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, void (*funcptr)(gdImagePtr, FILE *, int))
+{
+       FILE            *fh;
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       funcptr(img, fh, JSVAL_TO_INT(argv[1]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_save_str_i0(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, void *(*funcptr)(gdImagePtr, int *), const char *funcname)
+{
+       gdImagePtr      img;
+       void            *data = NULL;
+       int             size;
+       JSString        *str;
+
+       if (argc != 0) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       if ((data = funcptr(img, &size)) == NULL) {
+               QUEUE_EXCEPTION(funcname);
+               goto err;
+       }
+
+       if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+       *rval = STRING_TO_JSVAL(str);
+       gdFree(data);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (data != NULL)
+               gdFree(data);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_save_str_i1(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, void *(*funcptr)(gdImagePtr, int *, int),
+    const char *funcname)
+{
+       gdImagePtr      img;
+       void            *data = NULL;
+       int             size;
+       JSString        *str;
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       if ((data = funcptr(img, &size, JSVAL_TO_INT(argv[0]))) == NULL) {
+               QUEUE_EXCEPTION(funcname);
+               goto err;
+       }
+
+       if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+       *rval = STRING_TO_JSVAL(str);
+       gdFree(data);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (data != NULL)
+               gdFree(data);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_jpeg(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_file_i1(cx, obj, argc, argv, rval, gdImageJpeg);
+}
+
+static JSBool
+gdimage_m_jpeg_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_str_i1(cx, obj, argc, argv, rval,
+           gdImageJpegPtr, "gdImageJpegPtr()");
+}
+
+static JSBool
+gdimage_m_gif(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_file_i0(cx, obj, argc, argv, rval, gdImageGif);
+}
+
+static JSBool
+gdimage_m_gif_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_str_i0(cx, obj, argc, argv, rval,
+           gdImageGifPtr, "gdImageGifPtr()");
+}
+
+static JSBool
+gdimage_m_gif_anim_begin(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       FILE            *fh;
+       gdImagePtr      img;
+
+       if (argc != 3) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageGifAnimBegin(img, fh, JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]));
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gif_anim_begin_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+       void            *data = NULL;
+       int             size;
+       JSString        *str;
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       if ((data = gdImageGifAnimBeginPtr(img, &size, JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]))) == NULL) {
+               QUEUE_EXCEPTION("gdImageGifAnimBeginPtr()");
+               goto err;
+       }
+
+       if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+       *rval = STRING_TO_JSVAL(str);
+       gdFree(data);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (data != NULL)
+               gdFree(data);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gif_anim_add(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       FILE            *fh;
+       gdImagePtr      img, img2;
+
+       if (argc != 7) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[4])) {
+               QUEUE_EXCEPTION("Argument 5 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[5])) {
+               QUEUE_EXCEPTION("Argument 6 not an Integer");
+               goto err;
+       }
+       if (JSVAL_IS_NULL(argv[6]))
+               img2 = NULL;
+       else {
+               JSObject        *o;
+
+               if (!JSVAL_IS_OBJECT(argv[6])) {
+                       QUEUE_EXCEPTION(
+                           "Argument 7 not Null or GDImage object");
+                       goto err;
+               }
+               o = JSVAL_TO_OBJECT(argv[6]);
+               if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+                       QUEUE_EXCEPTION(
+                           "Argument 7 not Null or GDImage object");
+                       goto err;
+               }
+
+               img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+               assert(img2 != NULL);
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageGifAnimAdd(img, fh, JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+           JSVAL_TO_INT(argv[4]), JSVAL_TO_INT(argv[5]), img2);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gif_anim_add_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img, img2;
+       void            *data = NULL;
+       int             size;
+       JSString        *str;
+
+       if (argc != 6) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[4])) {
+               QUEUE_EXCEPTION("Argument 5 not an Integer");
+               goto err;
+       }
+       if (JSVAL_IS_NULL(argv[5]))
+               img2 = NULL;
+       else {
+               JSObject        *o;
+
+               if (!JSVAL_IS_OBJECT(argv[5])) {
+                       QUEUE_EXCEPTION(
+                           "Argument 6 not Null or GDImage object");
+                       goto err;
+               }
+               o = JSVAL_TO_OBJECT(argv[6]);
+               if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+                       QUEUE_EXCEPTION(
+                           "Argument 6 not Null or GDImage object");
+                       goto err;
+               }
+
+               img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+               assert(img2 != NULL);
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       if ((data = gdImageGifAnimAddPtr(img, &size, JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+           JSVAL_TO_INT(argv[4]), img2)) == NULL) {
+               QUEUE_EXCEPTION("gdImageGifAnimAddPtr()");
+               goto err;
+       }
+
+       if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+       *rval = STRING_TO_JSVAL(str);
+       gdFree(data);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (data != NULL)
+               gdFree(data);
+
+       return JS_FALSE;
+}
+
+/*
+ * For consistency, GD authors should have made these two still require the
+ * gdImagePtr argument.  However, they don't... so we had to rewrite these.
+ * We however still present a consistent API and attach this method to the
+ * GDImage object.
+ */
+static JSBool
+gdimage_m_gif_anim_end(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       FILE    *fh;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               return JS_FALSE;
+       }
+
+       gdImageGifAnimEnd(fh);
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_gif_anim_end_str(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       void            *data = NULL;
+       int             size;
+       JSString        *str;
+
+       if (argc != 0) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+
+       if ((data = gdImageGifAnimEndPtr(&size)) == NULL) {
+               QUEUE_EXCEPTION("gdImageGifAnimEndPtr()");
+               goto err;
+       }
+
+       if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+       *rval = STRING_TO_JSVAL(str);
+       gdFree(data);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (data != NULL)
+               gdFree(data);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_png(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_file_i0(cx, obj, argc, argv, rval, gdImagePng);
+}
+
+static JSBool
+gdimage_m_png_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_str_i0(cx, obj, argc, argv, rval, gdImagePngPtr,
+           "gdImagePngPtr()");
+}
+
+static JSBool
+gdimage_m_png_ex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_file_i1(cx, obj, argc, argv, rval, gdImagePngEx);
+}
+
+static JSBool
+gdimage_m_png_ex_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_str_i1(cx, obj, argc, argv, rval,
+           gdImagePngPtrEx, "gdImagePngPtrEx()");
+}
+
+/*
+ * GD is inconsistent and gdImageWBMP() takes int argument before the FILE *.
+ * We however make it consistent in this API.
+ */
+static JSBool
+gdimage_m_wbmp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       FILE            *fh;
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageWBMP(img, JSVAL_TO_INT(argv[1]), fh);
+
+       return JS_TRUE;
+}
+
+/*
+ * GD documentation states that gdImageWBMPPtr() does't take an int, but it
+ * does after the FILE *, like gdImageWBMP() but with revesed arguments order.
+ * This function seemed consistent, at least.
+ */
+static JSBool
+gdimage_m_wbmp_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_str_i1(cx, obj, argc, argv, rval, gdImageWBMPPtr,
+           "gdImageWBMPPtr()");
+}
+
+static JSBool
+gdimage_m_gd(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_file_i0(cx, obj, argc, argv, rval, gdImageGd);
+}
+
+static JSBool
+gdimage_m_gd_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_save_str_i0(cx, obj, argc, argv, rval, gdImageGdPtr,
+           "gdImageGdPtr()");
+}
+
+static JSBool
+gdimage_m_gd2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       FILE            *fh;
+       gdImagePtr      img;
+
+       if (argc != 3) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((fh = file_fh(cx, argv[0])) == NULL) {
+               QUEUE_EXCEPTION("Argument 1 not a File object");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageGd2(img, fh, JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]));
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_gd2_str(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+       void            *data = NULL;
+       int             size;
+       JSString        *str;
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       /*
+        * Also an inconsistent GD function as it requires the int pointer
+        * after the other integer arguments.
+        */
+       if ((data = gdImageGd2Ptr(img, JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]), &size)) == NULL) {
+               QUEUE_EXCEPTION("gdImageGd2Ptr()");
+               goto err;
+       }
+
+       if ((str = JS_NewStringCopyN(cx, data, size)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+       *rval = STRING_TO_JSVAL(str);
+       gdFree(data);
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (data != NULL)
+               gdFree(data);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_truecolor_to_palette(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageTrueColorToPalette(img, JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_create_palette_from_truecolor(JSContext *cx, JSObject *obj,
+    uintN argc, jsval *argv, jsval *rval)
+{
+       gdImagePtr      img, img2 = NULL;
+       JSObject        *o;
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               goto err;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       if ((img2 = gdImageCreatePaletteFromTrueColor(img,
+           JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]))) == NULL) {
+               QUEUE_EXCEPTION("gdImageCreatePaletteFromTrueColor()");
+               goto err;
+       }
+
+       if ((o = JS_NewObject(cx, &gdimage_class, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_SetPrivate(cx, o, img2)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+       if (img2 != NULL)
+               gdFree(img2);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_set_pixel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 3) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageSetPixel(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_primitive5_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, void (*funcptr)(gdImagePtr, int, int, int, int, int))
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 5) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[4])) {
+               QUEUE_EXCEPTION("Argument 5 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       funcptr(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+           JSVAL_TO_INT(argv[4]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_line(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_primitive5_i(cx, obj, argc, argv, rval, gdImageLine);
+}
+
+static JSBool
+gdimage_m_dashed_line(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+           gdImageDashedLine);
+}
+
+/*
+ * Converts a JS array of integer pairs to a C gdPoint array, which must be
+ * freed by the caller on success.  On failure, we return NULL and
+ * automatically send an appropriate exception.  On success, we return the
+ * gdPoint array pointer and store the number of verticles stored in it via
+ * the provided size pointer.
+ */
+static gdPointPtr
+array_to_gdpoints_i(JSContext *cx, jsval a, int *size)
+{
+       JSObject        *o;
+       jsuint          len;
+       JSIdArray       *ida = NULL;
+       gdPointPtr      pts = NULL;
+       int             i, i2, i3;
+       jsval           id, val;
+
+       if (!JSVAL_IS_OBJECT(a) ||
+           !JS_IsArrayObject(cx, (o = JSVAL_TO_OBJECT(a)))) {
+               QUEUE_EXCEPTION("Argument not an Array object");
+               goto err;
+       }
+       if (!JS_GetArrayLength(cx, o, &len) || ((len & 1) != 0)) {
+               QUEUE_EXCEPTION("Array not holding even pairs");
+               goto err;
+       }
+
+       len /= 2;
+       if ((pts = malloc(sizeof(gdPoint) * len)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+
+       if ((ida = JS_Enumerate(cx, o)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       for (i3 = i2 = i = 0; i < ida->length; i++) {
+               JS_IdToValue(cx, ida->vector[i], &id);
+               if (!JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) ||
+                   JSVAL_IS_VOID(val))
+                       continue;
+               if (!JSVAL_IS_INT(val)) {
+                       QUEUE_EXCEPTION("Array elements not all Integers");
+                       goto err;
+               }
+               if ((i2++ & 1) == 0)
+                       pts[i3].x = JSVAL_TO_INT(val);
+               else
+                       pts[i3++].y = JSVAL_TO_INT(val);
+       }
+       JS_DestroyIdArray(cx, ida);
+       ida = NULL;
+
+       *size = len;
+       return pts;
+
+err:
+       if (ida != NULL)
+               JS_DestroyIdArray(cx, ida);
+       if (pts != NULL)
+               free(pts);
+       *size = 0;
+
+       return NULL;
+}
+
+/*
+ * Converts a JS array of integer pairs to a C int array, which must be
+ * freed by the caller on success.  On failure, we return NULL and
+ * automatically send an appropriate exception.  On success, we return the
+ * int array pointer and store the number of entries stored in it via
+ * the provided size pointer.
+ */
+static int *
+array_to_ints_i(JSContext *cx, jsval a, int *size)
+{
+       JSObject        *o;
+       jsuint          len;
+       JSIdArray       *ida = NULL;
+       int             *pts = NULL;
+       int             i, i2;
+       jsval           id, val;
+
+       if (!JSVAL_IS_OBJECT(a) ||
+           !JS_IsArrayObject(cx, (o = JSVAL_TO_OBJECT(a)))) {
+               QUEUE_EXCEPTION("Argument not an Array object");
+               goto err;
+       }
+       if (!JS_GetArrayLength(cx, o, &len)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       if ((pts = malloc(sizeof(int) * len)) == NULL) {
+               QUEUE_EXCEPTION("Out of memory!");
+               goto err;
+       }
+
+       if ((ida = JS_Enumerate(cx, o)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       for (i2 = i = 0; i < ida->length; i++) {
+               JS_IdToValue(cx, ida->vector[i], &id);
+               if (!JS_LookupElement(cx, o, JSVAL_TO_INT(id), &val) ||
+                   JSVAL_IS_VOID(val))
+                       continue;
+               if (!JSVAL_IS_INT(val)) {
+                       QUEUE_EXCEPTION("Array elements not all Integers");
+                       goto err;
+               }
+               pts[i2++] = JSVAL_TO_INT(val);
+       }
+       JS_DestroyIdArray(cx, ida);
+       ida = NULL;
+
+       *size = len;
+       return pts;
+
+err:
+       if (ida != NULL)
+               JS_DestroyIdArray(cx, ida);
+       if (pts != NULL)
+               free(pts);
+       *size = 0;
+
+       return NULL;
+}
+
+static JSBool
+gdimage_m_polygon_i(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval, void (*funcptr)(gdImagePtr, gdPointPtr, int, int))
+{
+       gdImagePtr      img;
+       gdPointPtr      pts = NULL;
+       int             size;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((pts = array_to_gdpoints_i(cx, argv[0], &size)) == NULL)
+               goto err;
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       funcptr(img, pts, size, JSVAL_TO_INT(argv[1]));
+       free(pts);
+
+       return JS_TRUE;
+
+err:
+       if (pts != NULL)
+               free(pts);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_polygon(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_polygon_i(cx, obj, argc, argv, rval, gdImagePolygon);
+}
+
+static JSBool
+gdimage_m_open_polygon(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_polygon_i(cx, obj, argc, argv, rval,
+           gdImageOpenPolygon);
+}
+
+static JSBool
+gdimage_m_rectangle(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+           gdImageRectangle);
+}
+
+static JSBool
+gdimage_m_filled_polygon(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_polygon_i(cx, obj, argc, argv, rval,
+           gdImageFilledPolygon);
+}
+
+static JSBool
+gdimage_m_filled_rectangle(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+
+       return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+           gdImageFilledRectangle);
+}
+
+static JSBool
+gdimage_m_arc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+       int             i;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 7) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       for (i = 0; i < 7; i++) {
+               if (!JSVAL_IS_INT(argv[i])) {
+                       QUEUE_EXCEPTION("Argument not an Integer");
+                       return JS_FALSE;
+               }
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageArc(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+           JSVAL_TO_INT(argv[4]), JSVAL_TO_INT(argv[5]),
+           JSVAL_TO_INT(argv[6]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_filled_arc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+       int             i;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 8) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       for (i = 0; i < 8; i++) {
+               if (!JSVAL_IS_INT(argv[i])) {
+                       QUEUE_EXCEPTION("Argument not an Integer");
+                       return JS_FALSE;
+               }
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageFilledArc(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]),
+           JSVAL_TO_INT(argv[4]), JSVAL_TO_INT(argv[5]),
+           JSVAL_TO_INT(argv[6]), JSVAL_TO_INT(argv[7]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_filled_ellipse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+
+       return gdimage_m_primitive5_i(cx, obj, argc, argv, rval,
+           gdImageFilledEllipse);
+}
+
+static JSBool
+gdimage_m_fill_to_border(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 4) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageFillToBorder(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_fill(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 3) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageFill(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_antialiased(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageSetAntiAliased(img, JSVAL_TO_INT(argv[0]));
+
+       return JS_TRUE;
+}
+
+/*
+ * Although documentation specifies that this gdImageSetAntialiasedDontBlend()
+ * requires two parameters, it actually requires three.
+ */
+static JSBool
+gdimage_m_set_antialiaseddontblend(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 2) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageSetAntiAliasedDontBlend(img, JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_brush(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img, img2;
+       JSObject        *o;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_OBJECT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+               return JS_FALSE;
+       }
+       o = JSVAL_TO_OBJECT(argv[0]);
+       if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+               QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+       img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+       assert(img2 != NULL);
+
+       /*
+        * Delete any previously associated GDImage property and reassign the
+        * new one so that the JS GC knows the dependency.
+        */
+       (void) JS_DeleteProperty(cx, obj, "gdimage_brush");
+       if (!JS_DefineProperty(cx, obj, "gdimage_brush", argv[0], NULL,
+           NULL, 0)) {
+               QUEUE_EXCEPTION("Internal error!");
+               return JS_FALSE;
+       }
+
+       gdImageSetBrush(img, img2);
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_tile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img, img2;
+       JSObject        *o;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_OBJECT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+               return JS_FALSE;
+       }
+       o = JSVAL_TO_OBJECT(argv[0]);
+       if (!JS_InstanceOf(cx, o, &gdimage_class, NULL)) {
+               QUEUE_EXCEPTION("Argument 1 not a GDImage object");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+       img2 = JS_GetInstancePrivate(cx, o, &gdimage_class, NULL);
+       assert(img2 != NULL);
+
+       /*
+        * Delete any previously associated GDImage property and reassign the
+        * new one so that the JS GC knows the dependency.
+        */
+       (void) JS_DeleteProperty(cx, obj, "gdimage_tile");
+       if (!JS_DefineProperty(cx, obj, "gdimage_tile", argv[0], NULL, NULL,
+           0)) {
+               QUEUE_EXCEPTION("Internal error!");
+               return JS_FALSE;
+       }
+
+       gdImageSetTile(img, img2);
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_style(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+       int             *pts = NULL;
+       int             size;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+       if ((pts = array_to_ints_i(cx, argv[0], &size)) == NULL)
+               goto err;
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       /* The supplied array is copied as of gd v1.1.1 and up. */
+       gdImageSetStyle(img, pts, size);
+       free(pts);
+
+       return JS_TRUE;
+
+err:
+       if (pts != NULL)
+               free(pts);
+
+       return JS_FALSE;
+}
+
+static JSBool
+gdimage_m_set_thickness(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageSetThickness(img, JSVAL_TO_INT(argv[0]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_alpha_blending(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_BOOLEAN(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not a Boolean");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageAlphaBlending(img, (int)JSVAL_TO_BOOLEAN(argv[0]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_save_alpha(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 1) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_BOOLEAN(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not a Boolean");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageSaveAlpha(img, (int)JSVAL_TO_BOOLEAN(argv[0]));
+
+       return JS_TRUE;
+}
+
+static JSBool
+gdimage_m_set_clip(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 4) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[3])) {
+               QUEUE_EXCEPTION("Argument 4 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageSetClip(img, JSVAL_TO_INT(argv[0]), JSVAL_TO_INT(argv[1]),
+           JSVAL_TO_INT(argv[2]), JSVAL_TO_INT(argv[3]));
+
+       return JS_TRUE;
+}
+
+/*
+ * Unlike gdImageGetClip() which fills four ints via their supplied pointers,
+ * this method returns an object with x1, y1, x2, y2 properties set.
+ */
+static JSBool
+gdimage_m_get_clip(JSContext *cx, JSObject *obj, uintN argc,
+    jsval *argv, jsval *rval)
+{
+       gdImagePtr      img;
+       int             x1, y1, x2, y2;
+       JSObject        *o;
+
+       if (argc != 0) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               goto err;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       gdImageGetClip(img, &x1, &y1, &x2, &y2);
+
+       if ((o = JS_NewObject(cx, NULL, NULL, NULL)) == NULL) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+       *rval = OBJECT_TO_JSVAL(o);
+       if (!JS_DefineProperty(cx, o, "x1", INT_TO_JSVAL(x1), NULL, NULL,
+           JSPROP_ENUMERATE) ||
+           !JS_DefineProperty(cx, o, "y1", INT_TO_JSVAL(y1), NULL, NULL,
+           JSPROP_ENUMERATE) ||
+           !JS_DefineProperty(cx, o, "x2", INT_TO_JSVAL(x2), NULL, NULL,
+           JSPROP_ENUMERATE) ||
+           !JS_DefineProperty(cx, o, "y2", INT_TO_JSVAL(y2), NULL, NULL,
+           JSPROP_ENUMERATE)) {
+               QUEUE_EXCEPTION("Internal error!");
+               goto err;
+       }
+
+       return JS_TRUE;
+
+err:
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       return JS_FALSE;
+}
+
+
+static JSBool
+gdimage_m_color_allocate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
+    jsval *rval)
+{
+       gdImagePtr      img;
+       int             col;
+
+       *rval = OBJECT_TO_JSVAL(NULL);
+
+       if (argc != 3) {
+               QUEUE_EXCEPTION("Wrong number of arguments");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[0])) {
+               QUEUE_EXCEPTION("Argument 1 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[1])) {
+               QUEUE_EXCEPTION("Argument 2 not an Integer");
+               return JS_FALSE;
+       }
+       if (!JSVAL_IS_INT(argv[2])) {
+               QUEUE_EXCEPTION("Argument 3 not an Integer");
+               return JS_FALSE;
+       }
+
+       img = JS_GetInstancePrivate(cx, obj, &gdimage_class, NULL);
+       assert(img != NULL);
+
+       col = gdImageColorAllocate(img, JSVAL_TO_INT(argv[0]),
+           JSVAL_TO_INT(argv[1]), JSVAL_TO_INT(argv[2]));
+       *rval = INT_TO_JSVAL(col);
+
+       return JS_TRUE;
+}
index a2a49d2..20fd99f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: js-sh.c,v 1.8 2006/10/18 05:07:48 mmondor Exp $ */
+/* $Id: js-sh.c,v 1.9 2006/10/24 12:42:51 mmondor Exp $ */
 
 /*
  * Copyright (c) 2004-2005, Matthew Mondor
@@ -172,7 +172,7 @@ main(int argc, char **argv)
                if (JS_EvaluateScript(cctx->ctx, cctx->global, file->data,
                    file->size, argv[1], 1, &rval)) {
                        str = JS_ValueToString(cctx->ctx, rval);
-                       (void) printf("Script result: %s\n",
+                       (void) fprintf(stderr, "Script result: %s\n",
                            JS_GetStringBytes(str));
                } else {
                        /* XXX how to obtain error and stack backtrace? */