Beispiel #1
0
/**
 * Apply fx on the images.
 *
 * Ruby usage:
 *   - @verbatim ImageList#fx(expression) @endverbatim
 *   - @verbatim ImageList#fx(expression, channel) @endverbatim
 *   - @verbatim ImageList#fx(expression, channel, ...) @endverbatim
 *
 * Notes:
 *   - Default channel is AllChannels
 *
 * @param argc number of input arguments
 * @param argv array of input arguments
 * @param self this object
 * @return a new image
 */
VALUE
ImageList_fx(int argc, VALUE *argv, VALUE self)
{
    Image *images, *new_image;
    char *expression;
    ChannelType channels;
    ExceptionInfo *exception;


    channels = extract_channels(&argc, argv);

    // There must be exactly 1 remaining argument.
    if (argc == 0)
    {
        rb_raise(rb_eArgError, "wrong number of arguments (0 for 1 or more)");
    }
    else if (argc > 1)
    {
        raise_ChannelType_error(argv[argc-1]);
    }

    expression = StringValuePtr(argv[0]);

    images = images_from_imagelist(self);
    exception = AcquireExceptionInfo();
    new_image = FxImageChannel(images, channels, expression, exception);
    rm_split(images);
    rm_check_exception(exception, new_image, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_image);

    return rm_image_new(new_image);
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
0
/**
 * Requires a minimum of two images. The first image is transformed into the
 * second by a number of intervening images as specified by "number_images".
 *
 * Ruby usage:
 *   - @verbatim ImageList#morph(number_images) @endverbatim
 *
 * Notes:
 *   - Sets \@scenes to 0
 *
 * @param self this object
 * @param nimages the number of images
 * @return a new image list with the images array set to the morph sequence.
 */
VALUE
ImageList_morph(VALUE self, VALUE nimages)
{
    Image *images, *new_images;
    ExceptionInfo *exception;
    long number_images;


    // Use a signed long so we can test for a negative argument.
    number_images = NUM2LONG(nimages);
    if (number_images <= 0)
    {
        rb_raise(rb_eArgError, "number of intervening images must be > 0");
    }

    exception = AcquireExceptionInfo();
    images = images_from_imagelist(self);
    new_images = MorphImages(images, (unsigned long)number_images, exception);
    rm_split(images);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_images);

    return rm_imagelist_from_images(new_images);
}
Beispiel #4
0
/*
    Method:     ImageList#composite_layers
    Purpose:    Equivalent to convert's -layers composite option
    Notes:      see mogrify.c
*/
VALUE
ImageList_composite_layers(int argc, VALUE *argv, VALUE self)
{
#if defined(HAVE_COMPOSITELAYERS)
    volatile VALUE source_images;
    Image *dest, *source, *new_images;
    RectangleInfo geometry;
    CompositeOperator operator = OverCompositeOp;
    ExceptionInfo exception;

    switch (argc)
    {
        case 2:
            VALUE_TO_ENUM(argv[1], operator, CompositeOperator);
        case 1:
            source_images = argv[0];
            break;
        default:
            rb_raise(rb_eArgError, "wrong number of arguments (expected 1 or 2, got %d)", argc);
            break;
    }

    // Convert ImageLists to image sequences.
    dest = images_from_imagelist(self);
    new_images = clone_imagelist(dest);
    rm_split(dest);

    source = images_from_imagelist(source_images);

    SetGeometry(new_images,&geometry);
    (void) ParseAbsoluteGeometry(new_images->geometry, &geometry);

    geometry.width  = source->page.width != 0 ? source->page.width : source->columns;
    geometry.height = source->page.height != 0 ? source->page.height : source->rows;
    GravityAdjustGeometry(new_images->page.width  != 0 ? new_images->page.width  : new_images->columns
                        , new_images->page.height != 0 ? new_images->page.height : new_images->rows
                        , new_images->gravity, &geometry);

    GetExceptionInfo(&exception);
    CompositeLayers(new_images, operator, source, geometry.x, geometry.y, &exception);
    rm_split(source);
    rm_check_exception(&exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(&exception);

    return rm_imagelist_from_images(new_images);

#else

    self = self;
    argc = argc;
    argv = argv;
    rm_not_implemented();
    return (VALUE)0;

#endif
}
Beispiel #5
0
/*
    Method:     ImageList#to_blob
    Purpose:    returns the imagelist as a blob (a String)
    Notes:      runs an info parm block if present - the user can
                specify the image format and depth
*/
VALUE
ImageList_to_blob(VALUE self)
{
    Image *images;
    Info *info;
    volatile VALUE info_obj;
    volatile VALUE blob_str;
    void *blob = NULL;
    size_t length = 0;
    ExceptionInfo exception;

    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);

    GetExceptionInfo(&exception);
    (void) SetImageInfo(info, MagickTrue, &exception);
    rm_check_exception(&exception, images, RetainOnError);

    if (*info->magick != '\0')
    {
        Image *img;
        for (img = images; img; img = GetNextImageInList(img))
        {
            strncpy(img->magick, info->magick, sizeof(info->magick)-1);
        }
    }

    // Unconditionally request multi-images support. The worst that
    // can happen is that there's only one image or the format
    // doesn't support multi-image files.
    info->adjoin = MagickTrue;
    blob = ImagesToBlob(info, images, &length, &exception);
    if (exception.severity != UndefinedException)
    {
        magick_free((void*)blob);
    }
    rm_split(images);
    CHECK_EXCEPTION()
    (void) DestroyExceptionInfo(&exception);


    if (length == 0 || !blob)
    {
        return Qnil;
    }

    blob_str = rb_str_new(blob, (long)length);
    magick_free((void*)blob);

    return blob_str;
}
Beispiel #6
0
/*
    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;
}
Beispiel #7
0
/**
 * Equivalent to convert's -layers composite option.
 *
 * Ruby usage:
 *   - @verbatim ImageList#composite_layers(images) @endverbatim
 *   - @verbatim ImageList#composite_layers(images,operator) @endverbatim
 *
 * Notes:
 *   - Default operator is OverCompositeOp
 *
 * @param argc number of input arguments
 * @param argv array of input arguments
 * @param self this object
 * @return a new imagelist
 * @see mogrify.c in ImageMagick
 */
