/* Method: Draw#draw(i) Purpose: Execute the stored drawing primitives on the current image image */ VALUE Draw_draw(VALUE self, VALUE image_arg) { Draw *draw; Image *image; image_arg = rm_cur_image(image_arg); image = rm_check_frozen(image_arg); Data_Get_Struct(self, Draw, draw); if (draw->primitives == 0) { rb_raise(rb_eArgError, "nothing to draw"); } // Point the DrawInfo structure at the current set of primitives. magick_clone_string(&(draw->info->primitive), StringValuePtr(draw->primitives)); (void) DrawImage(image, draw->info); rm_check_image_exception(image, RetainOnError); magick_free(draw->info->primitive); draw->info->primitive = NULL; return self; }
/** * Call MapImages. * * Ruby usage: * - @verbatim ImageList#map(reference) @endverbatim * - @verbatim ImageList#map(reference, dither) @endverbatim * * Notes: * - Default dither is false * - Sets \@scene to self.scene * * @param argc number of input arguments * @param argv array of input arguments * @param self this object * @return a new ImageList with mapped images. */ VALUE ImageList_map(int argc, VALUE *argv, VALUE self) { Image *images, *new_images = NULL; Image *map; unsigned int dither = MagickFalse; VALUE scene, new_imagelist, t; ExceptionInfo *exception; #if defined(HAVE_REMAPIMAGES) QuantizeInfo quantize_info; rb_warning("ImageList#map is deprecated. Use ImageList#remap instead."); #endif switch (argc) { case 2: dither = RTEST(argv[1]); case 1: t = rm_cur_image(argv[0]); map = rm_check_destroyed(t); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc); break; } // Convert image array to image sequence, clone image sequence. exception = AcquireExceptionInfo(); images = images_from_imagelist(self); new_images = CloneImageList(images, exception); rm_split(images); rm_check_exception(exception, new_images, DestroyOnError); (void) DestroyExceptionInfo(exception); rm_ensure_result(new_images); // Call ImageMagick #if defined(HAVE_REMAPIMAGES) GetQuantizeInfo(&quantize_info); quantize_info.dither = dither; (void) RemapImages(&quantize_info, new_images, map); #else (void) MapImages(new_images, map, dither); #endif rm_check_image_exception(new_images, DestroyOnError); // Set @scene in new ImageList object to same value as in self. new_imagelist = rm_imagelist_from_images(new_images); scene = rb_iv_get(self, "@scene"); (void) imagelist_scene_eq(new_imagelist, scene); RB_GC_GUARD(scene); RB_GC_GUARD(new_imagelist); RB_GC_GUARD(t); return new_imagelist; }
/* Method: ImageList#map(reference, dither=false) Purpose: Call MapImages Returns: a new ImageList with mapped images. @scene is set to self.scene */ VALUE ImageList_map(int argc, VALUE *argv, VALUE self) { Image *images, *new_images = NULL; Image *map; unsigned int dither = False; volatile VALUE scene, new_imagelist, t; ExceptionInfo exception; switch (argc) { case 2: dither = RTEST(argv[1]); case 1: t = ImageList_cur_image(argv[0]); map = rm_check_destroyed(t); break; default: rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc); break; } if (imagelist_length(self) == 0L) { rb_raise(rb_eArgError, "no images in this image list"); } // Convert image array to image sequence, clone image sequence. GetExceptionInfo(&exception); images = images_from_imagelist(self); new_images = CloneImageList(images, &exception); rm_split(images); rm_check_exception(&exception, new_images, DestroyOnError); (void) DestroyExceptionInfo(&exception); rm_ensure_result(new_images); // Call ImageMagick (void) MapImages(new_images, map, dither); rm_check_image_exception(new_images, DestroyOnError); // Set @scene in new ImageList object to same value as in self. new_imagelist = rm_imagelist_from_images(new_images); scene = rb_iv_get(self, "@scene"); (void) imagelist_scene_eq(new_imagelist, scene); return new_imagelist; }
/** * Call RemapImages. * * Ruby usage: * - @verbatim ImageList#remap @endverbatim * - @verbatim ImageList#remap(remap_image) @endverbatim * - @verbatim ImageList#remap(remap_image, dither_method) @endverbatim * * Notes: * - Default remap_image is nil * - Default dither_method is RiemersmaDitherMethod * - Modifies images in-place. * * @param argc number of input arguments * @param argv array of input arguments * @param self this object * @see Image_remap */ VALUE ImageList_remap(int argc, VALUE *argv, VALUE self) { #if defined(HAVE_REMAPIMAGES) || defined(HAVE_AFFINITYIMAGES) Image *images, *remap_image = NULL; QuantizeInfo quantize_info; if (argc > 0 && argv[0] != Qnil) { VALUE t = rm_cur_image(argv[0]); remap_image = rm_check_destroyed(t); RB_GC_GUARD(t); } GetQuantizeInfo(&quantize_info); if (argc > 1) { VALUE_TO_ENUM(argv[1], quantize_info.dither_method, DitherMethod); quantize_info.dither = MagickTrue; } if (argc > 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1 or 2)", argc); } images = images_from_imagelist(self); #if defined(HAVE_REMAPIMAGE) (void) RemapImages(&quantize_info, images, remap_image); #else (void) AffinityImages(&quantize_info, images, remap_image); #endif rm_check_image_exception(images, RetainOnError); rm_split(images); return self; #else self = self; argc = argc; argv = argv; rm_not_implemented(); return(VALUE)0; #endif }
/* Method: ImageList#display Purpose: Display all the images to an X window screen. */ VALUE ImageList_display(VALUE self) { Image *images; Info *info; volatile VALUE info_obj; // Create a new Info object to use with this call info_obj = rm_info_new(); Data_Get_Struct(info_obj, Info, info); // Convert the images array to an images sequence. images = images_from_imagelist(self); (void) DisplayImages(info, images); rm_split(images); rm_check_image_exception(images, RetainOnError); return self; }
VALUE ImageList_animate(int argc, VALUE *argv, VALUE self) { Image *images; Info *info; VALUE info_obj; if (argc > 1) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 or 1)", argc); } // Create a new Info object to use with this call info_obj = rm_info_new(); // Convert the images array to an images sequence. images = images_from_imagelist(self); if (argc == 1) { Image *img; unsigned int delay; delay = NUM2UINT(argv[0]); for (img = images; img; img = GetNextImageInList(img)) { img->delay = delay; } } Data_Get_Struct(info_obj, Info, info); (void) AnimateImages(info, images); rm_check_image_exception(images, RetainOnError); rm_split(images); RB_GC_GUARD(info_obj); return self; }
/** * Write all the images to the specified file. If the file format supports * multi-image files, and the 'images' array contains more than one image, then * the images will be written as a single multi-image file. Otherwise each image * will be written to a separate file. * * Ruby usage: * - @verbatim ImageList#write(file) @endverbatim * * @param self this object * @param file the file * @return self */ VALUE ImageList_write(VALUE self, VALUE file) { Image *images, *img; Info *info; const MagickInfo *m; VALUE info_obj; unsigned long scene; ExceptionInfo *exception; info_obj = rm_info_new(); Data_Get_Struct(info_obj, Info, info); if (TYPE(file) == T_FILE) { OpenFile *fptr; // Ensure file is open - raise error if not GetOpenFile(file, fptr); #if defined(_WIN32) add_format_prefix(info, fptr->pathv); SetImageInfoFile(info, NULL); #else SetImageInfoFile(info, GetReadFile(fptr)); #endif } else { add_format_prefix(info, file); SetImageInfoFile(info, NULL); } // Convert the images array to an images sequence. images = images_from_imagelist(self); // Copy the filename into each image. Set a scene number to be used if // writing multiple files. (Ref: ImageMagick's utilities/convert.c for (scene = 0, img = images; img; img = GetNextImageInList(img)) { img->scene = scene++; strcpy(img->filename, info->filename); } // Find out if the format supports multi-images files. exception = AcquireExceptionInfo(); (void) SetImageInfo(info, MagickTrue, exception); rm_check_exception(exception, images, RetainOnError); m = GetMagickInfo(info->magick, exception); rm_check_exception(exception, images, RetainOnError); (void) DestroyExceptionInfo(exception); // Tell WriteImage if we want a multi-images file. if (imagelist_length(self) > 1L && m->adjoin) { info->adjoin = MagickTrue; } for (img = images; img; img = GetNextImageInList(img)) { rm_sync_image_options(img, info); (void) WriteImage(info, img); // images will be split before raising an exception rm_check_image_exception(images, RetainOnError); if (info->adjoin) { break; } } rm_split(images); RB_GC_GUARD(info_obj); return self; }
/* Method: Draw#annotate(img, w, h, x, y, text) <{optional parms}> Purpose: annotates an image with text Returns: self Notes: Additional Draw attribute methods may be called in the optional block, which is executed in the context of an Draw object. */ VALUE Draw_annotate( VALUE self, VALUE image_arg, VALUE width_arg, VALUE height_arg, VALUE x_arg, VALUE y_arg, VALUE text) { Draw *draw; Image *image; unsigned long width, height; long x, y; AffineMatrix keep; char geometry_str[50]; // Save the affine matrix in case it is modified by // Draw#rotation= Data_Get_Struct(self, Draw, draw); keep = draw->info->affine; image_arg = rm_cur_image(image_arg); image = rm_check_frozen(image_arg); // If we have an optional parm block, run it in self's context, // allowing the app a chance to modify the object's attributes if (rb_block_given_p()) { (void)rb_obj_instance_eval(0, NULL, self); } // Translate & store in Draw structure #if defined(HAVE_INTERPRETIMAGEPROPERTIES) draw->info->text = InterpretImageProperties(NULL, image, StringValuePtr(text)); #else draw->info->text = InterpretImageAttributes(NULL, image, StringValuePtr(text)); #endif if (!draw->info->text) { rb_raise(rb_eArgError, "no text"); } // Create geometry string, copy to Draw structure, overriding // any previously existing value. width = NUM2ULONG(width_arg); height = NUM2ULONG(height_arg); x = NUM2LONG(x_arg); y = NUM2LONG(y_arg); if (width == 0 && height == 0) { sprintf(geometry_str, "%+ld%+ld", x, y); } // WxH is non-zero else { sprintf(geometry_str, "%lux%lu%+ld%+ld", width, height, x, y); } magick_clone_string(&draw->info->geometry, geometry_str); (void) AnnotateImage(image, draw->info); magick_free(draw->info->text); draw->info->text = NULL; draw->info->affine = keep; rm_check_image_exception(image, RetainOnError); return self; }
/* Method: ImageList#write(file) Purpose: Write all the images to the specified file. If the file format supports multi-image files, and the @images array contains more than one image, then the images will be written as a single multi-image file. Otherwise each image will be written to a separate file. Returns self. */ VALUE ImageList_write(VALUE self, VALUE file) { Image *images, *img; Info *info; const MagickInfo *m; volatile VALUE info_obj; char *filename; long filenameL; unsigned long scene; ExceptionInfo exception; info_obj = rm_info_new(); Data_Get_Struct(info_obj, Info, info); if (TYPE(file) == T_FILE) { OpenFile *fptr; // Ensure file is open - raise error if not GetOpenFile(file, fptr); SetImageInfoFile(info, GetReadFile(fptr)); } else { // Convert arg to string. Catch exceptions. file = rb_rescue(rb_String, file, file_arg_rescue, file); // Copy the filename to the Info and to the Image. filename = rb_str2cstr(file, &filenameL); filenameL = min(filenameL, MaxTextExtent-1); memcpy(info->filename, filename, (size_t)filenameL); info->filename[filenameL] = '\0'; SetImageInfoFile(info, NULL); } // Convert the images array to an images sequence. images = images_from_imagelist(self); // Copy the filename into each images. Set a scene number to be used if // writing multiple files. (Ref: ImageMagick's utilities/convert.c for (scene = 0, img = images; img; img = GetNextImageInList(img)) { img->scene = scene++; strcpy(img->filename, info->filename); } GetExceptionInfo(&exception); (void) SetImageInfo(info, MagickTrue, &exception); rm_check_exception(&exception, images, RetainOnError); (void) DestroyExceptionInfo(&exception); // Find out if the format supports multi-images files. GetExceptionInfo(&exception); m = GetMagickInfo(info->magick, &exception); rm_check_exception(&exception, images, RetainOnError); (void) DestroyExceptionInfo(&exception); // Tell WriteImage if we want a multi-images file. if (imagelist_length(self) > 1L && m->adjoin) { info->adjoin = MagickTrue; } for (img = images; img; img = GetNextImageInList(img)) { (void) WriteImage(info, img); // images will be split before raising an exception rm_check_image_exception(images, RetainOnError); if (info->adjoin) { break; } } rm_split(images); return self; }