/* 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: Draw#stroke_pattern= Purpose: Accept an image as a stroke pattern Notes: See also fill_pattern= */ VALUE Draw_stroke_pattern_eq(VALUE self, VALUE pattern) { Draw *draw; Image *image; rb_check_frozen(self); Data_Get_Struct(self, Draw, draw); if (draw->info->stroke_pattern != NULL) { // Do not trace destruction DestroyImage(draw->info->stroke_pattern); draw->info->stroke_pattern = NULL; } if (!NIL_P(pattern)) { // DestroyDrawInfo destroys the clone pattern = rm_cur_image(pattern); image = rm_check_destroyed(pattern); // Do not trace creation draw->info->stroke_pattern = rm_clone_image(image); } return self; }
/** * 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: Draw#composite(x,y,width,height,img,operator=OverCompositeOp) Purpose: Implement the "image" drawing primitive Notes: The "img" argument can be either an ImageList object or an Image argument. */ VALUE Draw_composite(int argc, VALUE *argv, VALUE self) { Draw *draw; const char *op = "Over"; double x, y, width, height; CompositeOperator cop = OverCompositeOp; volatile VALUE image; Image *comp_img; struct TmpFile_Name *tmpfile_name; char name[MaxTextExtent]; // Buffer for "image" primitive char primitive[MaxTextExtent]; if (argc < 5 || argc > 6) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 5 or 6)", argc); } // Retrieve the image to composite image = rm_cur_image(argv[4]); (void) rm_check_destroyed(image); x = NUM2DBL(argv[0]); y = NUM2DBL(argv[1]); width = NUM2DBL(argv[2]); height = NUM2DBL(argv[3]); // The default composition operator is "Over". if (argc == 6) { VALUE_TO_ENUM(argv[5], cop, CompositeOperator); switch (cop) { case AddCompositeOp: op = "Add"; break; case AtopCompositeOp: op = "Atop"; break; case BumpmapCompositeOp: op = "Bumpmap"; break; case ClearCompositeOp: op = "Clear"; break; case CopyBlueCompositeOp: op = "CopyBlue"; break; case CopyGreenCompositeOp: op = "CopyGreen"; break; case CopyOpacityCompositeOp: op = "CopyOpacity"; break; case CopyRedCompositeOp: op = "CopyRed"; break; case CopyCompositeOp: op = "Copy"; break; case DifferenceCompositeOp: op = "Difference"; break; case InCompositeOp: op = "In"; break; case MinusCompositeOp: op = "Minus"; break; case MultiplyCompositeOp: op = "Multiply"; break; case OutCompositeOp: op = "Out"; break; case OverCompositeOp: op = "Over"; break; case PlusCompositeOp: op = "Plus"; break; case SubtractCompositeOp: op = "Subtract"; break; case XorCompositeOp: op = "Xor"; break; default: rb_raise(rb_eArgError, "unknown composite operator (%d)", cop); break; } } Data_Get_Struct(self, Draw, draw); // Create a temp copy of the composite image Data_Get_Struct(image, Image, comp_img); rm_write_temp_image(comp_img, name); // Add the temp filename to the filename array. // Use Magick storage since we need to keep the list around // until destroy_Draw is called. tmpfile_name = magick_malloc(sizeof(struct TmpFile_Name)+strlen(name)); strcpy(tmpfile_name->name, name); tmpfile_name->next = draw->tmpfile_ary; draw->tmpfile_ary = tmpfile_name; // Form the drawing primitive (void) sprintf(primitive, "image %s %g,%g,%g,%g '%s'", op, x, y, width, height, name); // Send "primitive" to self. (void) rb_funcall(self, rb_intern("primitive"), 1, rb_str_new2(primitive)); 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; }
/** * Implement the "image" drawing primitive. * * Ruby usage: * - @verbatim Draw#composite(x,y,width,height,img) @endverbatim * - @verbatim Draw#composite(x,y,width,height,img,operator) @endverbatim * * Notes: * - Default operator is overComposite * - The "img" argument can be either an ImageList object or an Image * argument. * * @param argc number of input arguments * @param argv array of input arguments * @param self this object * @return self */ VALUE Draw_composite(int argc, VALUE *argv, VALUE self) { Draw *draw; const char *op; double x, y, width, height; CompositeOperator cop; VALUE image; Image *comp_img; struct TmpFile_Name *tmpfile_name; char name[MaxTextExtent]; // Buffer for "image" primitive char primitive[MaxTextExtent]; if (argc < 5 || argc > 6) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 5 or 6)", argc); } // Retrieve the image to composite image = rm_cur_image(argv[4]); comp_img = rm_check_destroyed(image); x = NUM2DBL(argv[0]); y = NUM2DBL(argv[1]); width = NUM2DBL(argv[2]); height = NUM2DBL(argv[3]); cop = OverCompositeOp; if (argc == 6) { VALUE_TO_ENUM(argv[5], cop, CompositeOperator); } op = CommandOptionToMnemonic(MagickComposeOptions, cop); if (rm_strcasecmp("Unrecognized", op) == 0) { rb_raise(rb_eArgError, "unknown composite operator (%d)", cop); } Data_Get_Struct(self, Draw, draw); // Create a temp copy of the composite image rm_write_temp_image(comp_img, name); // Add the temp filename to the filename array. // Use Magick storage since we need to keep the list around // until destroy_Draw is called. tmpfile_name = magick_malloc(sizeof(struct TmpFile_Name)+strlen(name)); strcpy(tmpfile_name->name, name); tmpfile_name->next = draw->tmpfile_ary; draw->tmpfile_ary = tmpfile_name; // Form the drawing primitive (void) snprintf(primitive, sizeof(primitive), "image %s %g,%g,%g,%g '%s'", op, x, y, width, height, name); // Send "primitive" to self. (void) rb_funcall(self, rb_intern("primitive"), 1, rb_str_new2(primitive)); RB_GC_GUARD(image); return self; }