VALUE
ImageList_composite_layers(int argc, VALUE *argv, VALUE self)
{
    VALUE source_images;
    Image *dest, *source, *new_images;
    RectangleInfo geometry;
    CompositeOperator operator = OverCompositeOp;
    ExceptionInfo *exception;

    switch (argc)
    {
        case 2:
            VALUE_TO_ENUM(argv[1], operator, CompositeOperator);
        case 1:
            source_images = argv[0];
            break;
        default:
            rb_raise(rb_eArgError, "wrong number of arguments (expected 1 or 2, got %d)", argc);
            break;
    }

    // Convert ImageLists to image sequences.
    dest = images_from_imagelist(self);
    new_images = clone_imagelist(dest);
    rm_split(dest);

    source = images_from_imagelist(source_images);

    SetGeometry(new_images,&geometry);
    (void) ParseAbsoluteGeometry(new_images->geometry, &geometry);

    geometry.width  = source->page.width != 0 ? source->page.width : source->columns;
    geometry.height = source->page.height != 0 ? source->page.height : source->rows;
    GravityAdjustGeometry(new_images->page.width  != 0 ? new_images->page.width  : new_images->columns
                        , new_images->page.height != 0 ? new_images->page.height : new_images->rows
                        , new_images->gravity, &geometry);

    exception = AcquireExceptionInfo();
    CompositeLayers(new_images, operator, source, geometry.x, geometry.y, exception);
    rm_split(source);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    RB_GC_GUARD(source_images);

    return rm_imagelist_from_images(new_images);
}
Beispiel #8
0
/**
 * Compare each image with the next in a sequence and returns the maximum
 * bounding region of any pixel differences it discovers.
 *
 * Ruby usage:
 *   - @verbatim ImageList#deconstruct @endverbatim
 *
 * @param self this object
 * @return a new imagelist
 */
VALUE
ImageList_deconstruct(VALUE self)
{
    Image *new_images, *images;
    ExceptionInfo *exception;

    images = images_from_imagelist(self);
    exception = AcquireExceptionInfo();
    new_images = DeconstructImages(images, exception);
    rm_split(images);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_images);

    return rm_imagelist_from_images(new_images);
}
Beispiel #9
0
/*
 *  Extern:     rm_clone_image
 *  Purpose:    clone an image, handle errors
 *  Notes:      don't trace creation - the clone may not be used as an Image
 *              object. Let the caller do the trace if desired.
 */
