/dmagick/Image.d
http://github.com/MikeWey/DMagick · D · 4492 lines · 2101 code · 547 blank · 1844 comment · 125 complexity · 04d00e165654ff064104a41ec065a457 MD5 · raw file
Large files are truncated click here to view the full file
- /**
- * Copyright: Mike Wey 2011
- * License: zlib (See accompanying LICENSE file)
- * Authors: Mike Wey
- */
- module dmagick.Image;
- import std.algorithm : min;
- import std.array;
- import std.conv;
- import std.math;
- import std.string;
- import std.typecons : Tuple;
- import std.uni;
- import core.memory;
- import core.runtime;
- import core.time;
- import core.stdc.string;
- import dmagick.Color;
- import dmagick.Exception;
- import dmagick.Geometry;
- import dmagick.ImageView;
- import dmagick.Options;
- import dmagick.Utils;
- version(DMagick_No_Display)
- {
- }
- else
- {
- version(Windows) import dmagick.internal.Windows;
- }
- //Import all translated c headers.
- import dmagick.c.MagickCore;
- /// See_Also: $(CXREF geometry, _AffineMatrix)
- public alias dmagick.c.geometry.AffineMatrix AffineMatrix;
- /// See_Also: $(CXREF image, _AlphaChannelType)
- public alias dmagick.c.image.AlphaChannelType AlphaChannelType;
- /// See_Also: $(CXREF magickType, _ChannelType)
- public alias dmagick.c.magickType.ChannelType ChannelType;
- /// See_Also: $(CXREF image, _ChromaticityInfo)
- public alias dmagick.c.image.ChromaticityInfo ChromaticityInfo;
- /// See_Also: $(CXREF magickType, _ClassType)
- public alias dmagick.c.magickType.ClassType ClassType;
- /// See_Also: $(CXREF colorspace, _ColorspaceType)
- public alias dmagick.c.colorspace.ColorspaceType ColorspaceType;
- /// See_Also: $(CXREF composite, _CompositeOperator)
- public alias dmagick.c.composite.CompositeOperator CompositeOperator;
- /// See_Also: $(CXREF compress, _CompressionType)
- public alias dmagick.c.compress.CompressionType CompressionType;
- /// See_Also: $(CXREF layer, _DisposeType)
- public alias dmagick.c.layer.DisposeType DisposeType;
- /// See_Also: $(CXREF distort, _DistortImageMethod)
- public alias dmagick.c.distort.DistortImageMethod DistortImageMethod;
- /// See_Also: $(CXREF quantum, _EndianType)
- public alias dmagick.c.quantum.EndianType EndianType;
- /// See_Also: $(CXREF resample, _FilterTypes)
- public alias dmagick.c.resample.FilterTypes FilterTypes;
- /// See_Also: $(CXREF geometry, _GravityType)
- public alias dmagick.c.geometry.GravityType GravityType;
- /// See_Also: $(CXREF image, _ImageType)
- public alias dmagick.c.image.ImageType ImageType;
- /// See_Also: $(CXREF image, _InterlaceType)
- public alias dmagick.c.image.InterlaceType InterlaceType;
- /// See_Also: $(CXREF pixel, _InterpolatePixelMethod)
- public alias dmagick.c.pixel.InterpolatePixelMethod InterpolatePixelMethod;
- /// See_Also: $(CXREF statistic, _MagickEvaluateOperator)
- public alias dmagick.c.statistic.MagickEvaluateOperator MagickEvaluateOperator;
- /// See_Also: $(CXREF statistic, _MagickFunction)
- public alias dmagick.c.statistic.MagickFunction MagickFunction;
- /// See_Also: $(CXREF fx, _NoiseType)
- public alias dmagick.c.fx.NoiseType NoiseType;
- /// See_Also: $(CXREF image, _OrientationType)
- public alias dmagick.c.image.OrientationType OrientationType;
- /// See_Also: $(CXREF effect, _PreviewType)
- public alias dmagick.c.effect.PreviewType PreviewType;
- /// See_Also: $(CXREF magickType, _Quantum)
- public alias dmagick.c.magickType.Quantum Quantum;
- /// See_Also: $(CXREF profile, _RenderingIntent)
- public alias dmagick.c.profile.RenderingIntent RenderingIntent;
- /// See_Also: $(CXREF image, _ResolutionType)
- public alias dmagick.c.image.ResolutionType ResolutionType;
- /// See_Also: $(CXREF distort, _SparseColorMethod)
- public alias dmagick.c.distort.SparseColorMethod SparseColorMethod;
- /// See_Also: $(CXREF effect, _StatisticType)
- public alias dmagick.c.statistic.StatisticType StatisticType;
- /// See_Also: $(CXREF constitute, _StorageType)
- public alias dmagick.c.constitute.StorageType StorageType;
- /// See_Also: $(CXREF draw, _TypeMetric)
- public alias dmagick.c.draw.TypeMetric TypeMetric;
- /// See_Also: $(CXREF cacheView, _VirtualPixelMethod)
- public alias dmagick.c.cacheView.VirtualPixelMethod VirtualPixelMethod;
- alias ptrdiff_t ssize_t;
- /**
- * The image
- */
- class Image
- {
- alias dmagick.c.image.Image MagickCoreImage;
- alias RefCounted!( DestroyImage, MagickCoreImage ) ImageRef;
- ImageRef imageRef;
- Options options; ///The options for this image.
- private bool delegate(string, long, ulong) progressMonitor;
-
- ///
- this()
- {
- options = new Options();
- imageRef = ImageRef(AcquireImage(options.imageInfo));
- }
- this(MagickCoreImage* image, Options options = null)
- {
- this(ImageRef(image), options);
- }
- this(ImageRef image, Options options = null)
- {
- if ( options is null )
- this.options = new Options();
- else
- this.options = options;
- imageRef = image;
- }
- /**
- * Construct an Image by reading from the file or
- * URL specified by filename.
- */
- this(string filename)
- {
- options = new Options();
- read(filename);
- }
- /**
- * Construct a blank image with the specified color.
- */
- this(Geometry size, Color color)
- {
- options = new Options();
- options.size = size;
- //Use read to create a cnavas with the spacified color.
- read( "canvas:"~ color.toString() );
- }
- /**
- * Construct an image from an in-memory blob.
- * The Blob size, depth and magick format may also be specified.
- *
- * Some image formats require size to be specified,
- * the default depth Imagemagick uses is the Quantum size
- * it's compiled with. If it doesn't match the depth of the image
- * it may need to be specified.
- *
- * Imagemagick can usualy detect the image format, when the
- * format can't be detected a magick format must be specified.
- */
- this(void[] blob)
- {
- options = new Options();
- read(blob);
- }
- ///ditto
- this(void[] blob, Geometry size)
- {
- options = new Options();
- read(blob, size);
- }
- ///ditto
- this(void[] blob, Geometry size, size_t depth)
- {
- options = new Options();
- read(blob, size, depth);
- }
- ///ditto
- this(void[] blob, Geometry size, size_t depth, string magick)
- {
- options = new Options();
- read(blob, size, depth, magick);
- }
-
- ///ditto
- this(void[] blob, Geometry size, string magick)
- {
- options = new Options();
- read(blob, size, magick);
- }
- /**
- * Constructs an image from an array of pixels.
- *
- * Params:
- * columns = The number of columns in the image.
- * rows = The number of rows in the image.
- * map = A string describing the expected ordering
- * of the pixel array. It can be any combination
- * or order of R = red, G = green, B = blue, A = alpha
- * , C = cyan, Y = yellow, M = magenta, K = black,
- * or I = intensity (for grayscale).
- * storage = The pixel Staroage type (CharPixel,
- * ShortPixel, IntegerPixel, FloatPixel, or DoublePixel).
- * pixels = The pixel data.
- */
- this(size_t columns, size_t rows, string map, StorageType storage, void[] pixels)
- {
- options = new Options();
- MagickCoreImage* image =
- ConstituteImage(columns, rows, toStringz(map), storage, pixels.ptr, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Constructs a description of the image as a string.
- * The string contains some or all of the following fields:
- * $(LIST
- * $(B filename) The current filename.,
- * $(B [scene]) The scene number if the image is part of a secuence.,
- * $(B format) The image format.,
- * $(B width x height),
- * $(B page width x height + xOffset + yOffset),
- * $(B classType) DirectClass or PseudoClass,
- * $(B N-bit) bit depth.,
- * $(B blob size) if present.
- * )
- */
- override string toString()
- {
- string result;
- result = filename;
- //Scene number.
- ssize_t index = GetImageIndexInList(imageRef);
- if ( index > 0 )
- {
- result ~= std.string.format("[%s]", index);
- }
- result ~= std.string.format(" %s ", format);
- result ~= std.string.format("%sx%s ", columns, rows);
- //Page size
- if ( imageRef.page.width > 0 || imageRef.page.height > 0
- || imageRef.page.x != 0 || imageRef.page.y != 0 )
- {
- result ~= std.string.format("%sx%s%+s%+s ",
- imageRef.page.width, imageRef.page.height,
- imageRef.page.x, imageRef.page.y);
- }
- if ( classType == ClassType.DirectClass )
- result ~= "DirectClass ";
- else
- result ~= "PseudoClass ";
- result ~= std.string.format("%s-bit ", GetImageQuantumDepth(imageRef, true));
- //Size of the image.
- MagickSizeType size = GetBlobSize(imageRef);
- if ( size > 0 )
- {
- if ( size > 2*1024*1024 )
- result ~= std.string.format("%s MiB", size/1024/1024);
- else if ( size > 2*1024 )
- result ~= std.string.format("%s KiB", size/1024);
- else
- result ~= std.string.format("%s bytes", size);
- }
- return result;
- }
- /**
- * Adaptively blurs the image by blurring more intensely near
- * image edges and less intensely far from edges.
- * The adaptiveBlur method blurs the image with a Gaussian operator
- * of the given radius and standard deviation (sigma).
- * For reasonable results, radius should be larger than sigma.
- * Use a radius of 0 and adaptiveBlur selects a suitable radius for you.
- *
- * Params:
- * radius = The radius of the Gaussian in pixels,
- * not counting the center pixel.
- * sigma = The standard deviation of the Laplacian, in pixels.
- * channel = The channels to blur.
- */
- void adaptiveBlur(double radius = 0, double sigma = 1, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- AdaptiveBlurImageChannel(imageRef, channel, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * adaptiveResize uses the special Mesh Interpolation method
- * to resize images. Basically adaptiveResize avoids the excessive
- * blurring that resize can produce with sharp color changes.
- * This works well for slight image size adjustments and in
- * particularly for magnification, And especially with images
- * with sharp color changes. But when images are enlarged or reduced
- * by more than 50% it will start to produce aliasing,
- * and Moiré effects in the results.
- */
- void adaptiveResize(Geometry size)
- {
- size = size.toAbsolute(columns, rows);
- MagickCoreImage* image =
- AdaptiveResizeImage(imageRef, size.width, size.height, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Adaptively sharpens the image by sharpening more intensely near
- * image edges and less intensely far from edges. The adaptiveSharpen
- * method sharpens the image with a Gaussian operator of the given
- * radius and standard deviation (sigma). For reasonable results,
- * radius should be larger than sigma. Use a radius of 0 and
- * adaptiveSharpen selects a suitable radius for you.
- *
- * Params:
- * radius = The radius of the Gaussian in pixels,
- * not counting the center pixel.
- * sigma = The standard deviation of the Laplacian, in pixels.
- * channel = If no channels are specified, sharpens all the channels.
- */
- void adaptiveSharpen(double radius = 0, double sigma = 1, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- AdaptiveSharpenImageChannel(imageRef, channel, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Selects an individual threshold for each pixel based on the range
- * of intensity values in its local neighborhood. This allows for
- * thresholding of an image whose global intensity histogram doesn't
- * contain distinctive peaks.
- *
- * Params:
- * width = define the width of the local neighborhood.
- * heigth = define the height of the local neighborhood.
- * offset = constant to subtract from pixel neighborhood mean.
- */
- void adaptiveThreshold(size_t width = 3, size_t height = 3, ssize_t offset = 0)
- {
- MagickCoreImage* image =
- AdaptiveThresholdImage(imageRef, width, height, offset, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Adds random noise to the specified channel or channels in the image.
- * The amount of time addNoise requires depends on the NoiseType argument.
- *
- * Params:
- * type = A NoiseType value.
- * channel = 0 or more ChannelType arguments. If no channels are
- * specified, adds noise to all the channels
- */
- void addNoise(NoiseType type, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- AddNoiseImageChannel(imageRef, channel, type, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Transforms the image as specified by the affine matrix.
- */
- void affineTransform(AffineMatrix affine)
- {
- MagickCoreImage* image =
- AffineTransformImage(imageRef, &affine, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Annotates an image with text. Optionally you can include any
- * of the following bits of information about the image by embedding
- * the appropriate special characters:
- * --------------------
- * %b file size in bytes.
- * %c comment.
- * %d directory in which the image resides.
- * %e extension of the image file.
- * %f original filename of the image.
- * %h height of image.
- * %i filename of the image.
- * %k number of unique colors.
- * %l image label.
- * %m image file format.
- * %n number of images in a image sequence.
- * %o output image filename.
- * %p page number of the image.
- * %q image depth (8 or 16).
- * %q image depth (8 or 16).
- * %s image scene number.
- * %t image filename without any extension.
- * %u a unique temporary filename.
- * %w image width.
- * %x x resolution of the image.
- * %y y resolution of the image.
- *--------------------
- * Params:
- * text = The text.
- * xOffset = The x coordinate.
- * yOffset = The y coordinate.
- * gravity = Placement gravity.
- * degrees = The angle of the Text.
- */
- void annotate(
- string text,
- size_t xOffset,
- size_t yOffset,
- GravityType gravity = GravityType.NorthWestGravity,
- double degrees = 0.0)
- {
- annotate(text, Geometry(size_t.max, size_t.max, xOffset, yOffset), gravity, degrees);
- }
- /**
- * Ditto, but word wraps the text so it stays withing the
- * boundingArea. if the height and width are 0 the height and
- * with of the image are used to calculate the bounding area.
- */
- void annotate(
- string text,
- Geometry boundingArea = Geometry.init,
- GravityType gravity = GravityType.NorthWestGravity,
- double degrees = 0.0)
- {
- if ( boundingArea.width == 0 )
- boundingArea.width = columns;
- if ( boundingArea.height == 0 )
- boundingArea.height = rows;
- if ( boundingArea.width > 0 )
- text = wordWrap(text, boundingArea);
- DrawInfo* drawInfo = options.drawInfo;
- AffineMatrix oldAffine = options.affine;
- copyString(drawInfo.text, text);
- copyString(drawInfo.geometry, boundingArea.toString());
- drawInfo.gravity = gravity;
- options.transformRotation(degrees);
- scope(exit)
- {
- copyString(drawInfo.text, null);
- copyString(drawInfo.geometry, null);
- drawInfo.gravity = GravityType.NorthWestGravity;
- options.affine = oldAffine;
- }
- AnnotateImage(imageRef, drawInfo);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * extract the 'mean' from the image and adjust the image
- * to try make set its gamma appropriatally.
- *
- * Params:
- * channel = One or more channels to adjust.
- */
- void autoGamma(ChannelType channel = ChannelType.DefaultChannels)
- {
- AutoGammaImageChannel(imageRef, channel);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * adjusts the levels of a particular image channel by scaling
- * the minimum and maximum values to the full quantum range.
- *
- * Params:
- * channel = One or more channels to adjust.
- */
- void autoLevel(ChannelType channel = ChannelType.DefaultChannels)
- {
- AutoLevelImageChannel(imageRef, channel);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Adjusts an image so that its orientation is suitable for viewing
- * (i.e. top-left orientation). Note that only some models of modern
- * digital cameras can tag an image with the orientation.
- */
- void autoOrient()
- {
- final switch( this.orientation )
- {
- case OrientationType.UndefinedOrientation:
- case OrientationType.TopLeftOrientation:
- return;
- case OrientationType.TopRightOrientation:
- flop();
- break;
- case OrientationType.BottomRightOrientation:
- rotate(180);
- break;
- case OrientationType.BottomLeftOrientation:
- flip();
- break;
- case OrientationType.LeftTopOrientation:
- transpose();
- break;
- case OrientationType.RightTopOrientation:
- rotate(90);
- break;
- case OrientationType.RightBottomOrientation:
- transverse();
- break;
- case OrientationType.LeftBottomOrientation:
- rotate(270);
- break;
- }
- orientation = OrientationType.TopLeftOrientation;
- }
- /**
- * Changes the value of individual pixels based on the intensity
- * of each pixel channel. The result is a high-contrast image.
- *
- * More precisely each channel value of the image is 'thresholded'
- * so that if it is equal to or less than the given value it is set
- * to zero, while any value greater than that give is set to it
- * maximum or QuantumRange.
- *
- * Params:
- * threshold = The threshold value.
- * channel = One or more channels to adjust.
- */
- void bilevel(Quantum threshold, ChannelType channel = ChannelType.DefaultChannels)
- {
- BilevelImageChannel(imageRef, channel, threshold);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Forces all pixels below the threshold into black while leaving
- * all pixels above the threshold unchanged.
- *
- * Params:
- * threshold = The threshold value for red green and blue.
- * channel = One or more channels to adjust.
- */
- void blackThreshold(Quantum threshold, ChannelType channel = ChannelType.DefaultChannels)
- {
- blackThreshold(threshold, threshold, threshold, 0, channel);
- }
- ///ditto
- void blackThreshold(
- Quantum red,
- Quantum green,
- Quantum blue,
- Quantum opacity = 0,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- string thresholds = std.string.format("%s,%s,%s,%s", red, green, blue, opacity);
- BlackThresholdImageChannel(
- imageRef, channel, toStringz(thresholds), DMagickExceptionInfo()
- );
- }
- /**
- * Adds the overlay image to the target image according to
- * srcPercent and dstPercent.
- *
- * This method corresponds to the -blend option of ImageMagick's
- * composite command.
- *
- * Params:
- * overlay = The source image for the composite operation.
- * srcPercentage = Percentage for the source image.
- * dstPercentage = Percentage for this image.
- * xOffset = The x offset to use for the overlay.
- * yOffset = The y offset to use for the overlay.
- * gravity = The gravity to use for the overlay.
- */
- void blend(
- const(Image) overlay,
- int srcPercentage,
- int dstPercentage,
- ssize_t xOffset,
- ssize_t yOffset)
- {
- SetImageArtifact(imageRef, "compose:args",
- toStringz(std.string.format("%s,%s", srcPercentage, dstPercentage)));
- scope(exit) RemoveImageArtifact(imageRef, "compose:args");
- composite(overlay, CompositeOperator.BlendCompositeOp, xOffset, yOffset);
- }
- ///ditto
- void blend(
- const(Image) overlay,
- int srcPercentage,
- int dstPercentage,
- GravityType gravity = GravityType.NorthWestGravity)
- {
- RectangleInfo geometry;
- SetGeometry(overlay.imageRef, &geometry);
- GravityAdjustGeometry(columns, rows, gravity, &geometry);
- blend(overlay, srcPercentage, dstPercentage, geometry.x, geometry.y);
- }
- /**
- * mutes the colors of the image to simulate a scene at
- * nighttime in the moonlight.
- *
- * Params:
- * factor = The shift factor, larger values increase the effect.
- */
- void blueShift(double factor = 1.5)
- {
- MagickCoreImage* image =
- BlueShiftImage(imageRef, factor, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Blurs the specified channel. We convolve the image with a Gaussian
- * operator of the given radius and standard deviation (sigma).
- * The blur method differs from gaussianBlur in that it uses a
- * separable kernel which is faster but mathematically equivalent
- * to the non-separable kernel.
- *
- * Params:
- * radius = The radius of the Gaussian in pixels,
- * not counting the center pixel.
- * sigma = The standard deviation of the Laplacian, in pixels.
- * channel = The channels to blur.
- */
- void blur(double radius = 0, double sigma = 1, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- BlurImageChannel(imageRef, channel, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Surrounds the image with a border of the color defined
- * by the borderColor property.
- *
- * Params:
- * width = Border width in pixels.
- * height = Border height in pixels.
- */
- void border(size_t width, size_t height)
- {
- RectangleInfo borderInfo = RectangleInfo(width, height);
- MagickCoreImage* image =
- BorderImage(imageRef, &borderInfo, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Extract channel from image. Use this option to extract a
- * particular channel from the image. ChannelType.MatteChannel for
- * example, is useful for extracting the opacity values from an image.
- */
- Image channel(ChannelType channel) const
- {
- MagickCoreImage* image =
- SeparateImages(imageRef, channel, DMagickExceptionInfo());
- return new Image(image);
- }
- /**
- * Adds a "charcoal" effect to the image. You can alter the
- * intensity of the effect by changing the radius and sigma arguments.
- *
- * Params:
- * radius = The radius of the pixel neighborhood.
- * sigma = The standard deviation of the Gaussian, in pixels.
- */
- void charcoal(double radius = 0, double sigma = 1)
- {
- MagickCoreImage* image =
- CharcoalImage(imageRef, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Removes the specified rectangle and collapses the rest of
- * the image to fill the removed portion.
- *
- * Params:
- * geometry = The horizontal and/or vertical subregion to remove.
- */
- void chop(Geometry geometry)
- {
- RectangleInfo rectangle = geometry.rectangleInfo;
- MagickCoreImage* image =
- ChopImage(imageRef, &rectangle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Returns a copy of the image.
- */
- Image clone() const
- {
- MagickCoreImage* image =
- CloneImage(imageRef, 0, 0, true, DMagickExceptionInfo());
- return new Image(image, options.clone());
- }
- /**
- * replaces each color value in the given image, by using it as an
- * index to lookup a replacement color value in a Color Look UP Table
- * in the form of an image. The values are extracted along a diagonal
- * of the CLUT image so either a horizontal or vertial gradient image
- * can be used.
- *
- * Typically this is used to either re-color a gray-scale image
- * according to a color gradient in the CLUT image, or to perform a
- * freeform histogram (level) adjustment according to the (typically
- * gray-scale) gradient in the CLUT image.
- *
- * When the 'channel' mask includes the matte/alpha transparency
- * channel but one image has no such channel it is assumed that that
- * image is a simple gray-scale image that will effect the alpha channel
- * values, either for gray-scale coloring (with transparent or
- * semi-transparent colors), or a histogram adjustment of existing alpha
- * channel values. If both images have matte channels, direct and normal
- * indexing is applied, which is rarely used.
- *
- * Params:
- * clutImage = the color lookup table image for replacement
- * color values.
- * channel = One or more channels to adjust.
- */
- void clut(Image clutImage, ChannelType channel = ChannelType.DefaultChannels)
- {
- ClutImageChannel(imageRef, channel, clutImage.imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Applies a lightweight Color Correction Collection (CCC) file
- * to the image. The file solely contains one or more color corrections.
- * Here is a sample:
- * --------------------
- * <ColorCorrectionCollection xmlns="urn:ASC:CDL:v1.2">
- * <ColorCorrection id="cc03345">
- * <SOPNode>
- * <Slope> 0.9 1.2 0.5 </Slope>
- * <Offset> 0.4 -0.5 0.6 </Offset>
- * <Power> 1.0 0.8 1.5 </Power>
- * </SOPNode>
- * <SATNode>
- * <Saturation> 0.85 </Saturation>
- * </SATNode>
- * </ColorCorrection>
- * </ColorCorrectionCollection>
- * --------------------
- * which includes the slop, offset, and power for each of
- * the RGB channels as well as the saturation.
- *
- * See_Also: $(LINK2 http://en.wikipedia.org/wiki/ASC_CDL,
- * Wikipedia ASC CDL).
- */
- void colorDecisionList(string colorCorrectionCollection)
- {
- ColorDecisionListImage(imageRef, toStringz(colorCorrectionCollection));
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Blend the fill color with the image pixels. The opacityRed,
- * opacityGreen, opacityBlue and opacityAlpha arguments are the
- * percentage to blend with the red, green, blue and alpha channels.
- */
- void colorize(Color fill, uint opacityRed, uint opacityGreen, uint opacityBlue, uint opacityAlpha = 0)
- {
- string opacity = std.string.format("%s/%s/%s/%s",
- opacityRed, opacityGreen, opacityBlue, opacityAlpha);
- MagickCoreImage* image =
- ColorizeImage(imageRef, toStringz(opacity), fill.pixelPacket, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Applies color transformation to an image. This method permits
- * saturation changes, hue rotation, luminance to alpha, and various
- * other effects. Although variable-sized transformation matrices can
- * be used, typically one uses a 5x5 matrix for an RGBA image and a 6x6
- * for CMYKA (or RGBA with offsets). The matrix is similar to those
- * used by Adobe Flash except offsets are in column 6 rather than 5
- * (in support of CMYKA images) and offsets are normalized
- * (divide Flash offset by 255)
- *
- * Params:
- * matrix = A tranformation matrix, with a maximum size of 6x6.
- */
- void colorMatrix(double[][] matrix)
- {
- if ( matrix.length > 6 || matrix[0].length > 6 )
- throw new DMagickException("Matrix must be 6x6 or smaller.");
- static if ( is(typeof(ColorMatrixImage)) )
- {
- KernelInfo* kernelInfo = AcquireKernelInfo("1");
- scope(exit) DestroyKernelInfo(kernelInfo);
- kernelInfo.width = matrix[0].length;
- kernelInfo.height = matrix.length;
- kernelInfo.values = cast(double*)AcquireQuantumMemory(kernelInfo.width*kernelInfo.height, double.sizeof);
- scope(exit) kernelInfo.values = cast(double*)RelinquishMagickMemory(kernelInfo.values);
- foreach ( i, row; matrix )
- {
- size_t offset = i * row.length;
- kernelInfo.values[offset .. offset+row.length] = row;
- }
- MagickCoreImage* image =
- ColorMatrixImage(imageRef, kernelInfo, DMagickExceptionInfo());
- }
- else
- {
- double[] values;
- foreach ( i, row; matrix )
- {
- size_t offset = i * row.length;
- values[offset .. offset+row.length] = row;
- }
- MagickCoreImage* image =
- RecolorImage(imageRef, matrix.length, values.ptr, DMagickExceptionInfo());
- }
- imageRef = ImageRef(image);
- }
- /**
- * Compare current image with another image. Sets meanErrorPerPixel,
- * normalizedMaxError , and normalizedMeanError in the current image.
- * false is returned if the images are identical. An ErrorOption
- * exception is thrown if the reference image columns, rows, colorspace,
- * or matte differ from the current image.
- */
- bool compare(const(Image) referenceImage)
- {
- bool isEqual = IsImagesEqual(imageRef, referenceImage.imageRef) == 1;
- DMagickException.throwException(&(imageRef.exception));
- return isEqual;
- }
- /**
- * Composites dest onto this image using the specified composite operator.
- *
- * Params:
- * overlay = Image to use in the composite operation.
- * compositeOp = The composite operation to use.
- * xOffset = The x-offset of the composited image,
- * measured from the upper-left corner
- * of the image.
- * yOffset = The y-offset of the composited image,
- * measured from the upper-left corner
- * of the image.
- * gravity = The gravity that defines the location of the
- * location of overlay.
- * channel = One or more channels to compose.
- */
- void composite(
- const(Image) overlay,
- CompositeOperator compositeOp,
- ssize_t xOffset,
- ssize_t yOffset,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- CompositeImageChannel(imageRef, channel, compositeOp, overlay.imageRef, xOffset, yOffset);
- DMagickException.throwException(&(imageRef.exception));
- }
- ///ditto
- void composite(
- const(Image) overlay,
- CompositeOperator compositeOp,
- GravityType gravity = GravityType.NorthWestGravity,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- RectangleInfo geometry;
- SetGeometry(overlay.imageRef, &geometry);
- GravityAdjustGeometry(columns, rows, gravity, &geometry);
- composite(overlay, compositeOp, geometry.x, geometry.y, channel);
- }
- /**
- * Merge the source and destination images according to the
- * formula a*Sc*Dc + b*Sc + c*Dc + d where Sc is the source
- * pixel and Dc is the destination pixel.
- *
- * Params:
- * overlay = Image to use in to composite operation.
- * xOffset = The x-offset of the composited image,
- * measured from the upper-left corner
- * of the image.
- * yOffset = The y-offset of the composited image,
- * measured from the upper-left corner
- * of the image.
- * gravity = The gravity that defines the location of the
- * location of overlay.
- * channel = One or more channels to compose.
- */
- void composite(
- const(Image) overlay,
- double a,
- double b,
- double c,
- double d,
- ssize_t xOffset,
- ssize_t yOffset,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- SetImageArtifact(imageRef, "compose:args",
- toStringz(std.string.format("%s,%s,%s,%s", a, b, c, d)));
- scope(exit) RemoveImageArtifact(imageRef, "compose:args");
- composite(overlay, CompositeOperator.MathematicsCompositeOp, xOffset, yOffset, channel);
- }
- ///ditto
- void composite(
- const(Image) overlay,
- double a,
- double b,
- double c,
- double d,
- GravityType gravity = GravityType.NorthWestGravity,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- RectangleInfo geometry;
- SetGeometry(overlay.imageRef, &geometry);
- GravityAdjustGeometry(columns, rows, gravity, &geometry);
- composite(overlay, a, b, c, d, geometry.x, geometry.y, channel);
- }
- /**
- * Composites multiple copies of the source image across and down
- * the image, producing the same results as ImageMagick's composite
- * command with the -tile option.
- *
- * Params:
- * overlay = Image to use in to composite operation.
- * compositeOp = The composite operation to use.
- * channel = One or more channels to compose.
- */
- void compositeTiled(
- const(Image) overlay,
- CompositeOperator compositeOp,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- SetImageArtifact(imageRef, "compose:outside-overlay", "false");
- scope(exit) RemoveImageArtifact(imageRef, "compose:outside-overlay");
- for ( size_t y = 0; y < rows; y += overlay.rows )
- for ( size_t x = 0; x < columns; x += overlay.columns )
- composite(overlay, compositeOp, x, y, channel);
- }
- /**
- * enhances the intensity differences between the lighter and
- * darker elements of the image.
- *
- * Params:
- * sharpen = If true increases the image contrast otherwise
- * the contrast is reduced.
- */
- void contrast(bool sharpen = false)
- {
- ContrastImage(imageRef, sharpen);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * This is a simple image enhancement technique that attempts to
- * improve the contrast in an image by `stretching' the range of
- * intensity values it contains to span a desired range of values.
- * It differs from the more sophisticated histogram equalization in
- * that it can only apply a linear scaling function to the image pixel
- * values. As a result the `enhancement' is less harsh.
- *
- * Params:
- * blackPoint = Black out at most this many pixels.
- * Specify an apsulute number of pixels or an
- * percentage by passing a value between 1 and 0
- * whitePoint = Burn at most this many pixels.
- * Specify an apsulute number of pixels or an
- * percentage by passing a value between 1 and 0
- * channel = One or more channels to adjust.
- */
- void contrastStretch(double blackPoint, double whitePoint, ChannelType channel = ChannelType.DefaultChannels)
- {
- if ( blackPoint < 1 )
- blackPoint *= QuantumRange;
- if ( whitePoint < 1 )
- whitePoint *= QuantumRange;
- ContrastStretchImageChannel(imageRef, channel, blackPoint, whitePoint);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Applies a custom convolution kernel to the image.
- * See_Also: $(LINK2 http://www.dai.ed.ac.uk/HIPR2/convolve.htm,
- * Convolution in the Hypermedia Image Processing Reference).
- */
- void convolve(double[][] matrix, ChannelType channel = ChannelType.DefaultChannels)
- {
- double[] kernel = new double[matrix.length * matrix[0].length];
- foreach ( i, row; matrix )
- {
- size_t offset = i * row.length;
- kernel[offset .. offset+row.length] = row;
- }
- MagickCoreImage* image =
- ConvolveImageChannel(imageRef, channel, matrix.length, kernel.ptr, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Extract a region of the image starting at the offset defined by
- * geometry. Region must be fully defined, and no special handling
- * of geometry flags is performed.
- */
- void crop(Geometry geometry)
- {
- RectangleInfo rectangle = geometry.rectangleInfo;
- MagickCoreImage* image =
- CropImage(imageRef, &rectangle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * displaces an image's colormap by a given number of positions.
- * If you cycle the colormap a number of times you can produce
- * a psychodelic effect.
- */
- void cycleColormap(ssize_t amount)
- {
- CycleColormapImage(imageRef, amount);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Decipher an enciphered image.
- */
- void decipher(string passphrase)
- {
- DecipherImage(imageRef, toStringz(passphrase), DMagickExceptionInfo());
- }
- /**
- * Straightens an image. A threshold of 40% works for most images.
- *
- * Skew is an artifact that occurs in scanned images because of the
- * camera being misaligned, imperfections in the scanning or surface,
- * or simply because the paper was not placed completely flat when
- * scanned.
- *
- * Params:
- * threshold = Specify an apsulute number of pixels or an
- * percentage by passing a value between 1 and 0.
- * autoCropWidth = Specify a value for this argument to cause the
- * deskewed image to be auto-cropped.
- * The argument is the pixel width of the
- * image background (e.g. 40).
- * A width of 0 disables auto cropping.
- */
- void deskew(double threshold = 0.4, size_t autoCropWidth = 0)
- {
- if ( autoCropWidth > 0 )
- {
- SetImageArtifact(imageRef, "deskew:auto-crop", toStringz(to!(string)(autoCropWidth)) );
- scope(exit) RemoveImageArtifact(imageRef, "deskew:auto-crop");
- }
- if ( threshold < 1 )
- threshold *= QuantumRange;
- MagickCoreImage* image =
- DeskewImage(imageRef, threshold, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Reduces the speckle noise in an image while perserving
- * the edges of the original image.
- */
- void despeckle()
- {
- MagickCoreImage* image =
- DespeckleImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Uses displacementMap to move color from img to the output image.
- *
- * This method corresponds to the -displace option of ImageMagick's
- * composite command.
- *
- * Params:
- * displacementMap =
- * The source image for the composite operation.
- * xAmplitude = The maximum displacement on the x-axis.
- * yAmplitude = The maximum displacement on the y-axis.
- * xOffset = The x offset to use.
- * yOffset = The y offset to use.
- * gravity = The gravity to use.
- */
- void displace(
- const(Image) displacementMap,
- int xAmplitude,
- int yAmplitude,
- ssize_t xOffset,
- ssize_t yOffset)
- {
- SetImageArtifact(imageRef, "compose:args",
- toStringz(std.string.format("%s,%s", xAmplitude, yAmplitude)));
- scope(exit) RemoveImageArtifact(imageRef, "compose:args");
- composite(displacementMap, CompositeOperator.DisplaceCompositeOp, xOffset, yOffset);
- }
- ///ditto
- void displace(
- const(Image) overlay,
- int srcPercentage,
- int dstPercentage,
- GravityType gravity = GravityType.NorthWestGravity)
- {
- RectangleInfo geometry;
- SetGeometry(overlay.imageRef, &geometry);
- GravityAdjustGeometry(columns, rows, gravity, &geometry);
- displace(overlay, srcPercentage, dstPercentage, geometry.x, geometry.y);
- }
- /**
- * Display image on screen.
- *
- * $(RED Caution:) if an image format is is not compatible with
- * the display visual (e.g. JPEG on a colormapped display)
- * then the original image will be altered. Use a copy of the
- * original if this is a problem.
- */
- void display()
- {
- version(DMagick_No_Display)
- {
- }
- else
- {
- version(Windows)
- {
- Window win = new Window(this);
- win.display();
- }
- else
- {
- DisplayImages(options.imageInfo, imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- }
- }
- /**
- * Composites the overlay image onto this image. The opacity
- * of this image is multiplied by dstPercentage and opacity of
- * overlay is multiplied by srcPercentage.
- *
- * This method corresponds to the -dissolve option
- * of ImageMagick's composite command.
- *
- * Params:
- * overlay = The source image for the composite operation.
- * srcPercentage = Percentage for the source image.
- * dstPercentage = Percentage for this image.
- * xOffset = The x offset to use for the overlay.
- * yOffset = The y offset to use for the overlay.
- * gravity = The gravity to use for the overlay.
- */
- void dissolve(
- const(Image) overlay,
- int srcPercentage,
- int dstPercentage,
- ssize_t xOffset,
- ssize_t yOffset)
- {
- SetImageArtifact(imageRef, "compose:args",
- toStringz(std.string.format("%s,%s", srcPercentage, dstPercentage)));
- scope(exit) RemoveImageArtifact(imageRef, "compose:args");
- composite(overlay, CompositeOperator.DissolveCompositeOp, xOffset, yOffset);
- }
- ///ditto
- void dissolve(
- const(Image) overlay,
- int srcPercentage,
- int dstPercentage,
- GravityType gravity = GravityType.NorthWestGravity)
- {
- RectangleInfo geometry;
- SetGeometry(overlay.imageRef, &geometry);
- GravityAdjustGeometry(columns, rows, gravity, &geometry);
- dissolve(overlay, srcPercentage, dstPercentage, geometry.x, geometry.y);
- }
- /**
- * Distort an image using the specified distortion type and its
- * required arguments. This method is equivalent to ImageMagick's
- * -distort option.
- *
- * Params:
- * method = Distortion method to use.
- * arguments = An array of numbers. The size of the array
- * depends on the distortion type.
- * bestfit = If enabled, and the distortion allows it,
- * the destination image is adjusted to ensure
- * the whole source image will just fit within
- * the final destination image, which will be
- * sized and offset accordingly.
- */
- void distort(DistortImageMethod method, double[] arguments, bool bestfit = false)
- {
- MagickCoreImage* image =
- DistortImage(imageRef, method, arguments.length, arguments.ptr, bestfit, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Finds edges in an image.
- *
- * Params:
- * radius = the radius of the convolution filter.
- * If 0 a suitable default is selected.
- */
- void edge(double radius = 0)
- {
- MagickCoreImage* image =
- EdgeImage(imageRef, radius, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Emboss image (hilight edges with 3D effect).
- *
- * Params:
- * radius = The radius of the Gaussian, in pixels,
- * not counting the center pixel.
- * sigma = The standard deviation of the Laplacian, in pixels.
- */
- void emboss(double radius = 0, double sigma = 1)
- {
- MagickCoreImage* image =
- EmbossImage(imageRef, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Encipher an image.
- */
- void encipher(string passphrase)
- {
- EncipherImage(imageRef, toStringz(passphrase), DMagickExceptionInfo());
- }
- /**
- * Applies a digital filter that improves the quality of a noisy image.
- */
- void enhance()
- {
- MagickCoreImage* image =
- EnhanceImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Applies a histogram equalization to the image.
- */
- void equalize(ChannelType channel = ChannelType.DefaultChannels)
- {
- EqualizeImageChannel(imageRef, channel);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Initializes the image pixels to the image background color.
- */
- void erase()
- {
- SetImageBackgroundColor(imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Applies a value to the image with an arithmetic, relational, or
- * logical operator to an image. Use these operations to lighten or
- * darken an image, to increase or decrease contrast in an image, or
- * to produce the "negative" of an image.
- *
- * See_Also: $(LINK2 http://www.imagemagick.org/script/command-line-options.php#evaluate,
- * ImageMagick's -_evaluate option).
- */
- void evaluate(MagickEvaluateOperator op, double value, ChannelType channel = ChannelType.DefaultChannels)
- {
- EvaluateImageChannel(imageRef, channel, op, value, DMagickExceptionInfo());
- }
- /**
- * This method is very similar to crop. It extracts the rectangle
- * specified by its arguments from the image and returns it as a new
- * image. However, excerpt does not respect the virtual page offset and
- * does not update the page offset and is more efficient than cropping.
- *
- * It is the caller's responsibility to ensure that the rectangle lies
- * entirely within the original image.
- */
- void excerpt(Geometry geometry)
- {
- RectangleInfo rectangle = geometry.rectangleInfo;
- MagickCoreImage* image =
- ExcerptImage(imageRef, &rectangle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Extracts the pixel data from the specified rectangle.
- *
- * Params:
- * area = Area to extract.
- * map = This character string can be any combination
- * or order of R = red, G = green, B = blue, A =
- * alpha, C = cyan, Y = yellow, M = magenta, and K = black.
- * The ordering reflects the order of the pixels in
- * the supplied pixel array.
- *
- * Returns: An array of values containing the pixel components as
- * defined by the map parameter and the Type.
- */
- T[] exportPixels(T)(Geometry area, string map = "RGBA") const
- {
- T[] pixels = new T[(area.width * area.height) * map.length];
- exportPixels(area, pixels, map);
- return pixels;
- }
- /**
- * Ditto, but takes an existing pixel buffer.
- *
- * Throws: An ImageException if the buffer length is insufficient.
- */
- void exportPixels(T)(Geometry area, T[] pixels, string map = "RGBA") const
- {
- if ( pixels.length < (area.width * area.height) * map.length )
- throw new ImageException(std.string.format("Pixel buffer needs more storage for %s channels.", map));
- StorageType storage = getStorageType!(T);
- ExportImagePixels(
- imageRef,
- area.xOffset,
- area.yOffset,
- area.width,
- area.height,
- toStringz(map),
- storage,
- pixels.ptr,
- DMagickExceptionInfo());
- }
- unittest
- {
- Image image = new Image(Geometry(100, 100), new Color("red"));
- byte[] bytes = image.exportPixels!(byte)(Geometry(10,10,10,10));
- assert(bytes.length == 10 * 10 * 4);
- }
- /**
- * If the Geometry is larger than this Image, extends the image to
- * the specified geometry. And the new pixels are set to the
- * background color. If the Geometry is smaller than this image
- * crops the image.
- *
- * The new image is composed over the background using
- * the composite operator specified by the compose property.
- */
- void extent(Geometry geometry)
- {
- RectangleInfo rectangle = geometry.rectangleInfo;
- MagickCoreImage* image =
- ExtentImage(imageRef, &rectangle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * This interesting method searches for a rectangle in the image that
- * is similar to the target. For the rectangle to be similar each pixel
- * in the rectangle must match the corresponding pixel in the target
- * image within the range specified by the fuzz property of this image
- * and the target image.
- *
- * Params:
- * target = An image that forms the target of the search.
- * xOffset = The starting x position to search for a match.
- * yOffset = The starting y position to search for a match.
- *
- * Returns: The size and location of the match.
- */
- Geometry findSimilarRegion(Image target, ssize_t xOffset, ssize_t yOffset)
- {
- IsImageSimilar(imageRef, target.imageRef, &xOffset, &yOffset, DMagickExceptionInfo());
- return Geometry(target.columns, target.rows, xOffset, yOffset);
- }
- /**
- * creates a vertical mirror image by reflecting the pixels
- * around the central x-axis.
- */
- void flip()
- {
- FlipImage(imageRef, DMagickExceptionInfo());
- }
- /**
- * Changes the color value of any pixel that matches target and is an
- * immediate neighbor. To the fillColor or fillPattern set for this
- * image. If fillToBorder is true, the color value is changed
- * for any neighbor pixel that does not match the borderColor.
- *
- * By default target must match a particular pixel color exactly.
- * However, in many cases two colors may differ by a small amount.
- * The fuzz property of image defines how much tolerance is acceptable
- * to consider two colors as the same. For example, set fuzz to 10 and
- * the color red at intensities of 100 and 102 respectively are now
- * interpreted as the same color for the purposes of the floodfill.
- *
- * Params:
- * xOffset = Starting x location for the operation.
- * xOffset = Starting y location for the operation.
- * fillToBorder = If true fill untill the borderColor, else only
- * the target color if affected.
- * channel = The affected channels.
- */
- void floodFill(
- ssize_t xOffset,
- ssize_t yOffset,
- bool fillToBorder = false,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickPixelPacket target;
- GetMagickPixelPacket(imageRef, &target);
- if ( fillToBorder )
- {
- setMagickPixelPacket(&target, borderColor);
- }
- else
- {
- PixelPacket packet;
- GetOneAuthenticPixel(imageRef, xOffset, yOffset, &packet, DMagickExceptionInfo());
- setMagickPixelPacket(&target, new Color(packet));
- }
- FloodfillPaintImage(imageRef, channel, options.drawInfo, &target, xOffset, yOffset, fillToBorder);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Fill the image like floodFill but use the specified colors.
- *
- * Params:
- * xOffset = Starting x location for the operation.
- * xOffset = Starting y location for the operation.
- * fillColor = Fill color to use.
- * borderColor = borderColor to use.
- * channel = The affected channels.
- */
- void floodFillColor(
- ssize_t xOffset,
- ssize_t yOffset,
- Color fillColor,
- Color borderColor = null,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- Color oldFillColor = options.fillColor;
- options.fillColor = fillColor;
- scope(exit) options.fillColor = oldFillColor;
- floodFillPattern(xOffset, yOffset, null, borderColor, channel);
- }
- /**
- * Fill the image like floodFill but use the specified
- * pattern an borderColor.
- *
- * Params:
- * xOffset = Starting x location for the operation.
- * xOffset = Starting y location for the operation.
- * fillPattern = Fill pattern to use.
- * borderColor = borderColor to use.
- * channel = The affected channels.
- */
- void floodFillPattern(
- ssize_t xOffset,
- ssize_t yOffset,
- Image fillPattern,
- Color borderColor = null,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- // Cast away const, so we can temporarily hold
- // The image and asign it back to the fillPattern.
- Image oldFillPattern = cast(Image)options.fillPattern;
- options.fillPattern = fillPattern;
- scope(exit) options.fillPattern = oldFillPattern;
- Color oldBorderColor = this.borderColor;
- this.borderColor = borderColor;
- scope(exit) this.borderColor = oldBorderColor;
- // If the borderColor !is null, set fillToBorder to true.
- floodFill(xOffset, yOffset, borderColor !is null, channel);
- }
- /**
- * creates a horizontal mirror image by reflecting the pixels
- * around the central y-axis.
- */
- void flop()
- {
- FlopImage(imageRef, DMagickExceptionInfo());
- }
- /**
- * Adds a simulated 3D border.
- * The matteColor is used to draw the frame.
- *
- * Params:
- * geometry = The size portion indicates the width and height of
- * the frame. If no offsets are given then the border
- * added is a solid color. Offsets x and y, if present,
- * specify that the width and height of the border is
- *…