/************************************************************************/ /* Copyright (C) 2002-2004 Paul Duncan, and various contributors. */ /* */ /* Permission is hereby granted, free of charge, to any person */ /* obtaining a copy of this software and associated documentation files */ /* (the "Software"), to deal in the Software without restriction, */ /* including without limitation the rights to use, copy, modify, merge, */ /* publish, distribute, sublicense, and/or sell copies of the Software, */ /* and to permit persons to whom the Software is furnished to do so, */ /* subject to the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies of the Software, its documentation and */ /* marketing & publicity materials, and acknowledgment shall be given */ /* in the documentation, materials and software packages that this */ /* Software was used. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /************************************************************************/ #include /* Note: X support is disabled in the Makefile; it currently does not * compile */ #ifndef X_DISPLAY_MISSING #include #endif /* !X_DISPLAY_MISSING */ #include #include #define UNUSED(a) ((void) (a)) #define VERSION "0.5.2" /****************************/ /* CLASS AND MODULE GLOBALS */ /****************************/ static VALUE mImlib2, mError, cFileError, cDeletedError, cBorder, mCache, mColor, mTextDir, cRgbaColor, cHsvaColor, cHlsaColor, cCmyaColor, cContext, cGradient, cImage, cFilter, cFont, cColorMod, cPolygon, mOp, mOperation, mEncoding; #ifndef X_DISPLAY_MISSING static VALUE mX11, cDisplay, cPixmap, cVisual, cDrawable, cColormap; #endif /* X_DISPLAY_MISSING */ /***************/ /* WORKAROUNDS */ /***************/ #ifdef DISABLE_DRAW_PIXEL_WORKAROUND static char draw_pixel_workaround = 0; #else static char draw_pixel_workaround = 1; #endif /* DISABLE_DRAW_PIXEL_WORKAROUND */ /**********************************/ /* Imlib2::FileError EXCEPTIONS */ /* (exceptions and error strings) */ /**********************************/ static struct { VALUE exception; char *name, *description; } imlib_errors[] = { { 0, "NONE", "No error" }, { 0, "FILE_DOES_NOT_EXIST", "File does not exist" }, { 0, "FILE_IS_DIRECTORY", "File is directory" }, { 0, "PERMISSION_DENIED_TO_READ", "Permission denied to read" }, { 0, "NO_LOADER_FOR_FILE_FORMAT", "No loader for file format" }, { 0, "PATH_TOO_LONG", "Path too long" }, { 0, "PATH_COMPONENT_NON_EXISTANT", "Path component nonexistant" }, { 0, "PATH_COMPONENT_NOT_DIRECTORY", "Path component not directory" }, { 0, "PATH_POINTS_OUTSIDE_ADDRESS_SPACE","Path points outside address space"}, { 0, "TOO_MANY_SYMBOLIC_LINKS", "Too many symbolic links" }, { 0, "OUT_OF_MEMORY", "Out of memory" }, { 0, "OUT_OF_FILE_DESCRIPTORS", "Out of file descriptors" }, { 0, "PERMISSION_DENIED_TO_WRITE", "Permission denied to write" }, { 0, "OUT_OF_DISK_SPACE", "Out of disk space" }, { 0, "UNKNOWN", "Unknown or unspecified error" } }; typedef struct { Imlib_Image im; } ImStruct; #define GET_AND_CHECK_IMAGE(src, image) do { \ Data_Get_Struct((src), ImStruct, (image)); \ if (!(image)->im) { \ rb_raise(cDeletedError, "image deleted"); \ return Qnil; \ } \ } while (0) /********************************/ /* COLOR CLASSES */ /* (RGBA is Imlib_Color struct) */ /********************************/ typedef struct { double hue, saturation, value; int alpha; } HsvaColor; typedef struct { double hue, lightness, saturation; int alpha; } HlsaColor; typedef struct { int cyan, magenta, yellow, alpha; } CmyaColor; /*********************/ /* UTILITY FUNCTIONS */ /*********************/ /* raise an Imlib2::FileError exception based on an Imlib2 error type */ static void raise_imlib_error(const char *path, int err) { char buf[1024]; /* sanity check on error message */ if (err < IMLIB_LOAD_ERROR_NONE || err > IMLIB_LOAD_ERROR_UNKNOWN) err = IMLIB_LOAD_ERROR_UNKNOWN; /* add filename and path to buffer */ snprintf(buf, sizeof(buf), "\"%s\": %s", path, imlib_errors[err].description); /* raise exception */ rb_raise(imlib_errors[err].exception, buf); } /* set the context color -- polymorphic based on color class */ static void set_context_color(VALUE color) { if (rb_obj_is_kind_of(color, cRgbaColor) == Qtrue) { Imlib_Color *c; Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_color(c->red, c->green, c->blue, c->alpha); } else if (rb_obj_is_kind_of(color, cHsvaColor) == Qtrue) { HsvaColor *c; Data_Get_Struct(color, HsvaColor, c); imlib_context_set_color_hsva(c->hue, c->saturation, c->value, c->alpha); } else if (rb_obj_is_kind_of(color, cHlsaColor) == Qtrue) { HlsaColor *c; Data_Get_Struct(color, HlsaColor, c); imlib_context_set_color_hsva(c->hue, c->lightness, c->saturation, c->alpha); } else if (rb_obj_is_kind_of(color, cCmyaColor) == Qtrue) { CmyaColor *c; Data_Get_Struct(color, CmyaColor, c); imlib_context_set_color_hsva(c->cyan, c->magenta, c->yellow, c->alpha); } else { rb_raise(rb_eTypeError, "Invalid argument type (not " "Imlib2::Color::RgbaColor, " "Imlib2::Color::HvsaColor, " "Imlib2::Color::HslaColor, or " "Imlib2::Color::CmyaColor)"); } } /* don't actually free this value, but make ruby think it's gone */ /* static void dont_free(void *val) { UNUSED(val) } */ /******************/ /* BORDER METHODS */ /******************/ /* * Returns a new Imlib2::Border object. * * Examples: * left, top, right, bottom = 10, 10, 20, 20 * border = Imlib2::Border.new left, top, right, bottom * * values = [10, 10, 20, 20] * border = Imlib2::Border.new values * * edges = { * 'left' => 10, * 'right' => 20, * 'top' => 10, * 'bottom' => 20, * } * border = Imlib2::Border.new edges */ VALUE border_new(int argc, VALUE *argv, VALUE klass) { Imlib_Border *border; VALUE b_o; border = malloc(sizeof(Imlib_Border)); memset(border, 0, sizeof(Imlib_Border)); b_o = Data_Wrap_Struct(klass, 0, free, border); rb_obj_call_init(b_o, argc, argv); return b_o; } /* * Imlib2::Border constructor. * * Parameters are identical to Imlib2::Border::new. */ static VALUE border_init(int argc, VALUE *argv, VALUE self) { Imlib_Border *border; Data_Get_Struct(self, Imlib_Border, border); switch (argc) { case 1: /* must be either an array or a hash */ switch (TYPE(argv[0])) { case T_HASH: border->left = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("left"))); border->top = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("top"))); border->right = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("right"))); border->bottom = NUM2INT(rb_hash_aref(argv[0],rb_str_new2("bottom"))); break; case T_ARRAY: border->left = NUM2INT(rb_ary_entry(argv[0], 0)); border->top = NUM2INT(rb_ary_entry(argv[0], 1)); border->right = NUM2INT(rb_ary_entry(argv[0], 2)); border->bottom = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: /* it's a list of values */ border->left = NUM2INT(argv[0]); border->top = NUM2INT(argv[1]); border->right = NUM2INT(argv[2]); border->bottom = NUM2INT(argv[3]); break; default: /* no initializing values */ break; } return self; } /* * Get the left width (in pixels) of a border. * * Examples: * edge = border.left * edge = border.l */ static VALUE border_left(VALUE self) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); return INT2FIX(b->left); } /* * Set the left width (in pixels) of a border. * * Examples: * border.left = 10 * border.l = 10 */ static VALUE border_set_left(VALUE self, VALUE val) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); b->left = NUM2INT(val); return val; } /* * Get the right width (in pixels) of a border. * * Examples: * edge = border.right * edge = border.r */ static VALUE border_right(VALUE self) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); return INT2FIX(b->right); } /* * Set the right width (in pixels) of a border. * * Examples: * border.right = 10 * border.r = 10 */ static VALUE border_set_right(VALUE self, VALUE val) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); b->right = NUM2INT(val); return val; } /* * Get the top height (in pixels) of a border. * * Examples: * edge = border.top * edge = border.t */ static VALUE border_top(VALUE self) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); return INT2FIX(b->top); } /* * Set the top height (in pixels) of a border. * * Examples: * border.top = 10 * border.t = 10 */ static VALUE border_set_top(VALUE self, VALUE val) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); b->top = NUM2INT(val); return val; } /* * Get the bottom height (in pixels) of a border. * * Examples: * edge = border.bottom * edge = border.b */ static VALUE border_bottom(VALUE self) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); return INT2FIX(b->bottom); } /* * Set the bottom height (in pixels) of a border. * * Examples: * border.bottom = 10 * border.b = 10 */ static VALUE border_set_bottom(VALUE self, VALUE val) { Imlib_Border *b; Data_Get_Struct(self, Imlib_Border, b); b->bottom = NUM2INT(val); return val; } /*****************/ /* CACHE METHODS */ /*****************/ /* * Return the size (in bytes) of the application-wide image cache. * * Examples: * size = Imlib2::Cache::get_image_cache * size = Imlib2::Cache::image_cache * size = Imlib2::Cache::image */ static VALUE cache_image(VALUE klass) { UNUSED(klass); return INT2FIX(imlib_get_cache_size()); } /* * Set the size (in bytes) of the application-wide image cache. * * Examples: * new_size = 16 * 1024 ** 2 # 16 megabytes * Imlib2::Cache::set_image_cache new_size * * new_size = 16 * 1024 ** 2 # 16 megabytes * Imlib2::Cache::image_cache = new_size * * new_size = 16 * 1024 ** 2 # 16 megabytes * Imlib2::Cache::image = new_size */ static VALUE cache_set_image(VALUE klass, VALUE val) { UNUSED(klass); imlib_set_cache_size(NUM2INT(val)); return Qtrue; } /* * Return the size (in bytes) of the application-wide font cache. * * Examples: * size = Imlib2::Cache::get_font_cache * size = Imlib2::Cache::font_cache * size = Imlib2::Cache::font */ static VALUE cache_font(VALUE klass) { UNUSED(klass); return INT2FIX(imlib_get_font_cache_size()); } /* * Set the size (in bytes) of the application-wide font cache. * Examples: * new_size = 8 * 1024 ** 2 # 8 megabytes * Imlib2::Cache::set_font_cache new_size * * new_size = 8 * 1024 ** 2 # 8 megabytes * Imlib2::Cache::font_cache = new_size * * new_size = 8 * 1024 ** 2 # 8 megabytes * Imlib2::Cache::font = new_size */ static VALUE cache_set_font(VALUE klass, VALUE val) { UNUSED(klass); imlib_set_font_cache_size(NUM2INT(val)); return Qtrue; } /* * Flush and return the new size (in bytes) of the application-wide font * cache. * * Example: * new_size = Imlib2::Cache::flush_font_cache */ static VALUE cache_flush_font(VALUE klass) { imlib_flush_font_cache(); return cache_font(klass); } /**********************/ /* RGBA COLOR METHODS */ /**********************/ /* * Returns a new Imlib2::Color::RgbaColor. * * Examples: * r, g, b, a = 255, 0, 0, 255 * border = Imlib2::Color::RgbaColor.new r, g, b, a * * values = [255, 0, 0, 255] * border = Imlib2::Color::RgbaColor.new values * */ VALUE rgba_color_new(int argc, VALUE *argv, VALUE klass) { Imlib_Color *color; VALUE c_o; color = malloc(sizeof(Imlib_Color)); memset(color, 0, sizeof(Imlib_Color)); c_o = Data_Wrap_Struct(klass, 0, free, color); rb_obj_call_init(c_o, argc, argv); return c_o; } /* * Imlib2::Color::RgbaColor constructor. * * Parameters are identical to Imlib2::Color::RgbaColor::new. */ static VALUE rgba_color_init(int argc, VALUE *argv, VALUE self) { Imlib_Color *color = NULL; Data_Get_Struct(self, Imlib_Color, color); switch (argc) { case 1: /* must be either an array or a hash */ switch (TYPE(argv[0])) { case T_HASH: color->red = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("red"))); color->green = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("green"))); color->blue = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("blue"))); color->alpha = NUM2INT(rb_hash_aref(argv[0],rb_str_new2("alpha"))); break; case T_ARRAY: color->red = NUM2INT(rb_ary_entry(argv[0], 0)); color->green = NUM2INT(rb_ary_entry(argv[0], 1)); color->blue = NUM2INT(rb_ary_entry(argv[0], 2)); color->alpha = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid arguments (not array or hash)"); } break; case 4: /* it's a list of values */ color->red = NUM2INT(argv[0]); color->green = NUM2INT(argv[1]); color->blue = NUM2INT(argv[2]); color->alpha = NUM2INT(argv[3]); break; default: /* no initializing values */ break; } return self; } /* * Get the red element of a RgbaColor object. * * Examples: * amount = color.red * amount = color.r */ static VALUE rgba_color_red(VALUE self) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); return INT2FIX(b->red); } /* * Set the red element of a RgbaColor object. * * Examples: * color.red = 255 * color.r = 255 */ static VALUE rgba_color_set_red(VALUE self, VALUE val) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); b->red = NUM2INT(val); return val; } /* * Get the blue element of a RgbaColor object. * * Examples: * amount = color.blue * amount = color.b */ static VALUE rgba_color_blue(VALUE self) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); return INT2FIX(b->blue); } /* * Set the blue element of a RgbaColor object. * * Examples: * color.blue = 255 * color.b = 255 */ static VALUE rgba_color_set_blue(VALUE self, VALUE val) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); b->blue = NUM2INT(val); return val; } /* * Get the green element of a RgbaColor object. * * Examples: * amount = color.green * amount = color.g */ static VALUE rgba_color_green(VALUE self) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); return INT2FIX(b->green); } /* * Set the green element of a RgbaColor object. * * Examples: * color.green = 255 * color.g = 255 */ static VALUE rgba_color_set_green(VALUE self, VALUE val) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); b->green = NUM2INT(val); return val; } /* * Get the alpha element of a RgbaColor object. * * Examples: * amount = color.alpha * amount = color.a */ static VALUE rgba_color_alpha(VALUE self) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); return INT2FIX(b->alpha); } /* * Set the alpha element of a RgbaColor object. * * Examples: * color.alpha = 255 * color.a = 255 */ static VALUE rgba_color_set_alpha(VALUE self, VALUE val) { Imlib_Color *b; Data_Get_Struct(self, Imlib_Color, b); b->alpha = NUM2INT(val); return val; } /**********************/ /* HSVA COLOR METHODS */ /**********************/ /* * Returns a new Imlib2::Color::HsvaColor. * * Examples: * h, s, v, a = 255, 0, 0, 255 * border = Imlib2::Color::HsvaColor.new h, s, v, a * * values = [255, 0, 0, 255] * border = Imlib2::Color::HsvaColor.new values * */ VALUE hsva_color_new(int argc, VALUE *argv, VALUE klass) { HsvaColor *color; VALUE c_o; color = malloc(sizeof(HsvaColor)); memset(color, 0, sizeof(HsvaColor)); c_o = Data_Wrap_Struct(klass, 0, free, color); rb_obj_call_init(c_o, argc, argv); return c_o; } /* * Imlib2::Color::HsvaColor constructor. * * Parameters are identical to Imlib2::Color::HsvaColor::new. */ static VALUE hsva_color_init(int argc, VALUE *argv, VALUE self) { HsvaColor *color; Data_Get_Struct(self, HsvaColor, color); switch (argc) { case 1: /* must be either an array or a hash */ switch (TYPE(argv[0])) { case T_HASH: color->hue = NUM2DBL(rb_hash_aref(argv[0], rb_str_new2("hue"))); color->saturation = NUM2DBL(rb_hash_aref(argv[0], rb_str_new2("saturation"))); color->value = NUM2DBL(rb_hash_aref(argv[0], rb_str_new2("value"))); color->alpha = NUM2INT(rb_hash_aref(argv[0],rb_str_new2("alpha"))); break; case T_ARRAY: color->hue = NUM2DBL(rb_ary_entry(argv[0], 0)); color->saturation = NUM2DBL(rb_ary_entry(argv[0], 1)); color->value = NUM2DBL(rb_ary_entry(argv[0], 2)); color->alpha = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: /* it's a list of values */ color->hue = NUM2DBL(argv[0]); color->saturation = NUM2DBL(argv[1]); color->value = NUM2DBL(argv[2]); color->alpha = NUM2INT(argv[3]); break; default: /* no initializing values */ break; } return self; } /* * Get the hue element of a HsvaColor object. * * Examples: * amount = color.hue * amount = color.h */ static VALUE hsva_color_hue(VALUE self) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); return rb_float_new(b->hue); } /* * Set the hue element of a HsvaColor object. * * Examples: * color.hue = 255 * color.h = 255 */ static VALUE hsva_color_set_hue(VALUE self, VALUE val) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); b->hue = NUM2DBL(val); return val; } /* * Get the value element of a HsvaColor object. * * Examples: * amount = color.value * amount = color.v */ static VALUE hsva_color_value(VALUE self) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); return rb_float_new(b->value); } /* * Set the value element of a HsvaColor object. * * Examples: * color.value = 255 * color.v = 255 */ static VALUE hsva_color_set_value(VALUE self, VALUE val) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); b->value = NUM2DBL(val); return val; } /* * Get the saturation element of a HsvaColor object. * * Examples: * amount = color.saturation * amount = color.s */ static VALUE hsva_color_saturation(VALUE self) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); return rb_float_new(b->saturation); } /* * Set the saturation element of a HsvaColor object. * * Examples: * color.saturation = 255 * color.s = 255 */ static VALUE hsva_color_set_saturation(VALUE self, VALUE val) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); b->saturation = NUM2DBL(val); return val; } /* * Get the alpha element of a HsvaColor object. * * Examples: * amount = color.alpha * amount = color.a */ static VALUE hsva_color_alpha(VALUE self) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); return INT2FIX(b->alpha); } /* * Set the alpha element of a HsvaColor object. * * Examples: * color.alpha = 255 * color.a = 255 */ static VALUE hsva_color_set_alpha(VALUE self, VALUE val) { HsvaColor *b; Data_Get_Struct(self, HsvaColor, b); b->alpha = NUM2INT(val); return val; } /**********************/ /* HLSA COLOR METHODS */ /**********************/ /* * Returns a new Imlib2::Color::HlsaColor. * * Examples: * h, l, s, a = 255, 0, 0, 255 * border = Imlib2::Color::HlsaColor.new h, l, s, a * * values = [255, 0, 0, 255] * border = Imlib2::Color::HlsaColor.new values * */ VALUE hlsa_color_new(int argc, VALUE *argv, VALUE klass) { HlsaColor *color; VALUE c_o; color = malloc(sizeof(HlsaColor)); memset(color, 0, sizeof(HlsaColor)); c_o = Data_Wrap_Struct(klass, 0, free, color); rb_obj_call_init(c_o, argc, argv); return c_o; } /* * Imlib2::Color::HlsaColor constructor. * * Parameters are identical to Imlib2::Color::HlsaColor::new. */ static VALUE hlsa_color_init(int argc, VALUE *argv, VALUE self) { HlsaColor *color; Data_Get_Struct(self, HlsaColor, color); switch (argc) { case 1: /* must be either an array or a hash */ switch (TYPE(argv[0])) { case T_HASH: color->hue = NUM2DBL(rb_hash_aref(argv[0], rb_str_new2("hue"))); color->lightness = NUM2DBL(rb_hash_aref(argv[0], rb_str_new2("lightness"))); color->saturation = NUM2DBL(rb_hash_aref(argv[0], rb_str_new2("saturation"))); color->alpha = NUM2INT(rb_hash_aref(argv[0],rb_str_new2("alpha"))); break; case T_ARRAY: color->hue = NUM2DBL(rb_ary_entry(argv[0], 0)); color->lightness = NUM2DBL(rb_ary_entry(argv[0], 1)); color->saturation = NUM2DBL(rb_ary_entry(argv[0], 2)); color->alpha = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: /* it's a list of values */ color->hue = NUM2DBL(argv[0]); color->lightness = NUM2DBL(argv[1]); color->saturation = NUM2DBL(argv[2]); color->alpha = NUM2INT(argv[3]); break; default: /* no initializing values */ break; } return self; } /* * Get the hue element of a HlsaColor object. * * Examples: * amount = color.hue * amount = color.h */ static VALUE hlsa_color_hue(VALUE self) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); return rb_float_new(b->hue); } /* * Set the hue element of a HlsaColor object. * * Examples: * color.hue = 255 * color.h = 255 */ static VALUE hlsa_color_set_hue(VALUE self, VALUE val) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); b->hue = NUM2DBL(val); return val; } /* * Get the saturation element of a HlsaColor object. * * Examples: * amount = color.saturation * amount = color.s */ static VALUE hlsa_color_saturation(VALUE self) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); return rb_float_new(b->saturation); } /* * Set the saturation element of a HlsaColor object. * * Examples: * color.saturation = 255 * color.h = 255 */ static VALUE hlsa_color_set_saturation(VALUE self, VALUE val) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); b->saturation = NUM2DBL(val); return val; } /* * Get the lightness element of a HlsaColor object. * * Examples: * amount = color.lightness * amount = color.l */ static VALUE hlsa_color_lightness(VALUE self) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); return rb_float_new(b->lightness); } /* * Set the lightness element of a HlsaColor object. * * Examples: * color.lightness = 255 * color.l = 255 */ static VALUE hlsa_color_set_lightness(VALUE self, VALUE val) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); b->lightness = NUM2DBL(val); return val; } /* * Get the alpha element of a HlsaColor object. * * Examples: * amount = color.alpha * amount = color.a */ static VALUE hlsa_color_alpha(VALUE self) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); return INT2FIX(b->alpha); } /* * Set the alpha element of a HlsaColor object. * * Examples: * color.alpha = 255 * color.a = 255 */ static VALUE hlsa_color_set_alpha(VALUE self, VALUE val) { HlsaColor *b; Data_Get_Struct(self, HlsaColor, b); b->alpha = NUM2INT(val); return val; } /**********************/ /* CMYA COLOR METHODS */ /**********************/ /* * Returns a new Imlib2::Color::CmyaColor. * * Examples: * c, m, y, a = 255, 0, 0, 255 * border = Imlib2::Color::CmyaColor.new c, m, y, a * * values = [255, 0, 0, 255] * border = Imlib2::Color::CmyaColor.new values * */ VALUE cmya_color_new(int argc, VALUE *argv, VALUE klass) { CmyaColor *color; VALUE c_o; color = malloc(sizeof(CmyaColor)); memset(color, 0, sizeof(CmyaColor)); c_o = Data_Wrap_Struct(klass, 0, free, color); rb_obj_call_init(c_o, argc, argv); return c_o; } /* * Imlib2::Color::CmyaColor constructor. * * Parameters are identical to Imlib2::Color::CmyaColor::new. */ static VALUE cmya_color_init(int argc, VALUE *argv, VALUE self) { CmyaColor *color; Data_Get_Struct(self, CmyaColor, color); switch (argc) { case 1: /* must be either an array or a hash */ switch (TYPE(argv[0])) { case T_HASH: color->cyan = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("cyan"))); color->magenta = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("magenta"))); color->yellow = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("yellow"))); color->alpha = NUM2INT(rb_hash_aref(argv[0],rb_str_new2("alpha"))); break; case T_ARRAY: color->cyan = NUM2INT(rb_ary_entry(argv[0], 0)); color->magenta = NUM2INT(rb_ary_entry(argv[0], 1)); color->yellow = NUM2INT(rb_ary_entry(argv[0], 2)); color->alpha = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: /* it's a list of values */ color->cyan = NUM2INT(argv[0]); color->magenta = NUM2INT(argv[1]); color->yellow = NUM2INT(argv[2]); color->alpha = NUM2INT(argv[3]); break; default: /* no initializing values */ break; } return self; } /* * Get the cyan element of a CmyaColor object. * * Examples: * amount = color.cyan * amount = color.c */ static VALUE cmya_color_cyan(VALUE self) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); return INT2FIX(b->cyan); } /* * Set the cyan element of a CmyaColor object. * * Examples: * color.cyan = 255 * color.c = 255 */ static VALUE cmya_color_set_cyan(VALUE self, VALUE val) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); b->cyan = NUM2INT(val); return val; } /* * Get the yellow element of a CmyaColor object. * * Examples: * amount = color.yellow * amount = color.y */ static VALUE cmya_color_yellow(VALUE self) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); return INT2FIX(b->yellow); } /* * Set the yellow element of a CmyaColor object. * * Examples: * color.yellow = 255 * color.y = 255 */ static VALUE cmya_color_set_yellow(VALUE self, VALUE val) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); b->yellow = NUM2INT(val); return val; } /* * Get the magenta element of a CmyaColor object. * * Examples: * amount = color.magenta * amount = color.m */ static VALUE cmya_color_magenta(VALUE self) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); return INT2FIX(b->magenta); } /* * Set the magenta element of a CmyaColor object. * * Examples: * color.magenta = 255 * color.m = 255 */ static VALUE cmya_color_set_magenta(VALUE self, VALUE val) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); b->magenta = NUM2INT(val); return val; } /* * Get the alpha element of a CmyaColor object. * * Examples: * amount = color.alpha * amount = color.a */ static VALUE cmya_color_alpha(VALUE self) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); return INT2FIX(b->alpha); } /* * Set the alpha element of a CmyaColor object. * * Examples: * color.alpha = 255 * color.a = 255 */ static VALUE cmya_color_set_alpha(VALUE self, VALUE val) { CmyaColor *b; Data_Get_Struct(self, CmyaColor, b); b->alpha = NUM2INT(val); return val; } /***********************/ /* X11 DISPLAY METHODS */ /***********************/ #ifndef X_DISPLAY_MISSING static void disp_free(void *disp) { XFree(disp); } /* * Open a connection to the specified X11 Display (or the default * display if nil is specified). Raises a RunTimeError exception if a * connection to the specified display could not be opened. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * disp = Imlib2::X11::Display.new ':0.0' * */ VALUE display_new(VALUE klass, VALUE display) { Display *disp; VALUE self; if (display == Qnil) { char *env = getenv("DISPLAY"); disp = XOpenDisplay(env); } else { disp = XOpenDisplay(StringValuePtr(display)); } if (!disp) rb_raise(rb_eRuntimeError, "Couldn't open display"); self = Data_Wrap_Struct(klass, 0, disp_free, disp); rb_obj_call_init(self, 0, NULL); return self; } /* * Constructor for Imlib2::X11::Display object. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * This method is currently just a placeholder. * */ static VALUE display_init(VALUE self) { return self; } /**********************/ /* X11 VISUAL METHODS */ /**********************/ static void visual_free(void *vis) { /* FIXME: we might be leaking visuals here, but I don't think we * should be freeing the default one */ /* XFree(vis); */ } /* * Get the default X11 Visual on the specified Display and screen. * Raises a RunTimeError exception if the visual could not be created. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * vis = Imlib2::X11::Visual.new display, screen_num * */ VALUE visual_new(VALUE klass, VALUE display, VALUE screen) { Display *disp; Visual *vis; VALUE self; if (display == Qnil) display = display_new(cDisplay, Qnil); Data_Get_Struct(display, Display, disp); vis = DefaultVisual(disp, NUM2INT(screen)); self = Data_Wrap_Struct(klass, 0, visual_free, vis); rb_obj_call_init(self, 0, NULL); return self; } /* * Constructor for Imlib2::X11::Visual object. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * This method is currently just a placeholder. * */ static VALUE visual_init(VALUE self) { return self; } /************************/ /* X11 COLORMAP METHODS */ /************************/ static void cmap_free(void *vis) { /* FIXME: need to wrap colormap in struct to preserve display */ /* XFree(vis); */ } /* * Get the default X11 Colormap on the specified Display and screen. * Raises a RunTimeError exception if the colormap could not be * allocated. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * cmap = Imlib2::X11::Colormap.new display, screen_num * */ VALUE cmap_new(VALUE klass, VALUE display, VALUE screen) { Display *disp; Colormap *cmap; VALUE self; if (display == Qnil) display = display_new(cDisplay, Qnil); Data_Get_Struct(display, Display, disp); cmap = malloc(sizeof(Colormap)); *cmap = DefaultColormap(disp, NUM2INT(screen)); self = Data_Wrap_Struct(klass, 0, dont_free, cmap); rb_obj_call_init(self, 0, NULL); return self; } /* * Constructor for Imlib2::X11::Colormap object. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * This method is currently just a placeholder. * */ static VALUE cmap_init(VALUE self) { return self; } /************************/ /* X11 DRAWABLE METHODS */ /************************/ /* * Constructor for Imlib2::X11::Drawable object. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * This method is currently just a placeholder. * */ static VALUE drawable_init(VALUE self) { return self; } #endif /* X_DISPLAY_MISSING */ /*****************/ /* IMAGE METHODS */ /*****************/ static void im_struct_free(void *val) { ImStruct *im = (ImStruct*) val; if (im) { if (im->im) { imlib_context_set_image(im->im); imlib_free_image(); } free(im); } } /* * Returns a new Imlib2::Image with the specified width and height. * * Examples: * width, height = 640, 480 * image = Imlib2::Image.new width, height * * width, height = 320, 240 * image = Imlib2::Image.create width, height */ VALUE image_new(VALUE klass, VALUE w, VALUE h) { ImStruct *im = malloc(sizeof(ImStruct)); VALUE im_o; im->im = imlib_create_image(NUM2INT(w), NUM2INT(h)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); rb_obj_call_init(im_o, 0, NULL); return im_o; } /*********************************/ /* DRAW PIXEL WORKAROUND METHODS */ /*********************************/ /* * Are we using the buggy imlib_image_draw_pixel() work-around? * * Versions of Imlib2 up to and including 1.0.5 had a broken * imlib_image_draw_pixel() call. Imlib2-Ruby has a work-around, which * simulates drawing a pixel with a 1x1 rectangle. This method allows * you to check whether the work-around behavior is enabled. * * Examples: * puts 'work-around is enabled' if Imlib2::Image::draw_pixel_workaround? * puts 'work-around is enabled' if Imlib2::Image::bypass_draw_pixel? * */ VALUE image_dp_workaround(VALUE klass) { UNUSED(klass); return draw_pixel_workaround ? Qtrue : Qfalse; } /* * Enable or disable imlib_image_draw_pixel() work-around. * * Versions of Imlib2 up to and including 1.0.5 had a broken * imlib_image_draw_pixel() call. Imlib2-Ruby has a work-around, which * simulates drawing a pixel with a 1x1 rectangle. This method allows * you to enable or disable the work-around behavior. * * Examples: * Imlib2::Image::draw_pixel_workaround = false * Imlib2::Image::bypass_draw_pixel = false * */ VALUE image_set_dp_workaround(VALUE klass, VALUE val) { UNUSED(klass); draw_pixel_workaround = (val == Qtrue); return val; } /* * Returns a new Imlib2::Image initialized with the specified data. * * Examples: * other_image = Imlib2::Image.load 'sample_file.png' * width, height = other_image.width, other_image.height * data = other_image.data_for_reading_only * image = Imlib2::Image.create_using_data width, height, data * */ VALUE image_create_using_data(VALUE klass, VALUE w, VALUE h, VALUE data) { ImStruct *im; VALUE im_o; im = malloc(sizeof(ImStruct)); im->im = imlib_create_image_using_data(NUM2INT(w), NUM2INT(h), (DATA32 *) StringValuePtr (data)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); rb_obj_call_init(im_o, 0, NULL); return im_o; } /* * Returns a new Imlib2::Image initialized with the specified data. * * Examples: * other_image = Imlib2::Image.load 'sample_file.png' * width, height = other_image.width, other_image.height * data = other_image.data * image = Imlib2::Image.create_using_copied_data width, height, data * */ VALUE image_create_using_copied_data(VALUE klass, VALUE w, VALUE h, VALUE data) { ImStruct *im; VALUE im_o; im = malloc(sizeof(ImStruct)); im->im = imlib_create_image_using_copied_data(NUM2INT(w), NUM2INT(h), (DATA32 *) StringValuePtr (data)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); rb_obj_call_init(im_o, 0, NULL); return im_o; } /* * Load an Imlib2::Image from a file (throws exceptions). * * Examples: * image = Imlib2::Image.load 'sample_file.png' * * begin * image = Imlib2::Image.load 'sample_file.png' * rescue Imlib2::FileError * $stderr.puts 'Couldn't load file: ' + $! * end * */ static VALUE image_load(VALUE klass, VALUE filename) { ImStruct *im; Imlib_Image iim; Imlib_Load_Error err; VALUE im_o = Qnil; char *path; /* grab filename */ path = StringValuePtr(filename); iim = imlib_load_image_with_error_return(path, &err); if (err == IMLIB_LOAD_ERROR_NONE) { im = malloc(sizeof(ImStruct)); im->im = iim; im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); if (rb_block_given_p()) rb_yield(im_o); } else { /* there was an error loading -- throw an exception if we weren't * passed a block */ if (!rb_block_given_p()) raise_imlib_error(path, err); } return im_o; } /* * Load an Imlib2::Image from a file (no exceptions or error). * * Imlib2::Image::load_image() provides access to the low-level * imlib_load_image() function. You probably want to use * Imlib2::Image::load() instead of Imlib2::Image::load_image(). * * Examples: * image = Imlib2::Image.load_image 'sample_file.png' * */ static VALUE image_load_image(VALUE klass, VALUE filename) { ImStruct *im = malloc(sizeof(ImStruct)); VALUE im_o; im->im = imlib_load_image(StringValuePtr(filename)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); return im_o; } /* * Load an Imlib2::Image from a file (no exceptions or error). * * Imlib2::Image::load_immediately() provides access to the low-level * imlib_load_image_immediately() function. You probably want to use * Imlib2::Image::load() instead of this function. * * Examples: * image = Imlib2::Image.load_immediately 'sample_file.png' * */ static VALUE image_load_immediately(VALUE klass, VALUE filename) { ImStruct *im = malloc(sizeof(ImStruct)); VALUE im_o; im->im = imlib_load_image_immediately(StringValuePtr(filename)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); return im_o; } /* * Load an Imlib2::Image from a file (no caching, exception, or error). * * Imlib2::Image::load_without_cache() provides access to the low-level * imlib_load_image_without_cache() function. You probably want to use * Imlib2::Image::load() instead of this function. * * Examples: * image = Imlib2::Image.load_without_cache 'sample_file.png' * */ static VALUE image_load_without_cache(VALUE klass, VALUE filename) { ImStruct *im = malloc(sizeof(ImStruct)); VALUE im_o; im->im = imlib_load_image_without_cache(StringValuePtr(filename)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); return im_o; } /* * Load an Imlib2::Image from a file (no caching, deferred loading, * exceptions, or errors). * * Imlib2::Image::load_immediately_without_cache() provides access to the * low-level imlib_load_image_immediately_without_cache() function. You * probably want to use Imlib2::Image::load() instead of this function. * * Examples: * image = Imlib2::Image.load_immediately_without_cache 'sample_file.png' * */ static VALUE image_load_immediately_without_cache(VALUE klass, VALUE filename) { ImStruct *im = malloc(sizeof(ImStruct)); VALUE im_o; im->im = imlib_load_image_immediately_without_cache(StringValuePtr(filename)); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); return im_o; } /* * Load an Imlib2::Image from a file with a hash of the error value and * the image. * * Imlib2::Image::load_with_error_return() provides access to the * low-level imlib_load_image_with_error_return() function. You * probably want to use Imlib2::Image::load() instead of this function. * * Examples: * hash = Imlib2::Image.load_with_error_return 'sample_file.png' * if hash['error'] == 0 # 0 is no error * image = hash['image'] * end * */ static VALUE image_load_with_error_return(VALUE klass, VALUE filename) { ImStruct *im = malloc(sizeof(ImStruct)); Imlib_Load_Error er; VALUE hash, im_o; im->im = imlib_load_image_with_error_return(StringValuePtr(filename), &er); im_o = Data_Wrap_Struct(klass, 0, im_struct_free, im); hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("image"), im_o); rb_hash_aset(hash, rb_str_new2("error"), INT2FIX(er)); return hash; } /* * Save an Imlib2::Image to a file (throws an exception on error). * * Examples: * image.save 'output_file.png' * * filename = 'output_file.jpg' * begin * image.save filename * rescue Imlib2::FileError * $stderr.puts "Couldn't save file \"#{filename}\": " + $! * end * */ static VALUE image_save(VALUE self, VALUE val) { ImStruct *im; Imlib_Load_Error er; char *path; path = StringValuePtr(val); GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_save_image_with_error_return(path, &er); if (er == IMLIB_LOAD_ERROR_NONE) return self; if (er > IMLIB_LOAD_ERROR_UNKNOWN) er = IMLIB_LOAD_ERROR_UNKNOWN; raise_imlib_error(path, er); return Qnil; } /* * Save an Imlib2::Image to a file (no exception or error). * * Provides access to the low-level imlib_save_image() call. You * probably want to use Imlib2::Image::save() instead. * * Examples: * image.save_image 'output_file.png' * */ static VALUE image_save_image(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_save_image(StringValuePtr(val)); return self; } /* * Save an Imlib2::Image to a file (error returned as number). * * Provides access to the low-level imlib_save_image_with_error_return() * call. You probably want to use Imlib2::Image::save() instead. * * Examples: * error = image.save_with_error_return 'output_file.png' * puts 'an error occurred' unless error == 0 * */ static VALUE image_save_with_error_return(VALUE self, VALUE val) { ImStruct *im; Imlib_Load_Error er; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_save_image_with_error_return(StringValuePtr(val), &er); if (er > IMLIB_LOAD_ERROR_UNKNOWN) er = IMLIB_LOAD_ERROR_UNKNOWN; return INT2FIX(er); } /* * Copy an Imlib2::Image * * Examples: * new_image = old_image.clone * new_image = old_image.dup * */ static VALUE image_clone(VALUE self) { ImStruct *old_im, *new_im; VALUE im_o; new_im = malloc(sizeof(ImStruct)); GET_AND_CHECK_IMAGE(self, old_im); imlib_context_set_image(old_im->im); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); return im_o; } /* * Imlib2::Image constructor (currently just an empty placeholder). * */ static VALUE image_initialize(VALUE self) { return self; } /* * Free an Imlib2::Image object, and (optionally) de-cache it as well. * * Note: Any future operations on this image will raise an exception. * * Examples: * # free image * im.delete! * * # free image, and de-cache it too * im.delete!(true) * */ static VALUE image_delete(int argc, VALUE *argv, VALUE self) { ImStruct *im; /* get image */ GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); /* free image, and possibly de-cache it as well */ if (argc > 0 && argv[0] != Qnil && argv[0] != Qfalse) imlib_free_image_and_decache(); else imlib_free_image(); /* set struct ptr to NULL */ im->im = NULL; return Qnil; } /* * Return the width of an Imlib2::Image. * * Examples: * w = image.width * w = image.w * */ static VALUE image_width(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); return INT2FIX(imlib_image_get_width()); } /* * Return the height of an Imlib2::Image. * * Examples: * h = image.height * h = image.h * */ static VALUE image_height(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); return INT2FIX(imlib_image_get_height()); } /* * Return the filename of an Imlib2::Image. * * Examples: * path = image.filename * */ static VALUE image_filename(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); return rb_str_new2(imlib_image_get_filename()); } /* * Return a copy of an image's raw 32-bit data. * * Examples: * raw = image.data * */ static VALUE image_data(VALUE self) { ImStruct *im; int w, h; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); w = imlib_image_get_width(); h = imlib_image_get_height(); return rb_str_new((char*) imlib_image_get_data(), h * w * 4); } /* * Return a read-only reference to an image's raw 32-bit data. * * Examples: * RAW_DATA = image.data_for_reading_only * RAW_DATA = image.data! * */ static VALUE image_data_ro(VALUE self) { ImStruct *im; int w, h; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); w = imlib_image_get_width(); h = imlib_image_get_height(); return rb_str_new((char*) imlib_image_get_data_for_reading_only(), h * w * 4); } /* * Fill an image using raw 32-bit data. * * Note: The new data buffer must be the same size (in bytes) as the * original data buffer. * * Examples: * RAW_DATA = other_image.data! * image.put_data RAW_DATA * * RAW_DATA = other_image.data! * image.data = RAW_DATA * */ static VALUE image_put_data(VALUE self, VALUE str) { ImStruct *im; DATA32 *old_data, *new_data; int w, h, old_size; /* get image, check it, then set the context */ GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); /* get old data, calculate buffer size from width and height */ old_data = imlib_image_get_data(); w = imlib_image_get_width(); h = imlib_image_get_height(); old_size = w * h * 4; /* get new data, check size of buffer */ new_data = (DATA32*) StringValuePtr(str); /* check size of new buffer */ if (RSTRING(str)->len != old_size) rb_raise(rb_eArgError, "invalid buffer size"); /* copy new data to old address */ if (old_data != new_data) memcpy(old_data, new_data, old_size); /* actual put_back_data() call */ imlib_image_put_back_data(old_data); /* return success */ return Qtrue; } /* * Does this image have transparent or translucent regions? * * Examples: * if image.has_alpha? * puts 'this image has alpha' * end * */ static VALUE image_has_alpha(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); return imlib_image_has_alpha() ? Qtrue : Qfalse; } /* * Set image alpha transparency. * * Examples: * image.set_has_alpha true * image.has_alpha = true * */ static VALUE image_set_has_alpha(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_set_has_alpha(val == Qtrue); return val; } /* * Flag this image as changing on disk * * Examples: * image.changes_on_disk * */ static VALUE image_changes_on_disk(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_set_changes_on_disk(); return Qtrue; } /* * Get the Imlib2::Border of an Imlib2::Image * * Examples: * border = image.get_border * border = image.border * */ static VALUE image_get_border(VALUE self) { ImStruct *im; Imlib_Border *border; VALUE argv[4]; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); border = malloc(sizeof(Imlib_Border)); imlib_image_get_border(border); argv[0] = INT2NUM(border->left); argv[1] = INT2NUM(border->top); argv[2] = INT2NUM(border->right); argv[3] = INT2NUM(border->bottom); free(border); return border_new(4, argv, cBorder); } /* * Set the Imlib2::Border of an Imlib2::Image * * Examples: * image.set_border border * image.border = border * */ static VALUE image_set_border(VALUE self, VALUE border) { ImStruct *im; Imlib_Border *b; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); Data_Get_Struct(border, Imlib_Border, b); imlib_image_set_border(b); return border; } /* * Get the on-disk format of an Imlib2::Image * * Examples: * format = image.get_format * format = image.format * */ static VALUE image_get_format(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); return rb_str_new2(imlib_image_format()); } /* * Set the on-disk format of an Imlib2::Image * * Examples: * image.get_format 'png' * image.format = 'png' * */ static VALUE image_set_format(VALUE self, VALUE format) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_set_format(StringValuePtr(format)); return format; } /* * Set the irrelevant_format flag of an Imlib2::Image * * Examples: * image.set_irrelevant_format true * image.irrelevant_format = true * */ static VALUE image_irrelevant_format(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_set_irrelevant_format(val != Qfalse); return val; } /* * Set the irrelevant_border flag of an Imlib2::Image * * Examples: * image.set_irrelevant_border true * image.irrelevant_border = true * */ static VALUE image_irrelevant_border(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_set_irrelevant_border(val != Qfalse); return val; } /* * Set the irrelevant_alpha flag of an Imlib2::Image * * Examples: * image.set_irrelevant_alpha true * image.irrelevant_alpha = true * */ static VALUE image_irrelevant_alpha(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_set_irrelevant_alpha(val != Qfalse); return val; } /* * Get the Imlib2::Color::RgbaColor value of the pixel at x, y * * Examples: * color = image.query_pixel 320, 240 * color = image.pixel 320, 240 * */ static VALUE image_query_pixel(VALUE self, VALUE x, VALUE y) { ImStruct *im; Imlib_Color color; VALUE argv[4]; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_query_pixel(NUM2INT(x), NUM2INT(y), &color); argv[0] = INT2NUM(color.red); argv[1] = INT2NUM(color.green); argv[2] = INT2NUM(color.blue); argv[3] = INT2NUM(color.alpha); return rgba_color_new(4, argv, cRgbaColor); } /* * Get the Imlib2::Color::HsvaColor value of the pixel at x, y * * Examples: * color = image.query_pixel_hsva 320, 240 * color = image.pixel_hsva 320, 240 * */ static VALUE image_query_pixel_hsva(VALUE self, VALUE x, VALUE y) { ImStruct *im; float hue, saturation, value; int alpha; VALUE argv[4]; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_query_pixel_hsva(NUM2INT(x), NUM2INT(y), &hue, &saturation, &value, &alpha); argv[0] = rb_float_new(hue); argv[1] = rb_float_new(saturation); argv[2] = rb_float_new(value); argv[3] = INT2NUM(alpha); return hsva_color_new(4, argv, cHsvaColor); } /* * Get the Imlib2::Color::HlsaColor value of the pixel at x, y * * Examples: * color = image.query_pixel_hlsa 320, 240 * color = image.pixel_hlsa 320, 240 * */ static VALUE image_query_pixel_hlsa(VALUE self, VALUE x, VALUE y) { ImStruct *im; float hue, lightness, saturation; int alpha; VALUE argv[4]; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_query_pixel_hsva(NUM2INT(x), NUM2INT(y), &hue, &lightness, &saturation, &alpha); argv[0] = rb_float_new(hue); argv[1] = rb_float_new(lightness); argv[2] = rb_float_new(saturation); argv[3] = INT2NUM(alpha); return hlsa_color_new(4, argv, cHlsaColor); } /* * Get the Imlib2::Color::CmyaColor value of the pixel at x, y * * Examples: * color = image.query_pixel_cmya 320, 240 * color = image.pixel_cmya 320, 240 * */ static VALUE image_query_pixel_cmya(VALUE self, VALUE x, VALUE y) { ImStruct *im; CmyaColor color; VALUE argv[4]; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_query_pixel_cmya(NUM2INT(x), NUM2INT(y), &color.cyan, &color.magenta, &color.yellow, &color.alpha); argv[0] = INT2NUM(color.cyan); argv[1] = INT2NUM(color.magenta); argv[2] = INT2NUM(color.yellow); argv[3] = INT2NUM(color.alpha); return cmya_color_new(4, argv, cCmyaColor); } /* * Return a cropped copy of the image * * Examples: * x, y, w, h = 10, 10, old_image.width - 10, old_image.height - 10 * new_image = old_image.crop x, y, w, h * * rect = [10, 10, old_image.width - 10, old_image.height - 10] * new_image = old_image.crop rect * * x, y, w, h = 10, 10, old_image.width - 10, old_image.height - 10 * new_image = old_image.create_cropped x, y, w, h * * rect = [10, 10, old_image.width - 10, old_image.height - 10] * new_image = old_image.create_cropped rect * */ static VALUE image_crop(int argc, VALUE *argv, VALUE self) { ImStruct *old_im, *new_im; VALUE im_o; int x = 0, y = 0, w = 0, h = 0; switch (argc) { case 1: switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 1 or 4)"); } GET_AND_CHECK_IMAGE(self, old_im); imlib_context_set_image(old_im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_create_cropped_image(x, y, w, h); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); return im_o; } /* * Crop an image * * Examples: * x, y, w, h = 10, 10, image.width - 10, image.height - 10 * image.crop! x, y, w, h * * rect = [10, 10, image.width - 10, image.height - 10] * image.crop! rect * * x, y, w, h = 10, 10, image.width - 10, image.height - 10 * image.create_cropped! x, y, w, h * * rect = [10, 10, image.width - 10, image.height - 10] * image.create_cropped! rect * */ static VALUE image_crop_inline(int argc, VALUE *argv, VALUE self) { ImStruct *im; Imlib_Image old_im; int x = 0, y = 0, w = 0, h = 0; switch (argc) { case 1: switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 1 or 4)"); } GET_AND_CHECK_IMAGE(self, im); old_im = im->im; imlib_context_set_image(old_im); im->im = imlib_create_cropped_image(x, y, w, h); imlib_context_set_image(old_im); imlib_free_image(); return self; } /* * Create a cropped and scaled copy of an image * * Examples: * iw, ih = old_image.width, old_image.height * new_w, new_h = iw - 20, ih - 20 * x, y, w, h = 10, 10, iw - 10, ih - 10 * new_image = old_image.crop_scaled x, y, w, h, new_w, new_h * * iw, ih = old_image.width, old_image.height * new_w, new_h = iw - 20, ih - 20 * values = [10, 10, iw - 10, iw - 10, new_w, new_h] * new_image = old_image.crop_scaled values * * iw, ih = old_image.width, old_image.height * new_w, new_h = iw - 20, ih - 20 * x, y, w, h = 10, 10, iw - 10, ih - 10 * new_image = old_image.create_crop_scaled x, y, w, h, new_w, new_h * * iw, ih = old_image.width, old_image.height * new_w, new_h = iw - 20, ih - 20 * values = [10, 10, iw - 10, iw - 10, new_w, new_h] * new_image = old_image.create_crop_scaled values * */ static VALUE image_crop_scaled(int argc, VALUE *argv, VALUE self) { ImStruct *old_im, *new_im; VALUE im_o; int x = 0, y = 0, w = 0, h = 0, dw = 0, dh = 0; switch (argc) { case 1: switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); dw = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dw"))); dh = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dh"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); dw = NUM2INT(rb_ary_entry(argv[0], 4)); dh = NUM2INT(rb_ary_entry(argv[0], 5)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 6: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); dw = NUM2INT(argv[4]); dh = NUM2INT(argv[5]); break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 1 or 6)"); } GET_AND_CHECK_IMAGE(self, old_im); imlib_context_set_image(old_im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_create_cropped_scaled_image(x, y, w, h, dw, dh); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); return im_o; } /* * Crop and scale an image * * Examples: * iw, ih = image.width, image.height * new_w, new_h = iw - 20, ih - 20 * x, y, w, h = 10, 10, iw - 10, ih - 10 * image.crop_scaled! x, y, w, h, new_w, new_h * * iw, ih = image.width, image.height * new_w, new_h = iw - 20, ih - 20 * values = [10, 10, iw - 10, iw - 10, new_w, new_h] * image.crop_scaled! values * * iw, ih = image.width, image.height * new_w, new_h = iw - 20, ih - 20 * x, y, w, h = 10, 10, iw - 10, ih - 10 * image.create_crop_scaled! x, y, w, h, new_w, new_h * * iw, ih = image.width, image.height * new_w, new_h = iw - 20, ih - 20 * values = [10, 10, iw - 10, iw - 10, new_w, new_h] * image.create_crop_scaled! values * */ static VALUE image_crop_scaled_inline(int argc, VALUE *argv, VALUE self) { ImStruct *im; Imlib_Image old_im; int x = 0, y = 0, w = 0, h = 0, dw = 0, dh = 0; switch (argc) { case 1: switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); dw = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dw"))); dh = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dh"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); dw = NUM2INT(rb_ary_entry(argv[0], 4)); dh = NUM2INT(rb_ary_entry(argv[0], 5)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 6: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); dw = NUM2INT(argv[4]); dh = NUM2INT(argv[5]); break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 1 or 6)"); } GET_AND_CHECK_IMAGE(self, im); old_im = im->im; imlib_context_set_image(old_im); im->im = imlib_create_cropped_scaled_image(x, y, w, h, dw, dh); imlib_context_set_image(old_im); imlib_free_image(); return self; } /* * Create a horizontally-flipped copy of an image * * Examples: * backwards_image = old_image.flip_horizontal * */ static VALUE image_flip_horizontal(VALUE self) { ImStruct *im, *new_im; VALUE im_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); imlib_context_set_image(new_im->im); imlib_image_flip_horizontal(); return im_o; } /* * Flip an image horizontally * * Examples: * image.flip_horizontal! * */ static VALUE image_flip_horizontal_inline(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_flip_horizontal(); return self; } /* * Create a vertically-flipped copy of an image * * Examples: * upside_down_image = old_image.flip_vertical * */ static VALUE image_flip_vertical(VALUE self) { ImStruct *im, *new_im; VALUE im_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); imlib_context_set_image(new_im->im); imlib_image_flip_vertical(); return im_o; } /* * Flip an image vertically * * Examples: * image.flip_vertical! * */ static VALUE image_flip_vertical_inline(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_flip_vertical(); return self; } /* * Create a copy of an image flipped along it's diagonal axis * * Examples: * new_image = old_image.flip_diagonal * */ static VALUE image_flip_diagonal(VALUE self) { ImStruct *im, *new_im; VALUE im_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); imlib_context_set_image(new_im->im); imlib_image_flip_diagonal(); return im_o; } /* * Flip an image along it's diagonal axis * * Examples: * image.flip_diagonal! * */ static VALUE image_flip_diagonal_inline(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_flip_diagonal(); return self; } /* * Return a copy of an image rotated in 90 degree increments * * Examples: * increments = 3 # 90 * 3 degrees (eg 270 degrees) * new_image = old_image.orientate increments * */ static VALUE image_orientate(VALUE self, VALUE val) { ImStruct *im, *new_im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); imlib_context_set_image(new_im->im); imlib_image_orientate(NUM2INT(val)); return Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); } /* * Rotate an image in 90 degree increments * * Examples: * increments = 3 # 90 * 3 degrees (eg 270 degrees) * image.orientate! increments * */ static VALUE image_orientate_inline(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_orientate(NUM2INT(val)); return self; } /* * Return a blurred copy of an image * * Examples: * radius = 20 # radius of blur, in pixels * new_image = old_image.blur radius * */ static VALUE image_blur(VALUE self, VALUE val) { ImStruct *im, *new_im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); imlib_context_set_image(new_im->im); imlib_image_blur(NUM2INT(val)); return Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); } /* * Blur an image * * Examples: * radius = 20 # radius of blur, in pixels * image.blur! radius * */ static VALUE image_blur_inline(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_blur(NUM2INT(val)); return self; } /* * Return a sharpened copy of an image * * Examples: * radius = 15 # radius of sharpen, in pixels * new_image = old_image.sharpen radius * */ static VALUE image_sharpen(VALUE self, VALUE val) { ImStruct *im, *new_im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); imlib_context_set_image(new_im->im); imlib_image_sharpen(NUM2INT(val)); return Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); } /* * Sharpened an image * * Examples: * radius = 15 # radius of sharpen, in pixels * image.sharpen! radius * */ static VALUE image_sharpen_inline(VALUE self, VALUE val) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_sharpen(NUM2INT(val)); return self; } /* * Return a copy of an image suitable for seamless horizontal tiling * * Examples: * horiz_tile = old_image.tile_horizontal * */ static VALUE image_tile_horizontal(VALUE self) { ImStruct *im, *new_im; VALUE im_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); imlib_context_set_image(new_im->im); imlib_image_tile_horizontal(); return im_o; } /* * Modify an image so it is suitable for seamless horizontal tiling * * Examples: * image.tile_horizontal! * */ static VALUE image_tile_horizontal_inline(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_tile_horizontal(); return self; } /* * Return a copy of an image suitable for seamless vertical tiling * * Examples: * vert_tile = old_image.tile_vertical * */ static VALUE image_tile_vertical(VALUE self) { ImStruct *im, *new_im; VALUE im_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); imlib_context_set_image(new_im->im); imlib_image_tile_vertical(); return im_o; } /* * Modify an image so it is suitable for seamless vertical tiling * * Examples: * image.tile_vertical! * */ static VALUE image_tile_vertical_inline(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_tile_vertical(); return self; } /* * Return a copy of an image suitable for seamless tiling * * Examples: * horiz_tile = old_image.tile * */ static VALUE image_tile(VALUE self) { ImStruct *im, *new_im; VALUE im_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); im_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); imlib_context_set_image(new_im->im); imlib_image_tile(); return im_o; } /* * Modify an image so it is suitable for seamless tiling * * Examples: * image.tile! * */ static VALUE image_tile_inline(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_tile(); return self; } /* * Clear the contents of an image * * Examples: * image.clear * */ static VALUE image_clear(VALUE self) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_clear(); return self; } /* * I'm honestly not quite sure what this function does, but I wrapped it * anyway. * */ static VALUE image_clear_color(VALUE self, VALUE rgba_color) { ImStruct *im, *new_im; Imlib_Color *color; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); imlib_context_set_image(new_im->im); Data_Get_Struct(rgba_color, Imlib_Color, color); imlib_image_clear_color(color->red, color->blue, color->green, color->alpha); return Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); } /* * I'm honestly not quite sure what this function does, but I wrapped it * anyway. * */ static VALUE image_clear_color_inline(VALUE self, VALUE rgba_color) { ImStruct *im; Imlib_Color *color; GET_AND_CHECK_IMAGE(self, im); Data_Get_Struct(rgba_color, Imlib_Color, color); imlib_context_set_image(im->im); imlib_image_clear_color(color->red, color->blue, color->green, color->alpha); return self; } /* * Draw a pixel at the specified coordinates. * * Note: Versions of Imlib2 up to and including 1.0.5 had a broken * imlib_image_draw_pixel() call. Imlib2-Ruby has a work-around, which * simulates drawing a pixel with a 1x1 rectangle. To disable this * behavior, see the Imlib2::Image::draw_pixel_workaround= method. * * Examples: * im.draw_pixel 10, 10 # draw using context color * im.draw_pixel 10, 10, Imlib2::Color::BLUE # draw blue pixel * im.draw_pixel [10, 10], Imlib2::Color::RED # draw red pixel * */ static VALUE image_draw_pixel(int argc, VALUE *argv, VALUE self) { ImStruct *im; VALUE color = Qnil; int x = 0, y = 0; int blend, aa; switch (argc) { case 1: /* one argument is an array or hash of points, with color * defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is either two fixnum points (with color * defaulting to Qnil), or an array or hash of points and a color * */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); color = argv[1]; break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); color = argv[1]; break; case T_FIXNUM: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is two fixnum points and a color value */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); color = argv[2]; break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 1, 2, or 3)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); if (draw_pixel_workaround) { /* use draw_pixel workaround */ /*********************************************************************/ /* WORKAROUND: workaround for borked Imlib2 imlib_image_draw_pixel() */ /*********************************************************************/ /* save context, then disable blending and aa */ blend = imlib_context_get_blend(); aa = imlib_context_get_anti_alias(); /* draw 1x1 rectangle */ imlib_image_draw_rectangle(x, y, 1, 1); /* restore blend and aa context */ imlib_context_set_blend(blend); imlib_context_set_anti_alias(aa); } else { /* use imlib_image_draw_pixel() (buggy for Imlib2 <= 1.0.5) */ (void) imlib_image_draw_pixel(x, y, 0); } return self; } /* * Draw a line at the specified coordinates. * * Examples: * # draw line from 10, 10 to 20, 20 using context color * im.draw_line 10, 10, 20, 20 * * # draw magenta line from 5, 10 to 15, 20 * im.draw_line 5, 10, 15, 20, Imlib2::Color::MAGENTA * * # draw line from 10, 15 to 20, 25 using context color * im.draw_pixel [10, 15], [20, 25] * * # draw line from 1000, 2000 to 2100, 4200 with funky color * my_color = Imlib2::Color::CmykColor.new 100, 255, 0, 128 * im.draw_line [1000, 2000], [2100, 4200], my_color * */ static VALUE image_draw_line(int argc, VALUE *argv, VALUE self) { ImStruct *im; VALUE color = Qnil; int i = 0, x[2] = {0, 0}, y[2] = {0, 0}; switch (argc) { case 2: /* two arguments is an array or hash of points, with color * defaulting to Qnil (ie, the context color) */ for (i = 0; i < 2; i++) { switch (TYPE(argv[i])) { case T_HASH: x[i] = NUM2INT(rb_hash_aref(argv[i], rb_str_new2("x"))); y[i] = NUM2INT(rb_hash_aref(argv[i], rb_str_new2("y"))); break; case T_ARRAY: x[i] = NUM2INT(rb_ary_entry(argv[i], 0)); y[i] = NUM2INT(rb_ary_entry(argv[i], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } } break; case 3: /* three arguments is two arrays or hashes of points and a color * */ for (i = 0; i < 2; i++) { switch (TYPE(argv[i])) { case T_HASH: x[i] = NUM2INT(rb_hash_aref(argv[i], rb_str_new2("x"))); y[i] = NUM2INT(rb_hash_aref(argv[i], rb_str_new2("y"))); break; case T_ARRAY: x[i] = NUM2INT(rb_ary_entry(argv[i], 0)); y[i] = NUM2INT(rb_ary_entry(argv[i], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } } color = argv[2]; break; case 5: /* 5 arguments is 4 fixnum points and a color value */ color = argv[4]; /* pass-through */ case 4: x[0] = NUM2INT(argv[0]); y[0] = NUM2INT(argv[1]); x[1] = NUM2INT(argv[2]); y[1] = NUM2INT(argv[3]); break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 2, 3, 4, or 5)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); (void) imlib_image_draw_line(x[0], y[0], x[1], y[1], 0); return self; } /* * Draw a rectangle outline at the specified coordinates. * * Examples: * # draw rectangle around edge of image using context color * rect = [1, 1, im.width - 2, im.height - 2] * im.draw_rect rect * * # draw magenta rectangle outline in top-left corner of image * color = Imlib2::Color::MAGENTA * im.draw_rect [0, 0], [im.width / 2, im.height / 2], color * * # draw square from 10, 10 to 30, 30 using context color * im.draw_rect [10, 10, 20, 20] * */ static VALUE image_draw_rect(int argc, VALUE *argv, VALUE self) { ImStruct *im; VALUE color = Qnil; int x, y, w, h; x = y = w = h = 0; switch (argc) { case 1: /* 1 argument is an array or hash of x, y, w, h with color * defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is an array or hash of x, y, w, h with a color, * or an array or hash of x, y, and an array or hash of w, h (with * color defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is an array or hash of x, y and a color */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } color = argv[2]; break; case 4: /* 4 arguments is x, y, w, y (color to Qnil) */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); break; case 5: /* 4 arguments is x, y, w, y, color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); color = argv[4]; break; default: rb_raise(rb_eTypeError,"Invalid argument count (not 1, 2, 3, 4, or 5)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); imlib_image_draw_rectangle(x, y, w, h); return self; } /* * Fill a rectangle at the specified coordinates. * * Examples: * # fill image using context color * rect = [0, 0, im.width, im.height] * im.fill_rect rect * * # fill top-left quarter of image with green * color = Imlib2::Color::GREEN * im.fill_rect [0, 0], [im.width / 2, im.height / 2], color * * # fill square from 10, 10 to 30, 30 using context color * im.fill_rect [10, 10, 20, 20] * */ static VALUE image_fill_rect(int argc, VALUE *argv, VALUE self) { ImStruct *im; VALUE color = Qnil; int x, y, w, h; x = y = w = h = 0; switch (argc) { case 1: /* 1 argument is an array or hash of x, y, w, h with color * defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is an array or hash of x, y, w, h with a color, * or an array or hash of x, y, and an array or hash of w, h (with * color defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is an array or hash of x, y and a color */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } color = argv[2]; break; case 4: /* 4 arguments is x, y, w, y (color to Qnil) */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); break; case 5: /* 4 arguments is x, y, w, y, color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); color = argv[4]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 1, 2, 3, 4, or 5)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); imlib_image_fill_rectangle(x, y, w, h); return self; } /* * Copy the alpha channel from the source image to the specified coordinates * * Examples: * image.copy_alpha source_image, 10, 10 * image.copy_alpha source_image, [10, 10] * */ static VALUE image_copy_alpha(int argc, VALUE *argv, VALUE self) { ImStruct *src_im, *im; VALUE src; int x, y; src = argv[0]; switch (argc) { case 2: switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: x = NUM2INT(argv[1]); y = NUM2INT(argv[2]); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } GET_AND_CHECK_IMAGE(src, src_im); GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_copy_alpha_to_image(src_im->im, x, y); return self; } /* * Copy the alpha channel from a rectangle of the source image to the * specified coordinates * * Examples: * x, y, w, h = 10, 20, 100, 200 * dest_x, dest_y = 5, 10 * image.copy_alpha_rect source_image, x, y, w, h, dest_x, dest_y * * source_rect = [10, 20, 100, 200] * dest_coords = [5, 10] * image.copy_alpha_rect source_image, source_rect, dest_coords * * values = [10, 20, 100, 200, 5, 10] * image.copy_alpha_rect source_image, values * */ static VALUE image_copy_alpha_rect(int argc, VALUE *argv, VALUE self) { ImStruct *src_im, *im; VALUE src; int x, y, w, h, dx, dy; x = y = w = h = dx = dy = 0; src = argv[0]; switch (argc) { case 2: /* 2 arguments is a source image and an array or hash of * x, y, w, h, dx, dy */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); dx = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dy"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); w = NUM2INT(rb_ary_entry(argv[1], 2)); h = NUM2INT(rb_ary_entry(argv[1], 3)); dx = NUM2INT(rb_ary_entry(argv[1], 4)); dy = NUM2INT(rb_ary_entry(argv[1], 5)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is a source image, an array or hash of x,y,w,h, * and an array or hash of dx, dy */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); w = NUM2INT(rb_ary_entry(argv[1], 2)); h = NUM2INT(rb_ary_entry(argv[1], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[1], 0)); dy = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 4: /* four arguments is a source image, an array or hash of [x, y], * an array or hash of [w, h], and an array or hash of [dx, dy], * or a source image, an array or hash of [x, y, w, h], dx, dy */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); switch (TYPE(argv[2])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); switch (TYPE(argv[3])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[3], 0)); dy = NUM2INT(rb_ary_entry(argv[3], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[2], 0)); h = NUM2INT(rb_ary_entry(argv[2], 1)); switch (TYPE(argv[3])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[3], 0)); dy = NUM2INT(rb_ary_entry(argv[3], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); dx = NUM2INT(argv[2]); dy = NUM2INT(argv[3]); } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); switch (TYPE(argv[2])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); switch (TYPE(argv[3])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[3], 0)); dy = NUM2INT(rb_ary_entry(argv[3], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[2], 0)); h = NUM2INT(rb_ary_entry(argv[2], 1)); switch (TYPE(argv[3])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[3], 0)); dy = NUM2INT(rb_ary_entry(argv[3], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); dx = NUM2INT(argv[2]); dy = NUM2INT(argv[3]); } break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 5: /* five arguments is a source image, an array or hash of [x, y], * an array or hash of [w, h], dx, dy */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[2])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[2], 0)); h = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } dx = NUM2INT(argv[3]); dy = NUM2INT(argv[4]); case 6: /* six arguments is a source image, x, y, w, h, and an array or * hash of [dx, dy], or source image, an array or hash of [x, y], * an array or hash of [w, h], dx, dy */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); switch (TYPE(argv[2])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[2], 0)); h = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); switch (TYPE(argv[2])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[2], 0)); h = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: x = NUM2INT(argv[1]); y = NUM2INT(argv[2]); w = NUM2INT(argv[3]); h = NUM2INT(argv[4]); } break; case 7: /* seven arguments is a source image, x, y, w, y, dx, dy */ x = NUM2INT(argv[1]); y = NUM2INT(argv[2]); w = NUM2INT(argv[3]); h = NUM2INT(argv[4]); dx = NUM2INT(argv[5]); dy = NUM2INT(argv[6]); break; default: rb_raise(rb_eTypeError, "Invalid argument count " "(not 2, 3, 4, 5, 6, or 7)"); } GET_AND_CHECK_IMAGE(src, src_im); GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_copy_alpha_rectangle_to_image(src_im->im, x, y, w, h, dx, dy); return self; } /* * Scroll a rectangle to the specified coordinates * * Examples: * x, y, w, h = 10, 20, 100, 200 * dest_x, dest_y = 5, 10 * image.scroll_rect x, y, w, h, dest_x, dest_y * * source_rect = [10, 20, 100, 200] * dest_coords = [5, 10] * image.scroll_rect source_rect, dest_coords * * values = [10, 20, 100, 200, 5, 10] * image.scroll_rect values * */ static VALUE image_scroll_rect(int argc, VALUE *argv, VALUE self) { ImStruct *im; int x, y, w, h, dx, dy; switch (argc) { case 1: /* one argument is an array or hash of [x, y, w, h, dx, dy] */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); dx = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dy"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); dx = NUM2INT(rb_ary_entry(argv[0], 4)); dy = NUM2INT(rb_ary_entry(argv[0], 5)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is an array or hash of [x, y, w, h] and an array * or hash of [dx, dy] */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[1], 0)); dy = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is an array or hash of [x, y], an array or hash * of [w, h] and an array or hash of [dx, dy], or an array or hash * of [x, y, w, h], dx, dy */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); dx = NUM2INT(argv[1]); dy = NUM2INT(argv[2]); } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); dx = NUM2INT(argv[1]); dy = NUM2INT(argv[2]); } break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 4: /* four arguments is an array or hash of [x, y], an array or hash * of [w, h], dx, dy */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } dx = NUM2INT(argv[2]); dy = NUM2INT(argv[3]); break; case 5: /* five arguments is x, y, w, h, and an array or hash of * [dx, dy] */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); switch (TYPE(argv[4])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[4], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[4], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[4], 0)); dy = NUM2INT(rb_ary_entry(argv[4], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 6: /* six arguments is x, y, w, h, dx, dy */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); dx = NUM2INT(argv[4]); dy = NUM2INT(argv[5]); break; default: rb_raise(rb_eTypeError, "Invalid argument count " "(not 2, 3, 4, 5, 6, or 7)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_scroll_rect(x, y, w, h, dx, dy); return self; } /* * Copy a rectangle to the specified coordinates * * Examples: * x, y, w, h = 10, 20, 100, 200 * dest_x, dest_y = 5, 10 * image.copy_rect x, y, w, h, dest_x, dest_y * * source_rect = [10, 20, 100, 200] * dest_coords = [5, 10] * image.copy_rect source_rect, dest_coords * * values = [10, 20, 100, 200, 5, 10] * image.copy_rect values * */ static VALUE image_copy_rect(int argc, VALUE *argv, VALUE self) { ImStruct *im; int x, y, w, h, dx, dy; switch (argc) { case 1: /* one argument is an array or hash of [x, y, w, h, dx, dy] */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); dx = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("dy"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); dx = NUM2INT(rb_ary_entry(argv[0], 4)); dy = NUM2INT(rb_ary_entry(argv[0], 5)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is an array or hash of [x, y, w, h] and an array * or hash of [dx, dy] */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[1], 0)); dy = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is an array or hash of [x, y], an array or hash * of [w, h] and an array or hash of [dx, dy], or an array or hash * of [x, y, w, h], dx, dy */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); dx = NUM2INT(argv[1]); dy = NUM2INT(argv[2]); } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); switch (TYPE(argv[2])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[2], 0)); dy = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not array or hash)"); } break; default: w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); dx = NUM2INT(argv[1]); dy = NUM2INT(argv[2]); } break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 4: /* four arguments is an array or hash of [x, y], an array or hash * of [w, h], dx, dy */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } dx = NUM2INT(argv[2]); dy = NUM2INT(argv[3]); break; case 5: /* five arguments is x, y, w, h, and an array or hash of * [dx, dy] */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); switch (TYPE(argv[4])) { case T_HASH: dx = NUM2INT(rb_hash_aref(argv[4], rb_str_new2("dx"))); dy = NUM2INT(rb_hash_aref(argv[4], rb_str_new2("dy"))); break; case T_ARRAY: dx = NUM2INT(rb_ary_entry(argv[4], 0)); dy = NUM2INT(rb_ary_entry(argv[4], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 6: /* six arguments is x, y, w, h, dx, dy */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); dx = NUM2INT(argv[4]); dy = NUM2INT(argv[5]); break; default: rb_raise(rb_eTypeError, "Invalid argument count " "(not 2, 3, 4, 5, 6, or 7)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_image_copy_rect(x, y, w, h, dx, dy); return self; } /* * Draw an ellipse at the specified coordinates with the given color * * Examples: * # draw an ellipse in the center of the image using the context color * xc, yc, w, h = image.w / 2, image.h / 2, image.w / 2, image.h / 2 * image.draw_oval xc, yc, w, h * * # draw a violet circle in the center of the image * rect = [image.w / 2, image.h / 2, image.w / 2, image.w / 2] * color = Imlib2::Color::VIOLET * image.draw_ellipse rect, color * */ static VALUE image_draw_ellipse(int argc, VALUE *argv, VALUE self) { ImStruct *im; VALUE color = Qnil; int x, y, w, h; x = y = w = h = 0; switch (argc) { case 1: /* 1 argument is an array or hash of x, y, w, h with color * defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is an array or hash of x, y, w, h with a color, * or an array or hash of x, y, and an array or hash of w, h (with * color defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is an array or hash of x, y and a color */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } color = argv[2]; break; case 4: /* 4 arguments is x, y, w, y (color to Qnil) */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); break; case 5: /* 4 arguments is x, y, w, y, color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); color = argv[4]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 1, 2, 3, 4, or 5)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); imlib_image_draw_ellipse(x, y, w, h); return self; } /* * Fill an ellipse at the specified coordinates with the given color * * Examples: * # fill an ellipse in the center of the image using the context color * xc, yc, w, h = image.w / 2, image.h / 2, image.w / 2, image.h / 2 * image.draw_oval xc, yc, w, h * * # fill a violet circle in the center of the image * rect = [image.w / 2, image.h / 2, image.w / 2, image.w / 2] * color = Imlib2::Color::VIOLET * image.draw_ellipse rect, color * */ static VALUE image_fill_ellipse(int argc, VALUE *argv, VALUE self) { ImStruct *im; VALUE color = Qnil; int x, y, w, h; x = y = w = h = 0; switch (argc) { case 1: /* 1 argument is an array or hash of x, y, w, h with color * defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 2: /* two arguments is an array or hash of x, y, w, h with a color, * or an array or hash of x, y, and an array or hash of w, h (with * color defaulting to Qnil (ie, the context color) */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: w = NUM2INT(rb_ary_entry(argv[0], 2)); h = NUM2INT(rb_ary_entry(argv[0], 3)); /* we could do a type check here, but if it's invalid * it'll get caught in the set_context_color() call */ color = argv[1]; } break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 3: /* three arguments is an array or hash of x, y and a color */ switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[1])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[1], 0)); h = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } color = argv[2]; break; case 4: /* 4 arguments is x, y, w, y (color to Qnil) */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); break; case 5: /* 4 arguments is x, y, w, y, color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); w = NUM2INT(argv[2]); h = NUM2INT(argv[3]); color = argv[4]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 1, 2, 3, 4, or 5)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); imlib_image_fill_ellipse(x, y, w, h); return self; } /* * Blend a source image onto the image * * Examples: * src_x, src_y, src_w, src_h = 10, 10, 100, 100 * dst_x, dst_y, dst_w, dst_h = 10, 10, 50, 50 * image.blend! source_image, * src_x, src_y, src_w, src_h, * dst_x, dst_y, dst_w, dst_h * * src_rect = [50, 50, 5, 5] * dst_rect = [0, 0, image.width, image.height] * merge_alpha = false * image.blend! source_image, src_rect, dst_rect, merge_alpha * * src_x, src_y, src_w, src_h = 10, 10, 100, 100 * dst_x, dst_y, dst_w, dst_h = 10, 10, 50, 50 * image.blend_image! source_image, * src_x, src_y, src_w, src_h, * dst_x, dst_y, dst_w, dst_h * * src_rect = [50, 50, 5, 5] * dst_rect = [0, 0, image.width, image.height] * merge_alpha = false * image.blend_image! source_image, src_rect, dst_rect, merge_alpha * */ static VALUE image_blend_image_inline(int argc, VALUE *argv, VALUE self) { ImStruct *im, *src_im; int i, s[4], d[4]; char merge_alpha = 1; switch (argc) { case 4: /* four arguments is source image, an array or hash of * [sx, sy, sw, sh], an array or hash of [sx, sy, sw, sh], and * merge_alpha */ merge_alpha = (argv[3] == Qtrue) ? 1 : 0; case 3: /* three arguments is source image, an array or hash of * [sx, sy, sw, sh], and an array or hash of [sx, sy, sw, sh], * with merge_alpha defaulting to true */ switch (TYPE(argv[1])) { case T_HASH: s[0] = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); s[1] = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); s[2] = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); s[3] = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: for (i = 0; i < 4; i++) s[i] = NUM2INT(rb_ary_entry(argv[1], i)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[2])) { case T_HASH: d[0] = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("x"))); d[1] = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("y"))); d[2] = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); d[3] = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); break; case T_ARRAY: for (i = 0; i < 4; i++) d[i] = NUM2INT(rb_ary_entry(argv[2], i)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 6: /* six arguments is source image, an array or hash of [sx, sy], an * array or hash of [sw, sh], an array or hash of [dx, dy], an * array or hash of [dw, dh], and merge_alpha */ merge_alpha = (argv[5] == Qtrue) ? 1 : 0; case 5: /* five arguments is source image, an array or hash of [sx, sy], an * array or hash of [sw, sh], an array or hash of [dx, dy], and an * array or hash of [dw, dh], with merge_alpha defaulting to true */ switch (TYPE(argv[1])) { case T_HASH: s[0] = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); s[1] = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); break; case T_ARRAY: for (i = 0; i < 2; i++) s[i] = NUM2INT(rb_ary_entry(argv[1], i)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[2])) { case T_HASH: s[2] = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("s"))); s[3] = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); break; case T_ARRAY: for (i = 0; i < 2; i++) s[i + 2] = NUM2INT(rb_ary_entry(argv[2], i)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[3])) { case T_HASH: d[0] = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("x"))); d[1] = NUM2INT(rb_hash_aref(argv[3], rb_str_new2("y"))); break; case T_ARRAY: for (i = 0; i < 2; i++) d[i] = NUM2INT(rb_ary_entry(argv[3], i)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[4])) { case T_HASH: d[2] = NUM2INT(rb_hash_aref(argv[4], rb_str_new2("s"))); d[3] = NUM2INT(rb_hash_aref(argv[4], rb_str_new2("h"))); break; case T_ARRAY: for (i = 0; i < 2; i++) d[i + 2] = NUM2INT(rb_ary_entry(argv[4], i)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 10: /* ten arguments is source image, sx, sy, sw, sh, dx, dy, dw, dh, * and merge_alpha */ merge_alpha = (argv[9] == Qtrue) ? 1 : 0; case 9: /* ten arguments is source image, sx, sy, sw, sh, dx, dy, dw, and * dh, with merge_alpha defaulting to true */ for (i = 0; i < 4; i++) s[i] = NUM2INT(argv[i + 1]); for (i = 0; i < 4; i++) d[i] = NUM2INT(argv[i + 5]); break; default: rb_raise(rb_eTypeError, "Invalid argument count " "(not 3, 4, 5, 6, 9, or 10)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); GET_AND_CHECK_IMAGE(argv[0], src_im); imlib_blend_image_onto_image(src_im->im, merge_alpha, s[0], s[1], s[2], s[3], d[0], d[1], d[2], d[3]); return self; } /* * Return a copy of the image with the a portion of the source image * blended at the specified rectangle. * * Examples: * src_x, src_y, src_w, src_h = 10, 10, 100, 100 * dst_x, dst_y, dst_w, dst_h = 10, 10, 50, 50 * image.blend source_image, * src_x, src_y, src_w, src_h, * dst_x, dst_y, dst_w, dst_h * * src_rect = [50, 50, 5, 5] * dst_rect = [0, 0, image.width, image.height] * merge_alpha = false * image.blend source_image, src_rect, dst_rect, merge_alpha * * src_x, src_y, src_w, src_h = 10, 10, 100, 100 * dst_x, dst_y, dst_w, dst_h = 10, 10, 50, 50 * image.blend_image source_image, * src_x, src_y, src_w, src_h, * dst_x, dst_y, dst_w, dst_h * * src_rect = [50, 50, 5, 5] * dst_rect = [0, 0, image.width, image.height] * merge_alpha = false * image.blend_image source_image, src_rect, dst_rect, merge_alpha * */ static VALUE image_blend_image(int argc, VALUE *argv, VALUE self) { ImStruct *im, *new_im; VALUE i_o; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); new_im = malloc(sizeof(ImStruct)); new_im->im = imlib_clone_image(); i_o = Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); return image_blend_image_inline(argc, argv, i_o); } /* * Return a rotated copy of the image * * Examples: * new_image = old_image.rotate 37.2 * */ static VALUE image_rotate(VALUE self, VALUE angle) { ImStruct *new_im, *im; double a; new_im = malloc(sizeof(ImStruct)); GET_AND_CHECK_IMAGE(self, im); a = rb_float_new(angle); imlib_context_set_image(im->im); new_im->im = imlib_create_rotated_image(a); return Data_Wrap_Struct(cImage, 0, im_struct_free, new_im); } /* * Rotates the image * * Examples: * image.rotate! 37.2 * */ static VALUE image_rotate_inline(VALUE self, VALUE angle) { ImStruct *im; Imlib_Image new_im; double a; GET_AND_CHECK_IMAGE(self, im); a = rb_float_new(angle); imlib_context_set_image(im->im); new_im = imlib_create_rotated_image(a); imlib_context_set_image(im->im); imlib_free_image(); im->im = new_im; return self; } /* * Draw a string with the given Imlib2::Font at the specified coordinates * * Examples: * font = Imlib2::Font.new 'helvetica/12' * string = 'the blue crow flies at midnight' * image.draw_text font, string, 10, 10 * * # draw text in a specified color * font = Imlib2::Font.new 'helvetica/12' * string = 'the blue crow flies at midnight' * color = Imlib2::Color::AQUA * image.draw_text font, string, 10, 10, color * * # draw text in a specified direction * font = Imlib2::Font.new 'verdana/24' * string = 'the blue crow flies at midnight' * color = Imlib2::Color::YELLOW * direction = Imlib2::Direction::DOWN * image.draw_text font, string, 10, 10, color, direction * * # draw text with return metrics * font = Imlib2::Font.new 'arial/36' * string = 'the blue crow flies at midnight' * color = Imlib2::Color::PURPLE * direction = Imlib2::Direction::LEFT * metrics = image.draw_text font, string, 10, 10, color, direction * ['width', 'height', 'horiz_advance', 'vert_advance'].each_index { |i, v| * puts v << ' = ' << metrics[i] * } * */ static VALUE image_draw_text(int argc, VALUE *argv, VALUE self) { ImStruct *im; Imlib_Font *font; VALUE text, ary, color = Qnil, dir = Qnil; int x, y, i, r[] = { 0, 0, 0, 0 }, old_dir = -1; switch (argc) { case 3: /* three arguments is a font, a string, and an array or hash of * x, y, with both color and direction defaulting to Qnil (the * context values) */ switch (TYPE(argv[2])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[2], 0)); y = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } break; case 4: /* four arguments is a font, a string, x, y, with color and * direction defaulting to Qnil, OR a font, a string, an array * or hash of [x, y] and either a color or a direction */ switch (TYPE(argv[2])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("y"))); if (FIXNUM_P(argv[3])) dir = argv[3]; else color = argv[3]; break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[2], 0)); y = NUM2INT(rb_ary_entry(argv[2], 1)); break; if (FIXNUM_P(argv[3])) dir = argv[3]; else color = argv[3]; default: x = NUM2INT(argv[2]); y = NUM2INT(argv[3]); } break; case 5: /* five arguments is a font, a string, x, y, a color, OR a font, a * string, an array or hash of [x, y], a color and a direction */ if (FIXNUM_P(argv[2])) { x = NUM2INT(argv[2]); y = NUM2INT(argv[3]); color = argv[4]; } else { switch (TYPE(argv[2])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[2], 0)); y = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type " "(not Array or Hash)"); } color = argv[3]; dir = argv[4]; } break; case 6: x = NUM2INT(argv[2]); y = NUM2INT(argv[3]); color = argv[4]; dir = argv[5]; default: rb_raise(rb_eTypeError, "Invalid argument count (not 3, 4, or 5)"); } Data_Get_Struct(argv[0], Imlib_Font, font); GET_AND_CHECK_IMAGE(self, im); text = argv[1]; imlib_context_set_font(*font); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); if (dir != Qnil) { old_dir = imlib_context_get_direction(); imlib_context_set_direction(NUM2INT(dir)); } imlib_text_draw_with_return_metrics(x, y, StringValuePtr(text), &r[0], &r[1], &r[2], &r[3]); if (dir != Qnil) imlib_context_set_direction(old_dir); ary = rb_ary_new(); for (i = 0; i < 4; i++) rb_ary_push(ary, INT2FIX(r[i])); return ary; } /* * Fill a rectangle with the given Imlib2::Gradient at a given angle * * Examples: * x, y, w, h = 10, 10, image.width - 20, image.height - 20 * angle = 45.2 * image.fill_gradient gradient, x, y, w, h, angle * * rect = [5, 5, 500, 20] * image.gradient gradient, rect, 36.8 * */ static VALUE image_fill_gradient(int argc, VALUE *argv, VALUE self) { ImStruct *im; Imlib_Color_Range *grad; int x, y, w, h; double angle; switch (argc) { case 3: /* three arguments is a gradient, an array or hash of [x,y,w,h], * and an angle */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); w = NUM2INT(rb_ary_entry(argv[1], 2)); h = NUM2INT(rb_ary_entry(argv[1], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } angle = NUM2DBL(argv[2]); break; case 4: switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } switch (TYPE(argv[2])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[2], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[2], 0)); h = NUM2INT(rb_ary_entry(argv[2], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } angle = NUM2DBL(argv[3]); break; case 6: x = NUM2INT(argv[1]); y = NUM2INT(argv[2]); w = NUM2INT(argv[3]); h = NUM2INT(argv[4]); angle = NUM2DBL(argv[5]); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 3, 4, or 6)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); Data_Get_Struct(argv[0], Imlib_Color_Range, grad); imlib_context_set_color_range(*grad); imlib_image_fill_color_range_rectangle(x, y, w, h, angle); return self; } /* * Draw an Imlib2::Polygon with the specified color * * Examples: * # create a simple blue right triangle * triangle = Imlib2::Polygon.new [10, 10], [20, 20], [10, 20] * image.draw_polygon triangle, Imlib2::Color::BLUE * * # create an open red square polygon * square = Imlib2.Polygon.new [10, 10], [20, 10], [20, 20], [10, 20] * image.draw_poly square, false, Imlib2::Color::RED * */ static VALUE image_draw_poly(int argc, VALUE *argv, VALUE self) { ImStruct *im; ImlibPolygon *poly; VALUE color = Qnil; unsigned char closed = Qtrue; switch (argc) { case 1: /* one argument is poly.. closed is default (Qtrue) */ break; case 2: /* two arguments is poly and closed, or poly and color */ if ((rb_obj_is_kind_of(argv[1], cRgbaColor) == Qtrue) || (rb_obj_is_kind_of(argv[1], cHsvaColor) == Qtrue) || (rb_obj_is_kind_of(argv[1], cHlsaColor) == Qtrue) || (rb_obj_is_kind_of(argv[1], cCmyaColor) == Qtrue)) { color = argv[1]; } else /* FIXME: do type check here */ { closed = (argv[1] == Qtrue) ? 1 : 0; } break; case 3: /* two arguments is poly, closed, and color */ closed = (argv[1] == Qtrue) ? 1 : 0; color = argv[2]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 3, 4, or 6)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); Data_Get_Struct(argv[0], ImlibPolygon, poly); imlib_image_draw_polygon(*poly, closed); return self; } /* * Fill an Imlib2::Polygon with the specified color * * Examples: * # create an filled green diamond polygon * square = Imlib2.Polygon.new [50, 10], [70, 30], [50, 50], [30, 30] * image.fill_poly square, false, Imlib2::Color::GREEN * */ static VALUE image_fill_poly(int argc, VALUE *argv, VALUE self) { ImStruct *im; ImlibPolygon *poly; VALUE color = Qnil; switch (argc) { case 1: /* one argument is poly.. closed is default (Qtrue) */ break; case 2: color = argv[1]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 3, 4, or 6)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); if (color != Qnil) set_context_color(color); Data_Get_Struct(argv[0], ImlibPolygon, poly); imlib_image_fill_polygon(*poly); return self; } /* * Apply an Imlib2::Filter (eg a static filter) * * You should probably using Imlib2::Image#filter() instead, since it is * polymorphic (eg, it can handle both static and scripted filters). * * Example: * filter = Imlib2::Filter.new 20 * filter.set 2, 2, Imlib2::Color::GREEN * image.static_filter filter * */ static VALUE image_static_filter(VALUE self, VALUE filter) { ImStruct *im; Imlib_Filter *f; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); Data_Get_Struct(filter, Imlib_Filter, f); imlib_context_set_filter(*f); imlib_image_filter(); return self; } /***************************/ /* SCRIPT FILTER FUNCTIONS */ /***************************/ /* * Apply a scripted filter * * You should probably using Imlib2::Image#filter() instead, since it is * polymorphic (eg, it can handle both static and scripted filters). * * Example: * x, y = 20, 10 * filter_string = "tint( x=#{x}, y=#{y}, red=255, alpha=55 );" * image.script_filter filter_string * */ static VALUE image_script_filter(VALUE self, VALUE filter) { ImStruct *im; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); imlib_apply_filter(StringValuePtr(filter)); return self; } /********************/ /* FILTER FUNCTIONS */ /********************/ /* * Apply a scripted filter or a static (eg Imlib2::Filter) filter * * Example: * # apply a static filter * filter = Imlib2::Filter.new 20 * filter.set 2, 2, Imlib2::Color::GREEN * image.filter filter * * # apply a scripted filter * x, y = 20, 10 * filter_string = "tint( x=#{x}, y=#{y}, red=255, alpha=55 );" * image.filter filter_string * */ static VALUE image_filter(VALUE self, VALUE filter) { if (rb_obj_is_kind_of(self, rb_cString) == Qtrue) { return image_static_filter(self, filter); } else if (rb_obj_is_kind_of(self, cFilter) == Qtrue) { return image_script_filter(self, filter); } else { rb_raise(rb_eTypeError, "Invalid argument type " "(not String or Imlib2::Filter)"); } return self; } /* * Apply an Imlib2::ColorModifier to the image * * Examples: * # modify the contrast of the entire image * cmod = Imlib2::ColorModifier.new * cmod.contrast = 1.5 * image.apply_cmod color_mod * * # adjust the gamma of the given rect * cmod = Imlib2::ColorModifier.new * cmod.gamma = 0.5 * rect = [10, 10, 20, 40] * image.apply_color_modifier cmod, rect * */ static VALUE image_apply_cmod(int argc, VALUE *argv, VALUE self) { ImStruct *im; Imlib_Color_Modifier *cmod; char whole_image = 0; int x, y, w, h; x = y = w = h = 0; switch (argc) { case 1: whole_image = 1; break; case 2: switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); w = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("h"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); w = NUM2INT(rb_ary_entry(argv[1], 2)); h = NUM2INT(rb_ary_entry(argv[1], 3)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 5: x = NUM2INT(argv[1]); y = NUM2INT(argv[2]); w = NUM2INT(argv[3]); h = NUM2INT(argv[4]); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 1, 2, or 5)"); } GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); Data_Get_Struct(argv[0], Imlib_Color_Modifier, cmod); imlib_context_set_color_modifier(*cmod); if (whole_image) imlib_apply_color_modifier(); else imlib_apply_color_modifier_to_rectangle(x, y, w, h); return self; } #ifndef X_DISPLAY_MISSING /* * Render a pixmap and mask of an image. * * Note: this method returns an array with the pixmap and mask, not just * the pixmap. * * Examples: * pmap, mask = image.render_pixmap * pmap, mask = image.pixmap * * # render a half-size pixmap and mask of the image * pmap, mask = image.render_pixmap image.width / 2, image.height / 2 * * # render a half-size pixmap and mask of the image * pmap, mask = image.pixmap image.width / 2, image.height / 2 * */ static VALUE image_render_pixmap(int argc, VALUE *argv, VALUE self) { ImStruct *im; Imlib_Image old_im; Pixmap *pmap, *mask; VALUE ary; int w, h; char at_size = 0; switch (argc) { case 0: at_size = 0; break; case 1: /* one arg is an array or hash of [w, h] */ at_size = 1; switch (TYPE(argv[0])) { case T_HASH: w = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("w"))); h = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("h"))); break; case T_ARRAY: w = NUM2INT(rb_ary_entry(argv[0], 0)); h = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError,"Invalid argument type (not array or hash)"); } break; case 2: /* two args is w, h */ at_size = 1; w = NUM2INT(argv[0]); h = NUM2INT(argv[1]); break; default: rb_raise(rb_eArgError, "Invalid argument count (not 0, 1, or 2)"); } /* save existing context */ old_im = imlib_context_get_image(); GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); /* if we were passed width and height, then use them */ if (at_size) imlib_render_pixmaps_for_whole_image_at_size(pmap, mask, w, h); else imlib_render_pixmaps_for_whole_image(pmap, mask); /* restore existing context */ imlib_context_set_image(old_im); ary = rb_ary_new(); rb_ary_push(ary, Data_Wrap_Struct(cPixmap, 0, free, pmap)); rb_ary_push(ary, Data_Wrap_Struct(cPixmap, 0, free, mask)); return ary; } #endif /* !X_DISPLAY_MISSING */ /* * Attach an integer value to an Imlib2::Image. * * Examples: * image.attach_value('quality', 90) * image['quality'] = 90 */ static VALUE image_attach_val(VALUE self, VALUE key_o, VALUE val_o) { ImStruct *im; char *key; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); key = StringValuePtr(key_o); /* if (rb_obj_is_kind_of(val_o, rb_cString)) { void *val = (void*) StringValuePtr(val_o); fprintf(stderr, "attaching string\n"); imlib_image_attach_data_value(key, val, 0, NULL); } else */ if (rb_obj_is_kind_of(val_o, rb_cNumeric)) { int val = NUM2INT(val_o); imlib_image_attach_data_value(key, NULL, val, NULL); } else { rb_raise(rb_eTypeError, "Invalid argument (not string or integer)"); } /* return value */ return val_o; } /* * Get an integer value attached to an Imlib2::Image. * * Examples: * qual = image.get_attached_value('quality') * qual = image['quality'] */ static VALUE image_get_attach_val(VALUE self, VALUE key_o) { ImStruct *im; VALUE ret; char *key; /* char *data; */ GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); key = StringValuePtr(key_o); /* if it's got data, retrn that, otherwise return the value */ /* * if ((data = (char*) imlib_image_get_attached_value(key)) != NULL) { * fprintf(stderr, "it's a string \"%s\": %x\n", key, data); * ret = rb_str_new2(data); * } else { * fprintf(stderr, "it's an integer \"%s\"\n", key); */ ret = INT2FIX(imlib_image_get_attached_value(key)); /* * } */ /* return result */ return ret; } /* * Remove an integer value attached to an Imlib2::Image. * * Examples: * image.remove_attached_value('quality') */ static VALUE image_rm_attach_val(VALUE self, VALUE key_o) { ImStruct *im; char *key; GET_AND_CHECK_IMAGE(self, im); imlib_context_set_image(im->im); key = StringValuePtr(key_o); imlib_image_remove_attached_data_value(key); return Qnil; } /******************/ /* CMOD FUNCTIONS */ /******************/ static void cmod_free(void *val) { Imlib_Color_Modifier *cmod = (Imlib_Color_Modifier*) val; imlib_context_set_color_modifier(*cmod); imlib_free_color_modifier(); free(cmod); } /* * Returns a new Imlib2::ColorModifier * * Example: * cmod = Imlib2::ColorModifier.new * */ VALUE cmod_new(VALUE klass) { Imlib_Color_Modifier *cmod; VALUE self; cmod = malloc(sizeof(Imlib_Color_Modifier)); self = Data_Wrap_Struct(klass, 0, cmod_free, cmod); rb_obj_call_init(self, 0, NULL); return self; } /* * Imlib2::ColorModifier constructor * * This method takes no arguments. * */ static VALUE cmod_init(VALUE self) { return self; } /* * Set the gamma value. * * Example: * cmod.gamma = 0.5 * */ static VALUE cmod_gamma(VALUE self, VALUE gamma) { Imlib_Color_Modifier *cmod; Data_Get_Struct(self, Imlib_Color_Modifier, cmod); imlib_context_set_color_modifier(*cmod); imlib_modify_color_modifier_gamma(NUM2DBL(gamma)); return self; } /* * Set the brightness value. * * Example: * cmod.brightness = 2.0 * */ static VALUE cmod_brightness(VALUE self, VALUE brightness) { Imlib_Color_Modifier *cmod; Data_Get_Struct(self, Imlib_Color_Modifier, cmod); imlib_context_set_color_modifier(*cmod); imlib_modify_color_modifier_brightness(NUM2DBL(brightness)); return self; } /* * Set the contrast value. * * Example: * cmod.contrast = 0.8 * */ static VALUE cmod_contrast(VALUE self, VALUE contrast) { Imlib_Color_Modifier *cmod; Data_Get_Struct(self, Imlib_Color_Modifier, cmod); imlib_context_set_color_modifier(*cmod); imlib_modify_color_modifier_contrast(NUM2DBL(contrast)); return self; } /* * Reset the Imlib2::ColorModifier * * Example: * cmod.reset * */ static VALUE cmod_reset(VALUE self) { Imlib_Color_Modifier *cmod; Data_Get_Struct(self, Imlib_Color_Modifier, cmod); imlib_context_set_color_modifier(*cmod); imlib_reset_color_modifier(); return self; } /******************/ /* FONT FUNCTIONS */ /******************/ static void font_free(void *val) { Imlib_Font *font = (Imlib_Font*) val; imlib_context_set_font(*font); imlib_free_font(); free(font); } /* * Returns a new Imlib2::Font * * Note: the specified font must be in the font path. See * Imlib2::Font::list_paths() for a list of font paths, and * Imlib2::Font::list_fonts() for a list of fonts. * * Examples: * font = Imlib2::Font.new 'helvetica/24' * font = Imlib2::Font.load 'helvetica/24' * */ VALUE font_new(VALUE klass, VALUE font_name) { Imlib_Font *font; VALUE f_o; font = malloc(sizeof(Imlib_Font*)); *font = imlib_load_font(StringValuePtr(font_name)); f_o = Data_Wrap_Struct(klass, 0, font_free, font); rb_obj_call_init(f_o, 0, NULL); return f_o; } /* * Constructor for Imlib2::Font * * Currently just a placeholder. * */ static VALUE font_init(VALUE self) { return self; } /* * Get the width and height of the given string using this font. * * Example: * font = Imlib2::Font.new 'helvetica/12' * size = font.size 'how big am i?' * ['width', 'height'].each_index { |i, v| * puts 'text ' << v << ' = ' << size[i] * } * */ static VALUE font_text_size(VALUE self, VALUE text) { Imlib_Font *font; int sw = 0, sh = 0; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); imlib_get_text_size(StringValuePtr(text), &sw, &sh); return rb_ary_new3 (2, INT2FIX(sw), INT2FIX(sh)); } /* * Get the horizontal and vertical advance of the given string using * this font. * * Example: * font = Imlib2::Font.new 'verdana/36' * advances = font.advance "what's my advance?" * ['horizontal', 'vertical'].each_index { |i, v| * puts 'text ' << v << ' advance = ' << advances[i] * } * */ static VALUE font_text_advance(VALUE self, VALUE text) { Imlib_Font *font; int sw = 0, sh = 0; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); imlib_get_text_advance(StringValuePtr(text), &sw, &sh); return rb_ary_new3 (2, INT2FIX(sw), INT2FIX (sh)); } /* * Get the inset of the given string using this font * * Example: * font = Imlib2::Font.new 'palatino/9' * inset = font.inset 'wonder what the inset for this string is...' * */ static VALUE font_text_inset(VALUE self, VALUE text) { Imlib_Font *font; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); return INT2FIX(imlib_get_text_inset(StringValuePtr(text))); } /* * Get the character index of the pixel at the given coordinates using * this font. * * Example: * x, y, char_w, char_h = font.index "index\nstring\n", 5, 5 * */ static VALUE font_text_index(int argc, VALUE *argv, VALUE self) { Imlib_Font *font; VALUE text, ary; int x, y, i, r[] = { 0, 0, 0, 0 }; text = argv[0]; switch (argc) { case 2: /* two arguments is a string, and an array or hash of x, y */ switch (TYPE(argv[1])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[1], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[1], 0)); y = NUM2INT(rb_ary_entry(argv[1], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } break; case 3: /* three arguments is a string, x, y */ x = NUM2INT(argv[1]); y = NUM2INT(argv[2]); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); imlib_text_get_index_and_location(StringValuePtr(text), x, y, &r[0], &r[1], &r[2], &r[3]); ary = rb_ary_new(); for (i = 0; i < 4; i++) rb_ary_push(ary, INT2FIX(r[i])); return ary; } /* * Get the character coordinates of the at the given index using this font. * * Example: * x, y, char_w, char_h = font.index "index\nstring\n", 8 * */ static VALUE font_text_location(VALUE self, VALUE text, VALUE index) { Imlib_Font *font; VALUE ary; int i, r[] = { 0, 0, 0, 0 }; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); imlib_text_get_location_at_index(StringValuePtr(text), NUM2INT(index), &r[0], &r[1], &r[2], &r[3]); ary = rb_ary_new(); for (i = 0; i < 4; i++) rb_ary_push(ary, INT2FIX(r[i])); return ary; } /* * Get font ascent. * * Example: * a = font.ascent * */ static VALUE font_ascent(VALUE self) { Imlib_Font *font; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); return INT2FIX(imlib_get_font_ascent()); } /* * Get font descent. * * Example: * a = font.descent * */ static VALUE font_descent(VALUE self) { Imlib_Font *font; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); return INT2FIX(imlib_get_font_descent()); } /* * Get font maximum ascent. * * Example: * a = font.maximum_ascent * */ static VALUE font_maximum_ascent(VALUE self) { Imlib_Font *font; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); return INT2FIX(imlib_get_maximum_font_ascent()); } /* * Get font maximum descent. * * Example: * a = font.maximum_descent * */ static VALUE font_maximum_descent(VALUE self) { Imlib_Font *font; Data_Get_Struct(self, Imlib_Font, font); imlib_context_set_font(*font); return INT2FIX(imlib_get_maximum_font_descent()); } /* * Return an array of all known fonts * * Example: * font_list = Imlib2::Font.list_fonts * */ static VALUE font_list_fonts(VALUE klass) { VALUE ary; char **list; int i, len; UNUSED(klass); list = imlib_list_fonts(&len); ary = rb_ary_new(); for (i = 0; i < len; i++) rb_ary_push(ary, rb_str_new2(list[i])); /* FIXME: there has got to be a better way to do this: */ imlib_free_font_list(list, len); return ary; } /* * Add a path to the list of font paths. * * Example: * Imlib2::Font.add_path '/usr/lib/X11/fonts/Truetype' * */ static VALUE font_add_path(VALUE klass, VALUE path) { UNUSED(klass); imlib_add_path_to_font_path(StringValuePtr(path)); return Qtrue; } /* * Remove a path from the list of font paths. * * Example: * Imlib2::Font.remove_path '/usr/lib/X11/fonts/Truetype' * */ static VALUE font_remove_path(VALUE klass, VALUE path) { UNUSED(klass); imlib_remove_path_from_font_path(StringValuePtr(path)); return Qtrue; } /* * Return an array of font paths. * * Example: * path_list = Imlib2::Font.list_paths * */ static VALUE font_list_paths(VALUE klass) { VALUE ary; char **list; int i, len; UNUSED(klass); list = imlib_list_font_path(&len); ary = rb_ary_new(); for (i = 0; i < len; i++) rb_ary_push(ary, rb_str_new2(list[i])); /* FIXME: there has got to be a better way to do this: */ imlib_free_font_list(list, len); return ary; } /**********************/ /* GRADIENT FUNCTIONS */ /**********************/ static void gradient_free(void *val) { Imlib_Color_Range *range = (Imlib_Color_Range*) val; imlib_context_set_color_range(*range); imlib_free_color_range(); free(range); } /* * Return a new Imlib2::Gradient. * * Examples: * # create a blue to green gradient * grad = Imlib2::Gradient.new * grad.add_color 0, Imlib2::Color::BLUE * grad.add_color 100, Imlib2::Color::GREEN * * # create a red to yellow to black gradient * colors = [ [0, Imlib2::Color::RED ], * [100, Imlib2::Color::YELLOW ], * [200, Imlib2::Color::BLACK ] ] * grad = Imlib2::Gradient.new *colors * */ VALUE gradient_new(int argc, VALUE *argv, VALUE klass) { Imlib_Color_Range *range; VALUE g_o; range = malloc(sizeof(Imlib_Color_Range*)); *range = imlib_create_color_range(); g_o = Data_Wrap_Struct(klass, 0, gradient_free, range); rb_obj_call_init(g_o, argc, argv); return g_o; } /* * Add a color at the given distance * * Examples: * # add the context color with a 100 pixel offset * grad.add_color 100 * * # add white at a 100 pixel offset * grad.add_color 100, Imlib2::Color::WHITE * */ static VALUE gradient_add_color(int argc, VALUE *argv, VALUE self) { Imlib_Color_Range *grad; VALUE color = Qnil; int distance; switch (argc) { case 1: distance = NUM2INT(argv[0]); break; case 2: distance = NUM2INT(argv[0]); color = argv[1]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 1 or 2)"); } Data_Get_Struct(self, Imlib_Color_Range, grad); imlib_context_set_color_range(*grad); if (color != Qnil) set_context_color(color); imlib_add_color_to_color_range(distance); return self; } /* * Imlib2::Gradient constructor. * * Accepts an arbitrary number of arrays of offset, and color values * (the same as Imlib2::Gradient.new). * */ static VALUE gradient_init(int argc, VALUE *argv, VALUE self) { int i; for (i = 0; i < argc; i++) { VALUE args[2]; args[0]= rb_ary_entry(argv[i], 0); args[1] = rb_ary_entry(argv[i], 1); gradient_add_color(2, args, self); } return self; } /*********************/ /* POLYGON FUNCTIONS */ /*********************/ static void poly_free(void *val) { ImlibPolygon *poly = (ImlibPolygon*) val; imlib_polygon_free(*poly); free(poly); } /* * Return a new Imlib2::Polygon * * Examples: * poly = Imlib2::Polygon.new * * points = [[10, 10], [20, 30], [15, 8], [6, 3], [12, 2]] * poly = Imlib2::Polygon.new *points * */ VALUE poly_new(int argc, VALUE *argv, VALUE klass) { ImlibPolygon *poly; VALUE p_o; poly = malloc(sizeof(ImlibPolygon*)); *poly = imlib_polygon_new(); p_o = Data_Wrap_Struct(klass, 0, poly_free, poly); rb_obj_call_init(p_o, argc, argv); return p_o; } /* * Add a point to the polygon * * Example: * poly.add_point 123, 456 * */ static VALUE poly_add_point(int argc, VALUE *argv, VALUE self) { ImlibPolygon *poly; int x, y; switch (argc) { case 1: switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } break; case 2: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, ImlibPolygon, poly); imlib_polygon_add_point(*poly, x, y); return self; } /* * Constructor for Imlib2::Polygon * * Accepts the same arguments as Imlib2::Polygon.new. * */ static VALUE poly_init(int argc, VALUE *argv, VALUE self) { VALUE args[1]; int i; for (i = 0; i < argc; i++) { args[0] = argv[i]; poly_add_point(1, args, self); } return self; } /* * Return the bounding rectangle of the given polygon. * * Example: * bounds = poly.bounds * %q(x y w h).each_index { |i, v| puts v << ' = ' << bounds[i] } * */ static VALUE poly_bounds(VALUE self) { ImlibPolygon *poly; VALUE ary; int i, r[4] = { 0, 0, 0, 0 }; Data_Get_Struct(self, ImlibPolygon, poly); imlib_polygon_get_bounds(*poly, &r[0], &r[1], &r[2], &r[3]); ary = rb_ary_new(); for (i = 0; i < 4; i++) rb_ary_push(ary, INT2FIX(r[i])); return ary; } /* * Does the given point lie within the polygon? * * Example: * if poly.contains? 12, 5 * puts 'yes' * else * puts 'no' * end * */ static VALUE poly_contains(int argc, char *argv, VALUE self) { ImlibPolygon *poly; int x, y; switch (argc) { case 1: switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 2: x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, ImlibPolygon, poly); return imlib_polygon_contains_point(*poly, x, y) ? Qtrue : Qfalse; } /***************************/ /* STATIC FILTER FUNCTIONS */ /***************************/ static void filter_free(void *filter) { Imlib_Filter *f = (Imlib_Filter*) filter; imlib_context_set_filter(*f); imlib_free_filter(); free(f); } /* * Return a new Imlib2::Filter * * Example: * filter = Imlib2::Filter.new * */ VALUE filter_new(VALUE initsize, VALUE klass) { Imlib_Filter *f = malloc(sizeof(Imlib_Filter)); VALUE f_o, vals[1]; *f = imlib_create_filter(NUM2INT(initsize)); f_o = Data_Wrap_Struct(klass, 0, filter_free, f); vals[0] = initsize; rb_obj_call_init(f_o, 1, vals); return f_o; } /* * Constructor for Imlib2::Filter * * Currently just a placeholder. * */ VALUE filter_init(VALUE self, VALUE initsize) { UNUSED(initsize); /* don't do anythign here for now */ return self; } /* * Set the filter color value and x, y * * Example: * filter.set x, y, Imlib2::Color::RED * */ VALUE filter_set(int argc, VALUE *argv, VALUE self) { Imlib_Filter *f; Imlib_Color *c; int x, y; VALUE color; switch (argc) { case 2: /* 2 args is an array or hash of x, y, and an RGBAColor */ color = argv[1]; switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three args is x, y, and color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); color = argv[2]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_set(x, y, c->alpha, c->red, c->green, c->blue); return self; } VALUE filter_set_red(int argc, VALUE *argv, VALUE self) { Imlib_Filter *f; Imlib_Color *c; int x, y; VALUE color; switch (argc) { case 2: /* 2 args is an array or hash of x, y, and an RGBAColor */ color = argv[1]; switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three args is x, y, and color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); color = argv[2]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_set_red(x, y, c->alpha, c->red, c->green, c->blue); return self; } /* * Set the green filter color value and x, y * * Example: * filter.set_green x, y, Imlib2::Color::RgbaColor.new 0, 128, 0, 128 * */ VALUE filter_set_green(int argc, VALUE *argv, VALUE self) { Imlib_Filter *f; Imlib_Color *c; int x, y; VALUE color; switch (argc) { case 2: /* 2 args is an array or hash of x, y, and an RGBAColor */ color = argv[1]; switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three args is x, y, and color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); color = argv[2]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_set_green(x, y, c->alpha, c->red, c->green, c->blue); return self; } /* * Set the blue filter color value and x, y * * Example: * filter.set_blue x, y, Imlib2::Color::RgbaColor.new 0, 0, 64, 128 * */ VALUE filter_set_blue(int argc, VALUE *argv, VALUE self) { Imlib_Filter *f; Imlib_Color *c; int x, y; VALUE color; switch (argc) { case 2: /* 2 args is an array or hash of x, y, and an RGBAColor */ color = argv[1]; switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three args is x, y, and color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); color = argv[2]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_set_blue(x, y, c->alpha, c->red, c->green, c->blue); return self; } /* * Set the alpha filter color value and x, y * * Example: * filter.set_alpha x, y, Imlib2::Color::RgbaColor.new 0, 0, 0, 128 * */ VALUE filter_set_alpha(int argc, VALUE *argv, VALUE self) { Imlib_Filter *f; Imlib_Color *c; int x, y; VALUE color; switch (argc) { case 2: /* 2 args is an array or hash of x, y, and an RGBAColor */ color = argv[1]; switch (TYPE(argv[0])) { case T_HASH: x = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("x"))); y = NUM2INT(rb_hash_aref(argv[0], rb_str_new2("y"))); break; case T_ARRAY: x = NUM2INT(rb_ary_entry(argv[0], 0)); y = NUM2INT(rb_ary_entry(argv[0], 1)); break; default: rb_raise(rb_eTypeError, "Invalid argument type (not array or hash)"); } break; case 3: /* three args is x, y, and color */ x = NUM2INT(argv[0]); y = NUM2INT(argv[1]); color = argv[2]; break; default: rb_raise(rb_eTypeError, "Invalid argument count (not 2 or 3)"); } Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_set_alpha(x, y, c->alpha, c->red, c->green, c->blue); return self; } /* * Set filter constants. * * Example: * filter.set_constants RgbaColor.new 32, 32, 32, 32 * */ VALUE filter_constants(VALUE self, VALUE color) { Imlib_Filter *f; Imlib_Color *c; Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_constants(c->alpha, c->red, c->green, c->blue); return self; } /* * Set filter divisors. * * Example: * filter.set_divisors RgbaColor.new 0, 32, 0, 32 * */ VALUE filter_divisors(VALUE self, VALUE color) { Imlib_Filter *f; Imlib_Color *c; Data_Get_Struct(self, Imlib_Filter, f); Data_Get_Struct(color, Imlib_Color, c); imlib_context_set_filter(*f); imlib_filter_divisors(c->alpha, c->red, c->green, c->blue); return self; } /*********************/ /* CONTEXT FUNCTIONS */ /*********************/ static void ctx_free(void *val) { Imlib_Context *ctx = (Imlib_Context *) val; imlib_context_free(*ctx); free(ctx); } /* * Return a new Imlib2::Context. * * Example: * ctx = Imlib2::Context.new * */ VALUE ctx_new(VALUE klass) { VALUE self; Imlib_Context *ctx; ctx = malloc(sizeof(Imlib_Context)); *ctx = imlib_context_new(); self = Data_Wrap_Struct(klass, 0, ctx_free, ctx); rb_obj_call_init(self, 0, NULL); return self; } /* * Imlib2::Context constructor. * * Currently just a placeholder * */ static VALUE ctx_init(VALUE self) { return self; } /* * Pop the top context off the context stack. * * Example: * ctx = Imlib2::Context.pop * */ VALUE ctx_pop(VALUE klass) { Imlib_Context *ctx; ctx = (Imlib_Context *) malloc(sizeof(Imlib_Context)); imlib_context_pop(); *ctx = imlib_context_get(); return Data_Wrap_Struct(klass, 0, ctx_free, ctx); } /* * Return the current context. * * Example: * ctx = Imlib2::Context.get * */ VALUE ctx_get(VALUE klass) { Imlib_Context *ctx; ctx = (Imlib_Context *) malloc(sizeof(Imlib_Context)); *ctx = imlib_context_get(); return Data_Wrap_Struct(klass, 0, ctx_free, ctx); } /* * Push this context onto the context stack. * * Example: * ctx.push * */ static VALUE ctx_push(VALUE self) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); return self; } /* * Set the dither_mask flag. * * Example: * ctx.dither_mask = true * */ static VALUE ctx_set_dither_mask(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_dither_mask(val != Qnil && val != Qfalse); imlib_context_pop(); return self; } /* * Get the dither_mask flag. * * Example: * if ctx.dither_mask == true * puts 'dither_mask enabled' * end * */ static VALUE ctx_dither_mask(VALUE self) { Imlib_Context *ctx; VALUE r = Qfalse; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = imlib_context_get_dither_mask() ? Qtrue : Qfalse; imlib_context_pop(); return r; } /* * Set the anti_alias flag. * * Example: * ctx.anti_alias = true * */ static VALUE ctx_set_aa(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_anti_alias(val != Qnil && val != Qfalse); imlib_context_pop(); return self; } /* * Get the anti_alias flag. * * Example: * if ctx.anti_alias == true * puts 'anti_alias enabled.' * end * */ static VALUE ctx_aa(VALUE self) { Imlib_Context *ctx; VALUE r = Qfalse; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = imlib_context_get_anti_alias() ? Qtrue : Qfalse; imlib_context_pop(); return r; } /* * Set the dither flag. * * Example: * ctx.dither = true * */ static VALUE ctx_set_dither(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_dither(val != Qnil && val != Qfalse); imlib_context_pop(); return self; } /* * Get the dither flag. * * Example: * if ctx.dither * puts 'dither enabled.' * end * */ static VALUE ctx_dither(VALUE self) { Imlib_Context *ctx; VALUE r = Qfalse; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = imlib_context_get_dither() ? Qtrue : Qfalse; imlib_context_pop(); return r; } /* * Set the blend flag. * * Example: * ctx.blend = true * */ static VALUE ctx_set_blend(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_blend(val != Qnil && val != Qfalse); imlib_context_pop(); return self; } /* * Get the blend flag. * * Example: * if ctx.blend * puts 'blend enabled.' * end * */ static VALUE ctx_blend(VALUE self) { Imlib_Context *ctx; VALUE r = Qfalse; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = imlib_context_get_blend() ? Qtrue : Qfalse; imlib_context_pop(); return r; } /* * Set the current color modifier (Imlib2::ColorModifier). * * Example: * ctx.cmod = cmod * */ static VALUE ctx_set_cmod(VALUE self, VALUE val) { Imlib_Context *ctx; Imlib_Color_Modifier *cmod; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); Data_Get_Struct(val, Imlib_Color_Modifier, cmod); imlib_context_set_color_modifier(*cmod); imlib_context_pop(); return self; } /* * Get the current color modifier (Imlib2::ColorModifier). * * Example: * cmod = ctx.cmod * */ static VALUE ctx_cmod(VALUE self) { Imlib_Context *ctx; Imlib_Color_Modifier *cmod; cmod = malloc(sizeof(Imlib_Color_Modifier)); Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); *cmod = imlib_context_get_color_modifier(); imlib_context_pop(); return Data_Wrap_Struct(cColorMod, 0, cmod_free, cmod); } /* * Set the current operation (Imlib2::Op or Imlib2::Operation). * * Example: * ctx.operation = Imlib2::Op::COPY * */ static VALUE ctx_set_op(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_operation(NUM2INT(val)); imlib_context_pop(); return self; } /* * Get the current operation (Imlib2::Op or Imlib2::Operation). * * Example: * if ctx.op == Imlib2::Op::COPY * puts 'copy operation' * end * */ static VALUE ctx_op(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = INT2FIX(imlib_context_get_operation()); imlib_context_pop(); return r; } /* * Set the current font (Imlib2::Font). * * Example: * ctx.font = Imlib2::Font.new 'helvetica/12' * */ static VALUE ctx_set_font(VALUE self, VALUE val) { Imlib_Context *ctx; Imlib_Font *font; font = malloc(sizeof(Imlib_Font)); Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); Data_Get_Struct(val, Imlib_Font, font); imlib_context_set_font(*font); imlib_context_pop(); return self; } /* * Get the current font (Imlib2::Font). * * Example: * font = ctx.font * */ static VALUE ctx_font(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = Data_Wrap_Struct(cFont, 0, font_free, imlib_context_get_font()); imlib_context_pop(); return r; } /* * Set the current font direction (Imlib2::Dir or Imlib2::Direction). * * Example: * ctx.direction = Imlib2::Direction::LEFT * */ static VALUE ctx_set_dir(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_direction(NUM2INT(val)); imlib_context_pop(); return self; } /* * Get the current font direction (Imlib2::Dir or Imlib2::Direction). * * Example: * if ctx.direction != Imlib2::Direction::RIGHT * puts 'drawing funny text' * end * */ static VALUE ctx_dir(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = INT2FIX(imlib_context_get_direction()); imlib_context_pop(); return r; } /* * Set the text drawing angle. * * Example: * ctx.angle = 76.8 * */ static VALUE ctx_set_angle(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_angle(NUM2DBL(val)); imlib_context_pop(); return self; } /* * Get the text drawing angle. * * Example: * if ctx.dir == Imlib2::Direction::ANGLE * puts 'the current font angle is ' << ctx.angle * end * */ static VALUE ctx_angle(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = rb_float_new(imlib_context_get_angle()); imlib_context_pop(); return r; } /* * Set the current color (Imlib2::Color). * * Example: * ctx.color = Imlib2::Color::LIGHTGRAY * */ static VALUE ctx_set_color(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); set_context_color(val); imlib_context_pop(); return self; } /* * Get the current color (Imlib2::Color::RgbaColor). * * Example: * color = ctx.color * */ static VALUE ctx_color(VALUE self) { Imlib_Context *ctx; VALUE argv[4]; int i, r[4]; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_get_color(&(r[0]), &(r[1]), &(r[2]), &(r[3])); imlib_context_pop(); for (i = 0; i < 4; i++) argv[i] = INT2NUM(r[i]); return rgba_color_new(4, argv, cRgbaColor); } /* * Set the current gradient (Imlib2::Gradient). * * Example: * ctx.gradient = grad * */ static VALUE ctx_set_gradient(VALUE self, VALUE val) { Imlib_Context *ctx; Imlib_Color_Range *gradient; gradient = malloc(sizeof(Imlib_Color_Range)); Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); Data_Get_Struct(val, Imlib_Color_Range, gradient); imlib_context_set_color_range(*gradient); imlib_context_pop(); return self; } /* * Get the current gradient (Imlib2::Gradient). * * Example: * grad = ctx.gradient * */ static VALUE ctx_gradient(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = Data_Wrap_Struct(cGradient, 0, gradient_free, imlib_context_get_color_range()); imlib_context_pop(); return r; } /* * Set the progress callback granularity. * * This function is not useful at the moment since you cannot specify * progress callbacks from within ruby (this is a TODO item). * * Example: * ctx.progress_granularity = 10 * */ static VALUE ctx_set_progress_granularity(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_progress_granularity(NUM2INT(val)); imlib_context_pop(); return self; } /* * Get the progress callback granularity. * * This function is not useful at the moment since you cannot specify * progress callbacks from within Ruby (this is a TODO item). * * Example: * granularity = ctx.progress_granularity * */ static VALUE ctx_progress_granularity(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = INT2FIX(imlib_context_get_progress_granularity()); imlib_context_pop(); return r; } /* * Set the current image (Imlib2::Image). * * Note that this function is not useful at the moment since all image * instance methods blindly blow away the image and color context. So * you cannot safely mix image context and image instance methods. * * Example: * ctx.image = image * */ static VALUE ctx_set_image(VALUE self, VALUE val) { Imlib_Context *ctx; ImStruct *im; im = malloc(sizeof(ImStruct)); Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); GET_AND_CHECK_IMAGE(val, im); imlib_context_set_image(im->im); imlib_context_pop(); return self; } /* * Get the current image (Imlib2::Image). * * Note that this function is not useful at the moment since all image * instance methods blindly blow away the image and color context. So * you cannot safely mix image context and image instance methods. * * Example: * im = ctx.image * */ static VALUE ctx_image(VALUE self) { Imlib_Context *ctx; ImStruct *im; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); im = malloc(sizeof(ImStruct)); im->im = imlib_context_get_image(); r = Data_Wrap_Struct(cImage, 0, im_struct_free, im); imlib_context_pop(); return r; } /* * Set the cliprect. * * Example: * ctx.cliprect = [10, 10, 100, 100] * */ static VALUE ctx_set_cliprect(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_cliprect( NUM2INT(rb_ary_entry(val, 0)), NUM2INT(rb_ary_entry(val, 1)), NUM2INT(rb_ary_entry(val, 2)), NUM2INT(rb_ary_entry(val, 3)) ); imlib_context_pop(); return self; } /* * Get the cliprect. * * Example: * x, y, w, h = ctx.cliprect * */ static VALUE ctx_cliprect(VALUE self) { Imlib_Context *ctx; int i, r[4]; VALUE ary; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_get_cliprect(&(r[0]), &(r[1]), &(r[2]), &(r[3])); imlib_context_pop(); ary = rb_ary_new(); for (i = 0; i < 4; i++); rb_ary_push(ary, NUM2INT(r[i])); return ary; } /* * Set the current TrueType Font Encoding. * * Example: * ctx.encoding = Imlib2::Encoding::ISO_8859_5 * */ static VALUE ctx_set_encoding(VALUE self, VALUE val) { Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); imlib_context_set_TTF_encoding(NUM2INT(val)); imlib_context_pop(); return self; } /* * Get the current TrueType Font Encoding. * * Example: * if ctx.encoding == Imlib2::Encoding::ISO_8859_1 * puts 'using ISO-8859-1 encoding' * end * */ static VALUE ctx_encoding(VALUE self) { Imlib_Context *ctx; VALUE r = Qnil; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); r = INT2FIX(imlib_context_get_TTF_encoding()); imlib_context_pop(); return r; } #ifndef X_DISPLAY_MISSING /*************************/ /* CONTEXT X11 FUNCTIONS */ /*************************/ /* * Set the current X11 Display. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * context.set_display display * context.display = display * */ static VALUE ctx_set_display(VALUE self, VALUE display) { Display *disp; Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); Data_Get_Struct(display, Display, disp); imlib_context_push(*ctx); imlib_context_set_display(disp); imlib_context_pop(); return display; } /* * Get the current X11 Display. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * display = context.get_display * display = context.display * */ static VALUE ctx_display(VALUE self) { Imlib_Context *ctx; VALUE disp; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); disp = Data_Wrap_Struct(cDisplay, NULL, XFree, imlib_context_get_display()); imlib_context_pop(); return disp; } /* * Set the current X11 Visual. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * context.set_visual visual * context.visual = visual * */ static VALUE ctx_set_visual(VALUE self, VALUE visual) { Visual *vis; Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); Data_Get_Struct(visual, Visual, vis); imlib_context_push(*ctx); imlib_context_set_visual(vis); imlib_context_pop(); return visual; } /* * Get the current X11 Visual. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * visual = context.get_visual * visual = context.visual * */ static VALUE ctx_visual(VALUE self) { Imlib_Context *ctx; VALUE vis; Data_Get_Struct(self, Imlib_Context, ctx); imlib_context_push(*ctx); vis = Data_Wrap_Struct(cVisual, NULL, XFree, imlib_context_get_visual()); imlib_context_pop(); return vis; } /* * Set the current X11 Colormap. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * context.set_colormap colormap * context.colormap = colormap * */ static VALUE ctx_set_colormap(VALUE self, VALUE colormap) { Colormap *cmap; Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); Data_Get_Struct(colormap, Colormap, cmap); imlib_context_push(*ctx); imlib_context_set_colormap(*cmap); imlib_context_pop(); return colormap; } /* * Get the current X11 Colormap. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * colormap = context.get_colormap * colormap = context.colormap * */ static VALUE ctx_colormap(VALUE self) { Imlib_Context *ctx; Colormap *cmap; VALUE colormap; Data_Get_Struct(self, Imlib_Context, ctx); cmap = malloc(sizeof(Colormap)); imlib_context_push(*ctx); *cmap = imlib_context_get_colormap(); colormap = Data_Wrap_Struct(cColormap, 0, dont_free, cmap); imlib_context_pop(); return colormap; } /* * Set the current X11 Drawable. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * context.set_drawable drawable * context.drawable = drawable * */ static VALUE ctx_set_drawable(VALUE self, VALUE drawable) { Drawable *draw; Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); Data_Get_Struct(drawable, Drawable, draw); imlib_context_push(*ctx); imlib_context_set_drawable(*draw); imlib_context_pop(); return drawable; } /* * Get the current X11 Drawable. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * drawable = context.get_drawable * drawable = context.drawable * */ static VALUE ctx_drawable(VALUE self) { Imlib_Context *ctx; Drawable *draw; VALUE drawable; Data_Get_Struct(self, Imlib_Context, ctx); draw = malloc(sizeof(Drawable)); imlib_context_push(*ctx); *draw = imlib_context_get_drawable(); drawable = Data_Wrap_Struct(cDrawable, NULL, dont_free, draw); imlib_context_pop(); return drawable; } /* * Set the current X11 Mask. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * context.set_mask mask * context.mask = mask * */ static VALUE ctx_set_mask(VALUE self, VALUE mask_o) { Pixmap *mask; Imlib_Context *ctx; Data_Get_Struct(self, Imlib_Context, ctx); Data_Get_Struct(mask_o, Pixmap, mask); imlib_context_push(*ctx); imlib_context_set_mask(*mask); imlib_context_pop(); return mask_o; } /* * Get the current X11 Mask. * * Note: This method is not available unless Imlib2-Ruby was compiled * with X11 support. You can check the constant Imlib2::X11_SUPPORT to * see if X11 support is available. * * Examples: * mask = context.get_mask * mask = context.mask * */ static VALUE ctx_mask(VALUE self) { Imlib_Context *ctx; Pixmap *pmap; VALUE mask; Data_Get_Struct(self, Imlib_Context, ctx); pmap = malloc(sizeof(Pixmap)); imlib_context_push(*ctx); *pmap = imlib_context_get_mask(); mask = Data_Wrap_Struct(cPixmap, NULL, pmap_free, pmap); imlib_context_pop(); return mask; } #endif /* !X_DISPLAY_MISSING */ /******************/ /* INIT FUNCTIONS */ /******************/ void setup_color_constants(void) { static struct { char *name; int r, g, b, a; } color_constants[] = { { "CLEAR", 0, 0, 0, 0 }, { "TRANSPARENT",0, 0, 0, 0 }, { "TRANSLUCENT",0, 0, 0, 0 }, { "SHADOW", 0, 0, 0, 64 }, { "BLACK", 0, 0, 0, 255 }, { "DARKGRAY", 64, 64, 64, 255 }, { "DARKGREY", 64, 64, 64, 255 }, { "GRAY", 128, 128, 128, 255 }, { "GREY", 128, 128, 128, 255 }, { "LIGHTGRAY", 192, 192, 192, 255 }, { "LIGHTGREY", 192, 192, 192, 255 }, { "WHITE", 255, 255, 255, 255 }, { "RED", 255, 0, 0, 255 }, { "GREEN", 0, 255, 0, 255 }, { "BLUE", 0, 0, 255, 255 }, { "YELLOW", 255, 255, 0, 255 }, { "ORANGE", 255, 128, 0, 255 }, { "BROWN", 128, 64, 0, 255 }, { "MAGENTA", 255, 0, 128, 255 }, { "VIOLET", 255, 0, 255, 255 }, { "PURPLE", 128, 0, 255, 255 }, { "INDEGO", 128, 0, 255, 255 }, { "CYAN", 0, 255, 255, 255 }, { "AQUA", 0, 128, 255, 255 }, { "AZURE", 0, 128, 255, 255 }, { "TEAL", 0, 255, 128, 255 }, { "DARKRED", 128, 0, 0, 255 }, { "DARKGREEN", 0, 128, 0, 255 }, { "DARKBLUE", 0, 0, 128, 255 }, { "DARKYELLOW", 128, 128, 0, 255 }, { "DARKORANGE", 128, 64, 0, 255 }, { "DARKBROWN", 64, 32, 0, 255 }, { "DARKMAGENTA",128, 0, 64, 255 }, { "DARKVIOLET", 128, 0, 128, 255 }, { "DARKPURPLE", 64, 0, 128, 255 }, { "DARKINDEGO", 64, 0, 128, 255 }, { "DARKCYAN", 0, 128, 128, 255 }, { "DARKAQUA", 0, 64, 128, 255 }, { "DARKAZURE", 0, 64, 128, 255 }, { "DARKTEAL", 0, 128, 64, 255 }, { NULL, 0, 0, 0, 0 } }; int i; VALUE args[4]; for (i = 0; color_constants[i].name != NULL; i++) { /* fprintf(stderr, "DEBUG: adding %s [%d, %d, %d, %d]\n", color_constants[i].name, color_constants[i].r, color_constants[i].g, color_constants[i].b, color_constants[i].a);*/ args[0] = INT2FIX(color_constants[i].r); args[1] = INT2FIX(color_constants[i].g); args[2] = INT2FIX(color_constants[i].b); args[3] = INT2FIX(color_constants[i].a); rb_define_const(mColor, color_constants[i].name, rgba_color_new(4, args, cRgbaColor)); } } void setup_error_constants(void) { int i = 0; cFileError = rb_define_class_under(mImlib2, "FileError", rb_eException); mError = rb_define_module_under(mImlib2, "Error"); cDeletedError = rb_define_class_under(mError, "DeletedError", rb_eException); for (i = 0; i <= IMLIB_LOAD_ERROR_UNKNOWN; i++) imlib_errors[i].exception = rb_define_class_under(mError, imlib_errors[i].name, cFileError); } void Init_imlib2() { /* fprintf(stderr, "DEBUG: Loading Imlib2.so...\n"); */ mImlib2 = rb_define_module("Imlib2"); rb_define_const(mImlib2, "VERSION", rb_str_new2(VERSION)); #ifdef X_DISPLAY_MISSING rb_define_const(mImlib2, "X11_SUPPORT", Qfalse); #else rb_define_const(mImlib2, "X11_SUPPORT", Qtrue); #endif /* X_DISPLAY_MISSING */ /************************/ /* define Context class */ /************************/ cContext = rb_define_class_under(mImlib2, "Context", rb_cObject); rb_define_singleton_method(cContext, "new", ctx_new, 0); rb_define_method(cContext, "initialize", ctx_init, 0); /* context stack methods */ rb_define_method(cContext, "push", ctx_push, 0); rb_define_singleton_method(cContext, "pop", ctx_pop, 0); rb_define_singleton_method(cContext, "get", ctx_get, 0); rb_define_singleton_method(cContext, "current", ctx_get, 0); rb_define_method(cContext, "set_dither", ctx_set_dither, 1); rb_define_method(cContext, "dither=", ctx_set_dither, 1); rb_define_method(cContext, "get_dither", ctx_dither, 0); rb_define_method(cContext, "dither", ctx_dither, 0); rb_define_method(cContext, "set_dither_mask", ctx_set_dither_mask, 1); rb_define_method(cContext, "dither_mask=", ctx_set_dither_mask, 1); rb_define_method(cContext, "get_dither_mask", ctx_dither_mask, 0); rb_define_method(cContext, "dither_mask", ctx_dither_mask, 0); rb_define_method(cContext, "set_anti_alias", ctx_set_aa, 1); rb_define_method(cContext, "anti_alias=", ctx_set_aa, 1); rb_define_method(cContext, "aa=", ctx_set_aa, 1); rb_define_method(cContext, "get_anti_alias", ctx_aa, 0); rb_define_method(cContext, "anti_alias", ctx_aa, 0); rb_define_method(cContext, "aa", ctx_aa, 0); rb_define_method(cContext, "set_blend", ctx_set_blend, 1); rb_define_method(cContext, "blend=", ctx_set_blend, 1); rb_define_method(cContext, "get_blend", ctx_blend, 0); rb_define_method(cContext, "blend", ctx_blend, 0); rb_define_method(cContext, "set_color_modifier", ctx_set_cmod, 1); rb_define_method(cContext, "color_modifier=", ctx_set_cmod, 1); rb_define_method(cContext, "cmod=", ctx_set_cmod, 1); rb_define_method(cContext, "get_color_modifier", ctx_cmod, 0); rb_define_method(cContext, "color_modifier", ctx_cmod, 0); rb_define_method(cContext, "cmod", ctx_cmod, 0); rb_define_method(cContext, "set_operation", ctx_set_op, 1); rb_define_method(cContext, "operation=", ctx_set_op, 1); rb_define_method(cContext, "op=", ctx_set_op, 1); rb_define_method(cContext, "get_operation", ctx_op, 0); rb_define_method(cContext, "operation", ctx_op, 0); rb_define_method(cContext, "op", ctx_op, 0); rb_define_method(cContext, "set_font", ctx_set_font, 1); rb_define_method(cContext, "font=", ctx_set_font, 1); rb_define_method(cContext, "get_font", ctx_font, 0); rb_define_method(cContext, "font", ctx_font, 0); rb_define_method(cContext, "set_direction", ctx_set_dir, 1); rb_define_method(cContext, "direction=", ctx_set_dir, 1); rb_define_method(cContext, "dir=", ctx_set_dir, 1); rb_define_method(cContext, "get_direction", ctx_dir, 0); rb_define_method(cContext, "direction", ctx_dir, 0); rb_define_method(cContext, "dir", ctx_dir, 0); rb_define_method(cContext, "set_angle", ctx_set_angle, 1); rb_define_method(cContext, "angle=", ctx_set_angle, 1); rb_define_method(cContext, "get_angle", ctx_angle, 0); rb_define_method(cContext, "angle", ctx_angle, 0); rb_define_method(cContext, "set_color", ctx_set_color, 1); rb_define_method(cContext, "color=", ctx_set_color, 1); rb_define_method(cContext, "get_color", ctx_color, 0); rb_define_method(cContext, "color", ctx_color, 0); /* FIXME: add support for multiple color types */ /* maybe add aliases for color_range? */ rb_define_method(cContext, "set_gradient", ctx_set_gradient, 1); rb_define_method(cContext, "gradient=", ctx_set_gradient, 1); rb_define_method(cContext, "get_gradient", ctx_gradient, 0); rb_define_method(cContext, "gradient", ctx_gradient, 0); rb_define_method(cContext, "set_progress_granularity", ctx_set_progress_granularity, 1); rb_define_method(cContext, "progress_granularity=", ctx_set_progress_granularity, 1); rb_define_method(cContext, "get_progress_granularity", ctx_progress_granularity, 0); rb_define_method(cContext, "progress_granularity", ctx_progress_granularity, 0); rb_define_method(cContext, "set_image", ctx_set_image, 1); rb_define_method(cContext, "image=", ctx_set_image, 1); rb_define_method(cContext, "get_image", ctx_image, 0); rb_define_method(cContext, "image", ctx_image, 0); rb_define_method(cContext, "set_cliprect", ctx_set_cliprect, 1); rb_define_method(cContext, "cliprect=", ctx_set_cliprect, 1); rb_define_method(cContext, "get_cliprect", ctx_cliprect, 0); rb_define_method(cContext, "cliprect", ctx_cliprect, 0); rb_define_method(cContext, "set_ttf_encoding", ctx_set_encoding, 1); rb_define_method(cContext, "set_encoding", ctx_set_encoding, 1); rb_define_method(cContext, "encoding=", ctx_set_encoding, 1); rb_define_method(cContext, "get_encoding", ctx_encoding, 0); rb_define_method(cContext, "get_ttf_encoding", ctx_encoding, 0); rb_define_method(cContext, "encoding", ctx_encoding, 0); #ifndef X_DISPLAY_MISSING /* context X11 methods */ rb_define_method(cContext, "set_display", ctx_set_display, 1); rb_define_method(cContext, "display=", ctx_set_display, 1); rb_define_method(cContext, "get_display", ctx_display, 0); rb_define_method(cContext, "display", ctx_display, 0); rb_define_method(cContext, "set_visual", ctx_set_visual, 1); rb_define_method(cContext, "visual=", ctx_set_visual, 1); rb_define_method(cContext, "get_visual", ctx_visual, 0); rb_define_method(cContext, "visual", ctx_visual, 0); rb_define_method(cContext, "set_colormap", ctx_set_cmap, 1); rb_define_method(cContext, "colormap=", ctx_set_cmap, 1); rb_define_method(cContext, "set_cmap", ctx_set_cmap, 1); rb_define_method(cContext, "cmap=", ctx_set_cmap, 1); rb_define_method(cContext, "get_colormap", ctx_cmap, 0); rb_define_method(cContext, "colormap", ctx_cmap, 0); rb_define_method(cContext, "get_cmap", ctx_cmap, 0); rb_define_method(cContext, "cmap", ctx_cmap, 0); rb_define_method(cContext, "set_drawable", ctx_set_drawable, 1); rb_define_method(cContext, "drawable=", ctx_set_drawable, 1); rb_define_method(cContext, "get_drawable", ctx_drawable, 0); rb_define_method(cContext, "drawable", ctx_drawable, 0); rb_define_method(cContext, "set_mask", ctx_set_mask, 1); rb_define_method(cContext, "mask=", ctx_set_mask, 1); rb_define_method(cContext, "get_mask", ctx_mask, 0); rb_define_method(cContext, "mask", ctx_mask, 0); rb_define_method(cContext, "get_visual", ctx_visual, -1); rb_define_method(cContext, "visual", ctx_visual, -1); rb_define_method(cContext, "get_best_visual", ctx_visual, -1); rb_define_method(cContext, "best_visual", ctx_visual, -1); #endif /* X_DISPLAY_MISSING */ /**********************/ /* define Error class */ /**********************/ setup_error_constants(); /*********************/ /* define Dir module */ /*********************/ mTextDir = rb_define_module_under(mImlib2, "Dir"); rb_define_const(mTextDir, "RIGHT", INT2FIX(IMLIB_TEXT_TO_RIGHT)); rb_define_const(mTextDir, "LEFT", INT2FIX(IMLIB_TEXT_TO_LEFT)); rb_define_const(mTextDir, "DOWN", INT2FIX(IMLIB_TEXT_TO_DOWN)); rb_define_const(mTextDir, "UP", INT2FIX(IMLIB_TEXT_TO_UP)); rb_define_const(mTextDir, "ANGLE", INT2FIX(IMLIB_TEXT_TO_ANGLE)); /***************************/ /* define Direction module */ /* (can't alias modules) */ /***************************/ mTextDir = rb_define_module_under(mImlib2, "Direction"); rb_define_const(mTextDir, "RIGHT", INT2FIX(IMLIB_TEXT_TO_RIGHT)); rb_define_const(mTextDir, "LEFT", INT2FIX(IMLIB_TEXT_TO_LEFT)); rb_define_const(mTextDir, "DOWN", INT2FIX(IMLIB_TEXT_TO_DOWN)); rb_define_const(mTextDir, "UP", INT2FIX(IMLIB_TEXT_TO_UP)); rb_define_const(mTextDir, "ANGLE", INT2FIX(IMLIB_TEXT_TO_ANGLE)); /********************/ /* define Op module */ /********************/ mOp = rb_define_module_under(mImlib2, "Op"); rb_define_const(mOp, "COPY", INT2FIX(IMLIB_OP_COPY)); rb_define_const(mOp, "ADD", INT2FIX(IMLIB_OP_ADD)); rb_define_const(mOp, "SUBTRACT", INT2FIX(IMLIB_OP_SUBTRACT)); rb_define_const(mOp, "RESHADE", INT2FIX(IMLIB_OP_RESHADE)); /*******************************/ /* define Operation module */ /* (can't alias modules.. yet) */ /*******************************/ mOperation = rb_define_module_under(mImlib2, "Operation"); rb_define_const(mOperation, "COPY", INT2FIX(IMLIB_OP_COPY)); rb_define_const(mOperation, "ADD", INT2FIX(IMLIB_OP_ADD)); rb_define_const(mOperation, "SUBTRACT", INT2FIX(IMLIB_OP_SUBTRACT)); rb_define_const(mOperation, "RESHADE", INT2FIX(IMLIB_OP_RESHADE)); /**************************/ /* define Encoding module */ /**************************/ mEncoding = rb_define_module_under(mImlib2, "Encoding"); rb_define_const(mEncoding, "ISO_8859_1", INT2FIX(IMLIB_TTF_ENCODING_ISO_8859_1)); rb_define_const(mEncoding, "ISO_8859_2", INT2FIX(IMLIB_TTF_ENCODING_ISO_8859_2)); rb_define_const(mEncoding, "ISO_8859_3", INT2FIX(IMLIB_TTF_ENCODING_ISO_8859_3)); rb_define_const(mEncoding, "ISO_8859_4", INT2FIX(IMLIB_TTF_ENCODING_ISO_8859_4)); rb_define_const(mEncoding, "ISO_8859_5", INT2FIX(IMLIB_TTF_ENCODING_ISO_8859_5)); /***********************/ /* define Border class */ /***********************/ cBorder = rb_define_class_under(mImlib2, "Border", rb_cObject); rb_define_singleton_method(cBorder, "new", border_new, -1); rb_define_method(cBorder, "initialize", border_init, -1); /* FIXME rb_define_method(cBorder, "[]", border_ary, 0); rb_define_method(cBorder, "[]=", border_set_ary, 2); */ rb_define_method(cBorder, "left", border_left, 0); rb_define_method(cBorder, "left=", border_set_left, 1); rb_define_alias(cBorder, "l", "left"); rb_define_alias(cBorder, "l=", "left="); rb_define_method(cBorder, "right", border_right, 0); rb_define_method(cBorder, "right=", border_set_right, 1); rb_define_alias(cBorder, "r", "right"); rb_define_alias(cBorder, "r=", "right="); rb_define_method(cBorder, "top", border_top, 0); rb_define_method(cBorder, "top=", border_set_top, 1); rb_define_alias(cBorder, "t", "top"); rb_define_alias(cBorder, "t=", "top="); rb_define_method(cBorder, "bottom", border_bottom, 0); rb_define_method(cBorder, "bottom=", border_set_bottom, 1); rb_define_alias(cBorder, "b", "bottom"); rb_define_alias(cBorder, "b=", "bottom="); /***********************/ /* define Cache module */ /***********************/ mCache = rb_define_module_under(mImlib2, "Cache"); rb_define_singleton_method(mCache, "image", cache_image, 0); rb_define_singleton_method(mCache, "image=", cache_set_image, 1); rb_define_singleton_method(mCache, "image_cache", cache_image, 0); rb_define_singleton_method(mCache, "image_cache=", cache_set_image, 1); rb_define_singleton_method(mCache, "get_image_cache", cache_image, 0); rb_define_singleton_method(mCache, "set_image_cache", cache_set_image, 1); rb_define_singleton_method(mCache, "font", cache_font, 0); rb_define_singleton_method(mCache, "font=", cache_set_font, 1); rb_define_singleton_method(mCache, "font_cache", cache_font, 0); rb_define_singleton_method(mCache, "font_cache=", cache_set_font, 1); rb_define_singleton_method(mCache, "get_font_cache", cache_font, 0); rb_define_singleton_method(mCache, "set_font_cache", cache_set_font, 1); rb_define_singleton_method(mCache, "flush_font_cache", cache_flush_font, 0); /***********************/ /* define Color module */ /***********************/ mColor = rb_define_module_under(mImlib2, "Color"); /***************************/ /* define RGBA Color class */ /***************************/ cRgbaColor = rb_define_class_under(mColor, "RgbaColor", rb_cObject); rb_define_singleton_method(cRgbaColor, "new", rgba_color_new, -1); rb_define_method(cRgbaColor, "initialize", rgba_color_init, -1); /* FIXME rb_define_method(cRgbaColor, "[]", rgba_color_ary, 0); rb_define_method(cRgbaColor, "[]=", rgba_color_set_ary, 2); */ rb_define_method(cRgbaColor, "r", rgba_color_red, 0); rb_define_method(cRgbaColor, "r=", rgba_color_set_red, 1); rb_define_method(cRgbaColor, "red", rgba_color_red, 0); rb_define_method(cRgbaColor, "red=", rgba_color_set_red, 1); rb_define_method(cRgbaColor, "g", rgba_color_green, 0); rb_define_method(cRgbaColor, "g=", rgba_color_set_green, 1); rb_define_method(cRgbaColor, "green", rgba_color_green, 0); rb_define_method(cRgbaColor, "green=", rgba_color_set_green, 1); rb_define_method(cRgbaColor, "b", rgba_color_blue, 0); rb_define_method(cRgbaColor, "b=", rgba_color_set_blue, 1); rb_define_method(cRgbaColor, "blue", rgba_color_blue, 0); rb_define_method(cRgbaColor, "blue=", rgba_color_set_blue, 1); rb_define_method(cRgbaColor, "a", rgba_color_alpha, 0); rb_define_method(cRgbaColor, "a=", rgba_color_set_alpha, 1); rb_define_method(cRgbaColor, "alpha", rgba_color_alpha, 0); rb_define_method(cRgbaColor, "alpha=", rgba_color_set_alpha, 1); /***************************/ /* define HSVA Color class */ /***************************/ cHsvaColor = rb_define_class_under(mColor, "HsvaColor", rb_cObject); rb_define_singleton_method(cHsvaColor, "new", hsva_color_new, -1); rb_define_method(cHsvaColor, "initialize", hsva_color_init, -1); /* FIXME rb_define_method(cHsvaColor, "[]", hsva_color_ary, 0); rb_define_method(cHsvaColor, "[]=", hsva_color_set_ary, 2); */ rb_define_method(cHsvaColor, "h", hsva_color_hue, 0); rb_define_method(cHsvaColor, "h=", hsva_color_set_hue, 1); rb_define_method(cHsvaColor, "hue", hsva_color_hue, 0); rb_define_method(cHsvaColor, "hue=", hsva_color_set_hue, 1); rb_define_method(cHsvaColor, "s", hsva_color_saturation, 0); rb_define_method(cHsvaColor, "s=", hsva_color_set_saturation, 1); rb_define_method(cHsvaColor, "saturation", hsva_color_saturation, 0); rb_define_method(cHsvaColor, "saturation=", hsva_color_set_saturation, 1); rb_define_method(cHsvaColor, "v", hsva_color_value, 0); rb_define_method(cHsvaColor, "v=", hsva_color_set_value, 1); rb_define_method(cHsvaColor, "value", hsva_color_value, 0); rb_define_method(cHsvaColor, "value=", hsva_color_set_value, 1); rb_define_method(cHsvaColor, "a", hsva_color_alpha, 0); rb_define_method(cHsvaColor, "a=", hsva_color_set_alpha, 1); rb_define_method(cHsvaColor, "alpha", hsva_color_alpha, 0); rb_define_method(cHsvaColor, "alpha=", hsva_color_set_alpha, 1); /***************************/ /* define HSVA Color class */ /***************************/ cHlsaColor = rb_define_class_under(mColor, "HlsaColor", rb_cObject); rb_define_singleton_method(cHlsaColor, "new", hlsa_color_new, -1); rb_define_method(cHlsaColor, "initialize", hlsa_color_init, -1); /* FIXME rb_define_method(cHlsaColor, "[]", hlsa_color_ary, 0); rb_define_method(cHlsaColor, "[]=", hlsa_color_set_ary, 2); */ rb_define_method(cHlsaColor, "h", hlsa_color_hue, 0); rb_define_method(cHlsaColor, "h=", hlsa_color_set_hue, 1); rb_define_method(cHlsaColor, "hue", hlsa_color_hue, 0); rb_define_method(cHlsaColor, "hue=", hlsa_color_set_hue, 1); rb_define_method(cHlsaColor, "l", hlsa_color_lightness, 0); rb_define_method(cHlsaColor, "l=", hlsa_color_set_lightness, 1); rb_define_method(cHlsaColor, "lightness", hlsa_color_lightness, 0); rb_define_method(cHlsaColor, "lightness=", hlsa_color_set_lightness, 1); rb_define_method(cHlsaColor, "s", hlsa_color_saturation, 0); rb_define_method(cHlsaColor, "s=", hlsa_color_set_saturation, 1); rb_define_method(cHlsaColor, "saturation", hlsa_color_saturation, 0); rb_define_method(cHlsaColor, "saturation=", hlsa_color_set_saturation, 1); rb_define_method(cHlsaColor, "a", hlsa_color_alpha, 0); rb_define_method(cHlsaColor, "a=", hlsa_color_set_alpha, 1); rb_define_method(cHlsaColor, "alpha", hlsa_color_alpha, 0); rb_define_method(cHlsaColor, "alpha=", hlsa_color_set_alpha, 1); /***************************/ /* define CMYA Color class */ /***************************/ cCmyaColor = rb_define_class_under(mColor, "CmyaColor", rb_cObject); rb_define_singleton_method(cCmyaColor, "new", cmya_color_new, -1); rb_define_method(cCmyaColor, "initialize", cmya_color_init, -1); /* FIXME rb_define_method(cCmyaColor, "[]", cmya_color_ary, 0); rb_define_method(cCmyaColor, "[]=", cmya_color_set_ary, 2); */ rb_define_method(cCmyaColor, "c", cmya_color_cyan, 0); rb_define_method(cCmyaColor, "c=", cmya_color_set_cyan, 1); rb_define_method(cCmyaColor, "cyan", cmya_color_cyan, 0); rb_define_method(cCmyaColor, "cyan=", cmya_color_set_cyan, 1); rb_define_method(cCmyaColor, "m", cmya_color_magenta, 0); rb_define_method(cCmyaColor, "m=", cmya_color_set_magenta, 1); rb_define_method(cCmyaColor, "magenta", cmya_color_magenta, 0); rb_define_method(cCmyaColor, "magenta=", cmya_color_set_magenta, 1); rb_define_method(cCmyaColor, "y", cmya_color_yellow, 0); rb_define_method(cCmyaColor, "y=", cmya_color_set_yellow, 1); rb_define_method(cCmyaColor, "yellow", cmya_color_yellow, 0); rb_define_method(cCmyaColor, "yellow=", cmya_color_set_yellow, 1); rb_define_method(cCmyaColor, "a", cmya_color_alpha, 0); rb_define_method(cCmyaColor, "a=", cmya_color_set_alpha, 1); rb_define_method(cCmyaColor, "alpha", cmya_color_alpha, 0); rb_define_method(cCmyaColor, "alpha=", cmya_color_set_alpha, 1); /**************************/ /* define Color constants */ /**************************/ setup_color_constants(); /*************************/ /* define ColorMod class */ /*************************/ cColorMod = rb_define_class_under(mImlib2, "ColorModifier", rb_cObject); rb_define_singleton_method(cColorMod, "new", cmod_new, -1); rb_define_method(cColorMod, "initialize", cmod_init, -1); rb_define_method(cColorMod, "gamma=", cmod_gamma, 1); rb_define_method(cColorMod, "brightness=", cmod_brightness, 1); rb_define_method(cColorMod, "contrast=", cmod_contrast, 1); rb_define_method(cColorMod, "reset", cmod_reset, 0); /*************************/ /* define Gradient class */ /*************************/ cGradient = rb_define_class_under(mImlib2, "Gradient", rb_cObject); rb_define_singleton_method(cGradient, "new", gradient_new, -1); rb_define_method(cGradient, "initialize", gradient_init, -1); rb_define_method(cGradient, "add_color", gradient_add_color, 2); /* hack: alias should work with modules and classes as well :) */ /* disabled: this breaks with Rails (and probably other stuff */ /* * rb_eval_string( * "module Imlib2\n" * " class ColorRange < Gradient\n" * " end\n" * "end\n" * ); */ /**********************/ /* define Image class */ /**********************/ cImage = rb_define_class_under(mImlib2, "Image", rb_cObject); rb_define_singleton_method(cImage, "new", image_new, 2); rb_define_method(cImage, "initialize", image_initialize, 0); /* workarounds */ rb_define_singleton_method(cImage, "draw_pixel_workaround?", image_dp_workaround, 0); rb_define_singleton_method(cImage, "bypass_draw_pixel?", image_dp_workaround, 0); rb_define_singleton_method(cImage, "draw_pixel_workaround=", image_dp_workaround, 1); rb_define_singleton_method(cImage, "bypass_draw_pixel=", image_dp_workaround, 1); /* create methods */ rb_define_singleton_method(cImage, "create", image_new, 2); rb_define_singleton_method(cImage, "create_using_data", image_create_using_data, 3); rb_define_singleton_method(cImage, "create_using_copied_data", image_create_using_copied_data, 3); /* load methods */ rb_define_singleton_method(cImage, "load", image_load, 1); rb_define_singleton_method(cImage, "load_image", image_load_image, 1); rb_define_singleton_method(cImage, "load_immediately", image_load_immediately, 1); rb_define_singleton_method(cImage, "load_without_cache", image_load_without_cache, 1); rb_define_singleton_method(cImage, "load_immediately_without_cache", image_load_immediately_without_cache, 1); rb_define_singleton_method(cImage, "load_with_error_return", image_load_with_error_return, 1); /* save methods */ rb_define_method(cImage, "save", image_save, 1); rb_define_method(cImage, "save_image", image_save_image, 1); rb_define_method(cImage, "save_with_error_return", image_save_with_error_return, 1); /* delete method */ rb_define_method(cImage, "delete!", image_delete, -1); /* member methods */ rb_define_method(cImage, "width", image_width, 0); rb_define_method(cImage, "w", image_width, 0); rb_define_method(cImage, "height", image_height, 0); rb_define_method(cImage, "h", image_height, 0); rb_define_method(cImage, "filename", image_filename, 0); rb_define_method(cImage, "data", image_data, 0); rb_define_method(cImage, "data_for_reading_only", image_data_ro, 0); rb_define_method(cImage, "data!", image_data_ro, 0); rb_define_method(cImage, "data=", image_put_data, 1); rb_define_method(cImage, "put_back_data", image_put_data, 1); rb_define_method(cImage, "has_alpha", image_has_alpha, 0); rb_define_method(cImage, "has_alpha?", image_has_alpha, 0); rb_define_method(cImage, "has_alpha=", image_set_has_alpha, 1); rb_define_method(cImage, "set_has_alpha", image_set_has_alpha, 1); rb_define_method(cImage, "changes_on_disk", image_changes_on_disk, 0); rb_define_method(cImage, "set_changes_on_disk", image_changes_on_disk, 0); rb_define_method(cImage, "border", image_get_border, 0); rb_define_method(cImage, "get_border", image_get_border, 0); rb_define_method(cImage, "border=", image_set_border, 1); rb_define_method(cImage, "set_border", image_set_border, 1); rb_define_method(cImage, "format", image_get_format, 0); rb_define_method(cImage, "get_format", image_get_format, 0); rb_define_method(cImage, "format=", image_set_format, 1); rb_define_method(cImage, "set_format", image_set_format, 1); rb_define_method(cImage, "irrelevant_format=", image_irrelevant_format, 1); rb_define_method(cImage, "set_irrelevant_format", image_irrelevant_format, 1); rb_define_method(cImage, "irrelevant_border=", image_irrelevant_border, 1); rb_define_method(cImage, "set_irrelevant_border", image_irrelevant_border, 1); rb_define_method(cImage, "irrelevant_alpha=", image_irrelevant_alpha, 1); rb_define_method(cImage, "set_irrelevant_alpha", image_irrelevant_alpha, 1); rb_define_method(cImage, "pixel", image_query_pixel, 2); rb_define_method(cImage, "pixel_rgba", image_query_pixel, 2); rb_define_method(cImage, "query_pixel", image_query_pixel, 2); rb_define_method(cImage, "query_pixel_rgba", image_query_pixel, 2); rb_define_method(cImage, "pixel_hsva", image_query_pixel_hsva, 2); rb_define_method(cImage, "query_pixel_hsva", image_query_pixel_hsva, 2); rb_define_method(cImage, "pixel_hlsa", image_query_pixel_hlsa, 2); rb_define_method(cImage, "query_pixel_hlsa", image_query_pixel_hlsa, 2); rb_define_method(cImage, "pixel_cmya", image_query_pixel_cmya, 2); rb_define_method(cImage, "query_pixel_cmya", image_query_pixel_cmya, 2); /* more create methods */ rb_define_method(cImage, "crop", image_crop, -1); rb_define_method(cImage, "create_cropped", image_crop, -1); rb_define_method(cImage, "crop!", image_crop_inline, -1); rb_define_method(cImage, "create_cropped!", image_crop_inline, -1); rb_define_method(cImage, "crop_scaled", image_crop_scaled, -1); rb_define_method(cImage, "create_cropped_scaled", image_crop_scaled, -1); rb_define_method(cImage, "crop_scaled!", image_crop_scaled_inline, -1); rb_define_method(cImage, "create_cropped_scaled!", image_crop_scaled_inline, -1); /* image modification methods */ rb_define_method(cImage, "flip_horizontal", image_flip_horizontal, 0); rb_define_method(cImage, "flip_horizontal!", image_flip_horizontal_inline, 0); rb_define_method(cImage, "flip_vertical", image_flip_vertical, 0); rb_define_method(cImage, "flip_vertical!", image_flip_vertical_inline, 0); rb_define_method(cImage, "flip_diagonal", image_flip_diagonal, 0); rb_define_method(cImage, "flip_diagonal!", image_flip_diagonal_inline, 0); rb_define_method(cImage, "orientate", image_orientate, 1); rb_define_method(cImage, "orientate!", image_orientate_inline, 1); rb_define_method(cImage, "blur", image_blur, 1); rb_define_method(cImage, "blur!", image_blur_inline, 1); rb_define_method(cImage, "sharpen", image_sharpen, 1); rb_define_method(cImage, "sharpen!", image_sharpen_inline, 1); rb_define_method(cImage, "tile_horizontal", image_tile_horizontal, 0); rb_define_method(cImage, "tile_horizontal!", image_tile_horizontal_inline, 0); rb_define_method(cImage, "tile_vertical", image_tile_vertical, 0); rb_define_method(cImage, "tile_vertical!", image_tile_vertical_inline, 0); rb_define_method(cImage, "tile", image_tile, 0); rb_define_method(cImage, "tile!", image_tile_inline, 0); /* image drawing methods */ rb_define_method(cImage, "draw_pixel", image_draw_pixel, -1); rb_define_method(cImage, "draw_line", image_draw_line, -1); /* FIXME: rb_define_method(cImage, "clip_line", image_clip_line, -1);*/ rb_define_method(cImage, "draw_rect", image_draw_rect, -1); rb_define_method(cImage, "draw_rectangle", image_draw_rect, -1); rb_define_method(cImage, "fill_rect", image_fill_rect, -1); rb_define_method(cImage, "fill_rectangle", image_fill_rect, -1); rb_define_method(cImage, "copy_alpha", image_copy_alpha, -1); rb_define_method(cImage, "copy_alpha_rect", image_copy_alpha_rect, -1); rb_define_method(cImage, "scroll_rect", image_scroll_rect, -1); rb_define_method(cImage, "copy_rect", image_copy_rect, -1); /* ellipse drawing methods */ rb_define_method(cImage, "draw_ellipse", image_draw_ellipse, -1); rb_define_method(cImage, "draw_oval", image_draw_ellipse, -1); rb_define_method(cImage, "fill_ellipse", image_fill_ellipse, -1); rb_define_method(cImage, "fill_oval", image_fill_ellipse, -1); /* text drawing methods */ rb_define_method(cImage, "draw_text", image_draw_text, -1); /* gradient (color range) drawing methods */ rb_define_method(cImage, "gradient", image_fill_gradient, -1); rb_define_method(cImage, "fill_gradient", image_fill_gradient, -1); rb_define_method(cImage, "color_range", image_fill_gradient, -1); rb_define_method(cImage, "fill_color_range", image_fill_gradient, -1); /* polygon drawing methods */ rb_define_method(cImage, "draw_poly", image_draw_poly, -1); rb_define_method(cImage, "draw_polygon", image_draw_poly, -1); rb_define_method(cImage, "fill_poly", image_fill_poly, -1); rb_define_method(cImage, "fill_polygon", image_fill_poly, -1); /* blend methods */ rb_define_method(cImage, "blend!", image_blend_image_inline, -1); rb_define_method(cImage, "blend_image!", image_blend_image_inline, -1); rb_define_method(cImage, "blend", image_blend_image, -1); rb_define_method(cImage, "blend_image", image_blend_image, -1); /* rotation / skewing methods */ rb_define_method(cImage, "rotate", image_rotate, 1); rb_define_method(cImage, "rotate!", image_rotate_inline, 1); /* misc methods */ rb_define_method(cImage, "clone", image_clone, 0); rb_define_method(cImage, "dup", image_clone, 0); /* clear methods */ rb_define_method(cImage, "clear", image_clear, 0); rb_define_method(cImage, "clear_color", image_clear_color, 1); rb_define_method(cImage, "clear_color!", image_clear_color_inline, 1); /* polymorphic (implicit) filter methods */ rb_define_method(cImage, "filter", image_filter, 1); rb_define_method(cImage, "apply_filter", image_filter, 1); /* explicit filter methods */ rb_define_method(cImage, "static_filter", image_static_filter, 1); rb_define_method(cImage, "script_filter", image_script_filter, 1); /* color modifier methods */ rb_define_method(cImage, "apply_color_modifier", image_apply_cmod, 1); rb_define_method(cImage, "apply_cmod", image_apply_cmod, 1); rb_define_method(cImage, "apply", image_apply_cmod, 1); rb_define_method(cImage, "attach_value", image_attach_val, 2); rb_define_method(cImage, "get_attached_value", image_get_attach_val, 1); rb_define_method(cImage, "remove_attached_value", image_rm_attach_val, 1); rb_define_method(cImage, "[]", image_get_attach_val, 1); rb_define_method(cImage, "[]=", image_attach_val, 2); /* image X11 methods */ #ifndef X_DISPLAY_MISSING /* pixmap methods */ /* wraps all three pixmap render calls */ rb_define_method(cImage, "render_pixmap", image_render_pmap, -1); rb_define_method(cImage, "pixmap", image_render_pmap, -1); /* drawable methods */ /* wraps all three drawable render calls */ rb_define_method(cImage, "render_on_drawable", image_render_on_drawable, -1); /* X11 create methods */ rb_define_singleton_method(cImage, "create_from_drawable", image_create_from_drawable, -1); rb_define_singleton_method(cImage, "create_from_ximage", image_create_from_ximage, -1); rb_define_method(cImage, "copy_drawable", image_copy_drawable, -1); rb_define_method(cImage, "blend_drawable", image_blend_drawable, -1); rb_define_method(cImage, "render_on_drawable_skewed", image_render_drawable_skewed, -1); rb_define_method(cImage, "render_on_drawable_at_angle", image_render_drawable_angle, -1); #endif /* X_DISPLAY_MISSING */ /***********************/ /* define Filter class */ /***********************/ cFilter = rb_define_class_under(mImlib2, "Filter", rb_cObject); rb_define_singleton_method(cFilter, "new", filter_new, 1); rb_define_method(cFilter, "initialize", filter_init, 1); rb_define_method(cFilter, "set", filter_set, -1); rb_define_method(cFilter, "red", filter_set_red, -1); rb_define_method(cFilter, "set_red", filter_set_red, -1); rb_define_method(cFilter, "green", filter_set_green, -1); rb_define_method(cFilter, "set_green", filter_set_green, -1); rb_define_method(cFilter, "blue", filter_set_blue, -1); rb_define_method(cFilter, "set_blue", filter_set_blue, -1); rb_define_method(cFilter, "alpha", filter_set_alpha, -1); rb_define_method(cFilter, "set_alpha", filter_set_alpha, -1); rb_define_method(cFilter, "constants", filter_constants, 1); rb_define_method(cFilter, "divisors", filter_divisors, 1); /*********************/ /* define Font class */ /*********************/ cFont = rb_define_class_under(mImlib2, "Font", rb_cObject); rb_define_singleton_method(cFont, "new", font_new, 1); rb_define_singleton_method(cFont, "load", font_new, 1); rb_define_method(cFont, "initialize", font_init, 0); rb_define_method(cFont, "size", font_text_size, 1); rb_define_method(cFont, "text_size", font_text_size, 1); rb_define_method(cFont, "get_text_size", font_text_size, 1); rb_define_method(cFont, "advance", font_text_advance, 1); rb_define_method(cFont, "text_advance", font_text_advance, 1); rb_define_method(cFont, "get_text_advance", font_text_advance, 1); rb_define_method(cFont, "inset", font_text_inset, 1); rb_define_method(cFont, "text_inset", font_text_inset, 1); rb_define_method(cFont, "get_text_inset", font_text_inset, 1); rb_define_method(cFont, "index", font_text_index, -1); rb_define_method(cFont, "text_index", font_text_index, -1); rb_define_method(cFont, "text_index_and_location", font_text_index, -1); rb_define_method(cFont, "get_text_index_and_location", font_text_index, -1); rb_define_method(cFont, "location", font_text_location, 2); rb_define_method(cFont, "text_location", font_text_location, 2); rb_define_method(cFont, "text_location_at_index", font_text_location, 2); rb_define_method(cFont, "get_text_location_at_index", font_text_location, 2); rb_define_method(cFont, "ascent", font_ascent, 0); rb_define_method(cFont, "get_ascent", font_ascent, 0); rb_define_method(cFont, "descent", font_descent, 0); rb_define_method(cFont, "get_descent", font_descent, 0); rb_define_method(cFont, "maximum_ascent", font_maximum_ascent, 0); rb_define_method(cFont, "get_maximum_ascent", font_maximum_ascent, 0); rb_define_method(cFont, "maximum_descent", font_maximum_descent, 0); rb_define_method(cFont, "get_maximum_descent", font_maximum_descent, 0); /*******************************/ /* define Font singletons */ /* (font list, and font paths) */ /*******************************/ rb_define_singleton_method(cFont, "list", font_list_fonts, 0); rb_define_singleton_method(cFont, "fonts", font_list_fonts, 0); rb_define_singleton_method(cFont, "list_fonts", font_list_fonts, 0); rb_define_singleton_method(cFont, "add_path", font_add_path, 1); rb_define_singleton_method(cFont, "remove_path", font_remove_path, 1); rb_define_singleton_method(cFont, "paths", font_list_paths, 0); rb_define_singleton_method(cFont, "list_paths", font_list_paths, 0); /*********************/ /* define Font class */ /*********************/ cPolygon = rb_define_class_under(mImlib2, "Polygon", rb_cObject); rb_define_singleton_method(cPolygon, "new", poly_new, -1); rb_define_method(cPolygon, "initialize", poly_init, -1); rb_define_method(cPolygon, "add_point", poly_add_point, -1); rb_define_method(cPolygon, "bounds", poly_bounds, 0); rb_define_method(cPolygon, "get_bounds", poly_bounds, 0); rb_define_method(cPolygon, "contains?", poly_contains, -1); rb_define_method(cPolygon, "contains_point?", poly_contains, -1); #ifndef X_DISPLAY_MISSING /*********************/ /* define X11 module */ /*********************/ mX11 = rb_define_module_under(mImlib2, "X11", rb_cObject); cDisplay = rb_define_class_under(mX11, "Display", rb_cObject); rb_define_singleton_method(cDisplay, "new", disp_new, 0); rb_define_method(cDisplay, "initialize", disp_init, 0); cVisual = rb_define_class_under(mX11, "Visual", rb_cObject); rb_define_singleton_method(cVisual, "new", vis_new, 2); rb_define_method(cVisual, "initialize", vis_init, 2); cColormap = rb_define_class_under(mX11, "Colormap", rb_cObject); rb_define_singleton_method(cColormap, "new", cmap_new, 0); rb_define_method(cColormap, "initialize", cmap_init, 0); cDrawable = rb_define_class_under(mX11, "Drawable", rb_cObject); rb_define_singleton_method(cDrawable, "new", drawable_new, 0); rb_define_method(cDrawable, "initialize", drawable_init, 0); cPixmap = rb_define_class_under(mX11, "Pixmap", rb_cObject); rb_define_singleton_method(cPixmap, "new", pmap_new, 0); rb_define_method(cPixmap, "initialize", pmap_init, 0); #endif /* !X_DISPLAY_MISSING */ /* fprintf(stderr, "DEBUG: Done Loading Imlib2.so.\n"); */ }