Image *
rm_clone_image(Image *image)
{
    Image *clone;
    ExceptionInfo exception;

    GetExceptionInfo(&exception);
    clone = CloneImage(image, 0, 0, MagickTrue, &exception);
    if (!clone)
    {
        rb_raise(rb_eNoMemError, "not enough memory to continue");
    }
    rm_check_exception(&exception, clone, DestroyOnError);
    (void) DestroyExceptionInfo(&exception);

    return clone;
}
Beispiel #10
0
/**
 * Call MontageImages.
 *
 * Ruby usage:
 *   - @verbatim ImageList#montage <{parm block}> @endverbatim
 *
 * Notes:
 *   - Creates Montage object, yields to block if present in Montage object's
 *     scope.
 *
 * @param self this object
 * @return a new image list
 */
VALUE
ImageList_montage(VALUE self)
{
    VALUE montage_obj;
    Montage *montage;
    Image *new_images, *images;
    ExceptionInfo *exception;

    // Create a new instance of the Magick::Montage class
    montage_obj = rm_montage_new();
    if (rb_block_given_p())
    {
        // Run the block in the instance's context, allowing the app to modify the
        // object's attributes.
        (void) rb_obj_instance_eval(0, NULL, montage_obj);
    }

    Data_Get_Struct(montage_obj, Montage, montage);

    images = images_from_imagelist(self);

    // If app specified a non-default composition operator, use it for all images.
    if (montage->compose != UndefinedCompositeOp)
    {
        Image *i;
        for (i = images; i; i = GetNextImageInList(i))
        {
            i->compose = montage->compose;
        }
    }

    exception = AcquireExceptionInfo();

    // MontageImage can return more than one image.
    new_images = MontageImages(images, montage->info, exception);
    rm_split(images);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_images);

    RB_GC_GUARD(montage_obj);

    return rm_imagelist_from_images(new_images);
}
Beispiel #11
0
/*
    Method:     ImageList#average
    Purpose:    Average all images together by calling AverageImages
    Returns:    an Frame object for the averaged image
*/
VALUE
ImageList_average(VALUE self)
{
    Image *images, *new_image;
    ExceptionInfo exception;

    // Convert the images array to an images sequence.
    images = images_from_imagelist(self);

    GetExceptionInfo(&exception);
    new_image = AverageImages(images, &exception);
    rm_split(images);
    rm_check_exception(&exception, new_image, DestroyOnError);
    (void) DestroyExceptionInfo(&exception);

    rm_ensure_result(new_image);

    return rm_image_new(new_image);
}
Beispiel #12
0
/**
 * Call CoalesceImages.
 *
 * Ruby usage:
 *   - @verbatim ImageList#coalesce @endverbatim
 *
 * Notes:
 *   - Respects the delay, matte, and start_loop fields in each image.
 *
 * @param self this object
 * @return a new Image with the coalesced image sequence return stored in the
 * images array
 */
VALUE
ImageList_coalesce(VALUE self)
{
    Image *images, *new_images;
    ExceptionInfo *exception;

    // Convert the image array to an image sequence.
    images = images_from_imagelist(self);

    exception = AcquireExceptionInfo();
    new_images = CoalesceImages(images, exception);
    rm_split(images);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_images);

    return rm_imagelist_from_images(new_images);
}
Beispiel #13
0
/**
 * Clone a list of images, handle errors.
 *
 * No Ruby usage (internal function)
 *
 * @param images the images
 * @return a new array of images
 */
static Image *
clone_imagelist(Image *images)
{
    Image *new_imagelist = NULL, *image, *clone;
    ExceptionInfo *exception;

    exception = AcquireExceptionInfo();

    image = GetFirstImageInList(images);
    while (image)
    {
        clone = CloneImage(image, 0, 0, MagickTrue, exception);
        rm_check_exception(exception, new_imagelist, DestroyOnError);
        AppendImageToList(&new_imagelist, clone);
        image = GetNextImageInList(image);
    }

    (void) DestroyExceptionInfo(exception);
    return new_imagelist;
}
Beispiel #14
0
/*
    Extern:     rm_check_image_exception
    Purpose:    If an ExceptionInfo struct in a list of images indicates a warning,
                issue a warning message. If an ExceptionInfo struct indicates an
                error, raise an exception and optionally destroy the images.
 */
void
rm_check_image_exception(Image *imglist, ErrorRetention retention)
{
    ExceptionInfo exception;
    Image *badboy = NULL;
    Image *image;

    if (imglist == NULL)
    {
        return;
    }

    GetExceptionInfo(&exception);

    // Find the image with the highest severity
    image = GetFirstImageInList(imglist);
    while (image)
    {
        if (image->exception.severity != UndefinedException)
        {
            if (!badboy || image->exception.severity > badboy->exception.severity)
            {
                badboy = image;
                InheritException(&exception, &badboy->exception);
            }

            ClearMagickException(&image->exception);
        }
        image = GetNextImageInList(image);
    }

    if (badboy)
    {
        rm_check_exception(&exception, imglist, retention);
    }

    (void) DestroyExceptionInfo(&exception);
}
Beispiel #15
0
/**
 * Merge all the images into a single image.
 *
 * Ruby usage:
 *   - @verbatim ImageList#mosaic @endverbatim
 *
 * @param self this object
 * @return the new image
 */
VALUE
ImageList_mosaic(VALUE self)
{
    Image *images, *new_image;
    ExceptionInfo *exception;

    exception = AcquireExceptionInfo();
    images = images_from_imagelist(self);

#if defined(HAVE_ENUM_MOSAICLAYER)
    new_image = MergeImageLayers(images, MosaicLayer, exception);
#else
    new_image = MosaicImages(images, exception);
#endif

    rm_split(images);
    rm_check_exception(exception, new_image, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_image);

    return rm_image_new(new_image);
}
Beispiel #16
0
/*
    Method:     ImageList#flatten_images
    Purpose:    merge all the images into a single image
    Returns:    the new image
    Notes:      Can't use "flatten" because that's an Array method
*/
VALUE
ImageList_flatten_images(VALUE self)
{
    Image *images, *new_image;
    ExceptionInfo exception;

    images = images_from_imagelist(self);
    GetExceptionInfo(&exception);

#if defined(HAVE_ENUM_FLATTENLAYER)
    new_image = MergeImageLayers(images, FlattenLayer, &exception);
#else
    new_image = FlattenImages(images, &exception);
#endif

    rm_split(images);
    rm_check_exception(&exception, new_image, DestroyOnError);
    (void) DestroyExceptionInfo(&exception);

    rm_ensure_result(new_image);

    return rm_image_new(new_image);
}
Beispiel #17
0
/**
 * Append all the images by calling ImageAppend.
 *
 * Ruby usage:
 *   - @verbatim ImageList#append(stack) @endverbatim
 *
 * @param self this object
 * @param stack_arg the stack of images
 * @return a Frame object for the result
 */
VALUE
ImageList_append(VALUE self, VALUE stack_arg)
{
    Image *images, *new_image;
    unsigned int stack;
    ExceptionInfo *exception;

    // Convert the image array to an image sequence.
    images = images_from_imagelist(self);

    // If stack == true, stack rectangular images top-to-bottom,
    // otherwise left-to-right.
    stack = RTEST(stack_arg);

    exception = AcquireExceptionInfo();
    new_image = AppendImages(images, stack, exception);
    rm_split(images);
    rm_check_exception(exception, new_image, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_image);

    return rm_image_new(new_image);
}
Beispiel #18
0
/**
 * Average all images together by calling AverageImages.
 *
 * Ruby usage:
 *   - @verbatim ImageList#average @endverbatim
 *
 * @param self this object
 * @return a Frame object for the averaged image
 */
VALUE
ImageList_average(VALUE self)
{
    Image *images, *new_image;
    ExceptionInfo *exception;

    // Convert the images array to an images sequence.
    images = images_from_imagelist(self);

    exception = AcquireExceptionInfo();
#if defined(HAVE_EVALUATEIMAGES)
    new_image = EvaluateImages(images, MeanEvaluateOperator, exception);
#else
    new_image = AverageImages(images, exception);
#endif

    rm_split(images);
    rm_check_exception(exception, new_image, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_image);

    return rm_image_new(new_image);
}
Beispiel #19
0
/**
 * Call QuantizeImages.
 *
 * Ruby usage:
 *   - @verbatim ImageList#quantize @endverbatim
 *   - @verbatim ImageList#quantize(number_colors) @endverbatim
 *   - @verbatim ImageList#quantize(number_colors, colorspace) @endverbatim
 *   - @verbatim ImageList#quantize(number_colors, colorspace, dither) @endverbatim
 *   - @verbatim ImageList#quantize(number_colors, colorspace, dither, tree_depth) @endverbatim
 *   - @verbatim ImageList#quantize(number_colors, colorspace, dither, tree_depth, measure_error) @endverbatim
 *
 * Notes:
 *   - Default number_colors is 256
 *   - Default coorspace is Magick::RGBColorsapce
 *   - Default dither is true
 *   - Default tree_depth is 0
 *   - Default measure_error is false
 *   - Sets \@scene to the same value as self.scene
 *
 * @param argc number of input arguments
 * @param argv array of input arguments
 * @param self this object
 * @return a new ImageList with quantized images
 */
VALUE
ImageList_quantize(int argc, VALUE *argv, VALUE self)
{
    Image *images, *new_images;
    Image *new_image;
    QuantizeInfo quantize_info;
    ExceptionInfo *exception;
    VALUE new_imagelist, scene;

    GetQuantizeInfo(&quantize_info);

    switch (argc)
    {
        case 5:
            quantize_info.measure_error = (MagickBooleanType) RTEST(argv[4]);
        case 4:
            quantize_info.tree_depth = (unsigned long)NUM2INT(argv[3]);
        case 3:
#if defined(HAVE_TYPE_DITHERMETHOD) && defined(HAVE_ENUM_NODITHERMETHOD)
            if (rb_obj_is_kind_of(argv[2], Class_DitherMethod))
            {
                VALUE_TO_ENUM(argv[2], quantize_info.dither_method, DitherMethod);
                quantize_info.dither = quantize_info.dither_method != NoDitherMethod;
            }
#else
            quantize_info.dither = (MagickBooleanType) RTEST(argv[2]);
#endif
        case 2:
            VALUE_TO_ENUM(argv[1], quantize_info.colorspace, ColorspaceType);
        case 1:
            quantize_info.number_colors = NUM2ULONG(argv[0]);
        case 0:
            break;
        default:
            rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 5)", 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);

    rm_ensure_result(new_images);


    (void) QuantizeImages(&quantize_info, new_images);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    // Create new ImageList object, convert mapped image sequence to images,
    // append to images array.
    new_imagelist = ImageList_new();
    while ((new_image = RemoveFirstImageFromList(&new_images)))
    {
        imagelist_push(new_imagelist, rm_image_new(new_image));
    }

    // Set @scene in new ImageList object to same value as in self.
    scene = rb_iv_get(self, "@scene");
    (void) rb_iv_set(new_imagelist, "@scene", scene);

    RB_GC_GUARD(new_imagelist);
    RB_GC_GUARD(scene);

    return new_imagelist;
}
Beispiel #20
0
/**
 * Equivalent to -layers option in ImageMagick 6.2.6.
 *
 * Ruby usage:
 *   - @verbatim ImageList#optimize_layers(method) @endverbatim
 *
 * @param self this object
 * @param method the method to use
 * @return a new imagelist
 */
VALUE
ImageList_optimize_layers(VALUE self, VALUE method)
{
    Image *images, *new_images, *new_images2;
    LAYERMETHODTYPE mthd;
    ExceptionInfo *exception;
    QuantizeInfo quantize_info;

    new_images2 = NULL;     // defeat "unused variable" message

    exception = AcquireExceptionInfo();
#if defined(HAVE_TYPE_IMAGELAYERMETHOD)
    VALUE_TO_ENUM(method, mthd, ImageLayerMethod);
#else
    VALUE_TO_ENUM(method, mthd, MagickLayerMethod);
#endif
    images = images_from_imagelist(self);

    switch (mthd)
    {
        case CoalesceLayer:
            new_images = CoalesceImages(images, exception);
            break;
        case DisposeLayer:
            new_images = DisposeImages(images, exception);
            break;
        case OptimizeTransLayer:
            new_images = clone_imagelist(images);
            OptimizeImageTransparency(new_images, exception);
            break;
        case RemoveDupsLayer:
            new_images = clone_imagelist(images);
            RemoveDuplicateLayers(&new_images, exception);
            break;
        case RemoveZeroLayer:
            new_images = clone_imagelist(images);
            RemoveZeroDelayLayers(&new_images, exception);
            break;
        case CompositeLayer:
            rm_split(images);
            rb_raise(rb_eNotImpError, "Magick::CompositeLayer is not supported. Use the composite_layers method instead.");
            break;
            // In 6.3.4-ish, OptimizeImageLayer replaced OptimizeLayer
        case OptimizeImageLayer:
            new_images = OptimizeImageLayers(images, exception);
            break;
            // and OptimizeLayer became a "General Purpose, GIF Animation Optimizer" (ref. mogrify.c)
        case OptimizeLayer:
            new_images = CoalesceImages(images, exception);
            rm_split(images);
            rm_check_exception(exception, new_images, DestroyOnError);
            new_images2 = OptimizeImageLayers(new_images, exception);
            DestroyImageList(new_images);
            rm_check_exception(exception, new_images2, DestroyOnError);
            new_images = new_images2;
            OptimizeImageTransparency(new_images, exception);
            rm_check_exception(exception, new_images, DestroyOnError);
            // mogrify supports -dither here. We don't.
#if defined(HAVE_REMAPIMAGE)
            GetQuantizeInfo(&quantize_info);
            (void) RemapImages(&quantize_info, new_images, NULL);
#else
            (void) MapImages(new_images, NULL, 0);
#endif
            break;
        case OptimizePlusLayer:
            new_images = OptimizePlusImageLayers(images, exception);
            break;
        case CompareAnyLayer:
        case CompareClearLayer:
        case CompareOverlayLayer:
            new_images = CompareImageLayers(images, mthd, exception);
            break;
#if defined(HAVE_ENUM_MOSAICLAYER)
        case MosaicLayer:
            new_images = MergeImageLayers(images, mthd, exception);
            break;
#endif
#if defined(HAVE_ENUM_FLATTENLAYER)
        case FlattenLayer:
            new_images = MergeImageLayers(images, mthd, exception);
            break;
#endif
#if defined(HAVE_ENUM_MERGELAYER)
        case MergeLayer:
            new_images = MergeImageLayers(images, mthd, exception);
            break;
#endif
#if defined(HAVE_ENUM_TRIMBOUNDSLAYER)
        case TrimBoundsLayer:
            new_images = MergeImageLayers(images, mthd, exception);
            break;
#endif
        default:
            rm_split(images);
            rb_raise(rb_eArgError, "undefined layer method");
            break;
    }

    rm_split(images);
    rm_check_exception(exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(exception);

    rm_ensure_result(new_images);

    return rm_imagelist_from_images(new_images);
}
Beispiel #21
0
/*
    Method:     ImageList#optimize_layers
    Purpose:    Equivalent to -layers option in 6.2.6
    Returns:    a new imagelist
*/
VALUE
ImageList_optimize_layers(VALUE self, VALUE method)
{
    Image *images, *new_images, *new_images2;
    LAYERMETHODTYPE mthd;
    ExceptionInfo exception;

    new_images2 = NULL;     // defeat "unused variable" message

    GetExceptionInfo(&exception);
#if defined(HAVE_TYPE_IMAGELAYERMETHOD)
    VALUE_TO_ENUM(method, mthd, ImageLayerMethod);
#else
    VALUE_TO_ENUM(method, mthd, MagickLayerMethod);
#endif
    images = images_from_imagelist(self);

    switch (mthd)
    {
        case CoalesceLayer:
            new_images = CoalesceImages(images, &exception);
            break;
        case DisposeLayer:
            new_images = DisposeImages(images, &exception);
            break;
#if defined(HAVE_ENUM_OPTIMIZETRANSLAYER)
        case OptimizeTransLayer:
            new_images = clone_imagelist(images);
            OptimizeImageTransparency(new_images, &exception);
            break;
#endif
#if defined(HAVE_ENUM_REMOVEDUPSLAYER)
        case RemoveDupsLayer:
            new_images = clone_imagelist(images);
            RemoveDuplicateLayers(&new_images, &exception);
            break;
#endif
#if defined(HAVE_ENUM_REMOVEZEROLAYER)
        case RemoveZeroLayer:
            new_images = clone_imagelist(images);
            RemoveZeroDelayLayers(&new_images, &exception);
            break;
#endif
#if defined(HAVE_ENUM_COMPOSITELAYER)
        case CompositeLayer:
            rb_raise(rb_eNotImpError, "Magick::CompositeLayer is not yet supported.");
            break;
#endif
#if defined(HAVE_ENUM_OPTIMIZEIMAGELAYER)
            // In 6.3.4-ish, OptimizeImageLayer replaced OptimizeLayer
        case OptimizeImageLayer:
            new_images = OptimizeImageLayers(images, &exception);
            break;
            // and OptimizeLayer became a "General Purpose, GIF Animation Optimizer" (ref. mogrify.c)
        case OptimizeLayer:
            new_images = CoalesceImages(images, &exception);
            rm_split(images);
            rm_check_exception(&exception, new_images, DestroyOnError);
            new_images2 = OptimizeImageLayers(new_images, &exception);
            DestroyImageList(new_images);
            rm_check_exception(&exception, new_images2, DestroyOnError);
            new_images = new_images2;
            OptimizeImageTransparency(new_images, &exception);
            rm_check_exception(&exception, new_images, DestroyOnError);
            // mogrify supports -dither here. We don't.
            (void) MapImages(new_images, NULL, 0);
            break;
#else
        case OptimizeLayer:
            new_images = OptimizeImageLayers(images, &exception);
            break;
#endif
        case OptimizePlusLayer:
            new_images = OptimizePlusImageLayers(images, &exception);
            break;
        case CompareAnyLayer:
        case CompareClearLayer:
        case CompareOverlayLayer:
            new_images = CompareImageLayers(images, mthd, &exception);
            break;
        default:
            rb_raise(rb_eArgError, "undefined layer method");
            break;
    }

    rm_split(images);
    rm_check_exception(&exception, new_images, DestroyOnError);
    (void) DestroyExceptionInfo(&exception);

    rm_ensure_result(new_images);

    return rm_imagelist_from_images(new_images);
}
Beispiel #22
0
/*
    Method:     ImageList#quantize(<number_colors<, colorspace<, dither<, tree_depth<, measure_error>>>>>)
                     defaults: 256, Magick::RGBColorspace, true, 0, false
    Purpose:    call QuantizeImages
    Returns:    a new ImageList with quantized images. 'scene' is set to the same
                value as self.scene
*/
VALUE
ImageList_quantize(int argc, VALUE *argv, VALUE self)
{
    Image *images, *new_images;
    Image *new_image;
    QuantizeInfo quantize_info;
    ExceptionInfo exception;
    volatile VALUE new_imagelist, scene;

    GetQuantizeInfo(&quantize_info);

    switch (argc)
    {
        case 5:
            quantize_info.measure_error = (MagickBooleanType) RTEST(argv[4]);
        case 4:
            quantize_info.tree_depth = (unsigned long)NUM2INT(argv[3]);
        case 3:
            quantize_info.dither = (MagickBooleanType) RTEST(argv[2]);
        case 2:
            VALUE_TO_ENUM(argv[1], quantize_info.colorspace, ColorspaceType);
        case 1:
            quantize_info.number_colors = NUM2ULONG(argv[0]);
        case 0:
            break;
        default:
            rb_raise(rb_eArgError, "wrong number of arguments (%d for 0 to 5)", 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);


    (void) QuantizeImages(&quantize_info, new_images);
    rm_check_exception(&exception, new_images, DestroyOnError);

    // Create new ImageList object, convert mapped image sequence to images,
    // append to images array.
    new_imagelist = ImageList_new();
    while ((new_image = ShiftImageList(&new_images)))
    {
        imagelist_push(new_imagelist, rm_image_new(new_image));
    }

    // Set @scene in new ImageList object to same value as in self.
    scene = rb_iv_get(self, "@scene");
    (void) rb_iv_set(new_imagelist, "@scene", scene);

    return new_imagelist;
}
Beispiel #23
0
/*
  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;
}
Beispiel #24
0
/**
 * 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;
}