/dmagick/Image.d
D | 4492 lines | 2101 code | 547 blank | 1844 comment | 125 complexity | 04d00e165654ff064104a41ec065a457 MD5 | raw 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
- * partitioned to form an outer bevel of thickness x
- * pixels and an inner bevel of thickness y pixels.
- * Negative offsets make no sense as frame arguments.
- */
- void frame(Geometry geometry)
- {
- FrameInfo frameInfo;
- frameInfo.width = columns + ( 2 * geometry.width );
- frameInfo.height = rows + ( 2 * geometry.height );
- frameInfo.x = geometry.width;
- frameInfo.y = geometry.height;
- frameInfo.inner_bevel = geometry.yOffset;
- frameInfo.outer_bevel = geometry.xOffset;
- MagickCoreImage* image =
- FrameImage(imageRef, &frameInfo, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * 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.
- *
- * This method is equivalent to the
- * $(LINK2 http://www.imagemagick.org/script/command-line-options.php#function,
- * convert -function) option.
- *
- * Params:
- * function = The MagickFunction to use.
- * params =
- * An array of values to be used by the function.
- * $(LIST $(COMMA $(B PolynomialFunction:)
- * The Polynomial function takes an arbitrary number of
- * parameters, these being the coefficients of a polynomial,
- * in decreasing order of degree. That is, entering
- * [aₙ, aₙ₋₁, ... a₁, a₀] will invoke a polynomial function
- * given by: aₙ uⁿ + aₙ₋₁ uⁿ⁻¹ + ··· a₁ u + a₀, where where
- * u is pixel's original normalized channel value.),
- * $(COMMA $(B SinusoidFunction:)
- * These values are given as one to four parameters, as
- * follows, [freq, phase, amp, bias] if omitted the default
- * values will be used: [1.0, 0.0, 0.5, 0.5].),
- * $(COMMA $(B ArcsinFunction:)
- * These values are given as one to four parameters, as
- * follows, [width, center, range, bias] if omitted the
- * default values will be used: [1.0, 0.5, 1.0, 0.5].),
- * $(COMMA $(B ArctanFunction:)
- * These values are given as one to four parameters, as
- * follows, [slope, center, range, bias] if omitted the
- * default values will be used: [1.0, 0.5, 1.0, 0.5].))
- * channel = The channels this funtion aplies to.
- */
- void functionImage(MagickFunction funct, double[] params, ChannelType channel = ChannelType.DefaultChannels)
- {
- FunctionImageChannel(imageRef, channel, funct, params.length, params.ptr, DMagickExceptionInfo());
- }
- /**
- * Applies a mathematical expression to the specified image.
- *
- * See_Aso:
- * $(LINK2 http://www.imagemagick.org/script/fx.php,
- * FX, The Special Effects Image Operator) for a detailed
- * discussion of this option.
- */
- void fx(string expression, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- FxImageChannel(imageRef, channel, toStringz(expression), DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * gamma gamma-corrects a particular image channel.
- * The same image viewed on different devices will have perceptual
- * differences in the way the image's intensities are represented
- * on the screen. Specify individual gamma levels for the red,
- * green, and blue channels, or adjust all three with the gamma
- * function. Values typically range from 0.8 to 2.3.
- *
- * You can also reduce the influence of a particular channel
- * with a gamma value of 0.
- */
- void gamma(double value, ChannelType channel = ChannelType.DefaultChannels)
- {
- GammaImageChannel(imageRef, channel, value);
- DMagickException.throwException(&(imageRef.exception));
- }
- ///ditto
- void gamma(double red, double green, double blue)
- {
- GammaImageChannel(imageRef, ChannelType.RedChannel, red);
- GammaImageChannel(imageRef, ChannelType.GreenChannel, green);
- GammaImageChannel(imageRef, ChannelType.BlueChannel, blue);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Blurs an image. We convolve the image with a Gaussian operator
- * of the given radius and standard deviation (sigma).
- * For reasonable results, the radius should be larger than sigma.
- *
- * Params:
- * radius = The radius of the Gaussian, in pixels,
- * not counting the center pixel.
- * sigma = the standard deviation of the Gaussian, in pixels.
- * channel = The channels to blur.
- */
- void gaussianBlur(double radius = 0, double sigma = 1, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- GaussianBlurImageChannel(imageRef, channel, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Returns the TypeMetric class witch provides the information
- * regarding font metrics such as ascent, descent, text width,
- * text height, and maximum horizontal advance. The units of
- * these font metrics are in pixels, and that the metrics are
- * dependent on the current Image font (default Ghostscript's
- * "Helvetica"), pointsize (default 12 points), and x/y resolution
- * (default 72 DPI) settings.
- *
- * The pixel units may be converted to points (the standard
- * resolution-independent measure used by the typesetting industry)
- * via the following equation:
- * ----------------------------------
- * sizePoints = (sizePixels * 72)/resolution
- * ----------------------------------
- * where resolution is in dots-per-inch (DPI). This means that at the
- * default image resolution, there is one pixel per point.
- * See_Also:
- * $(LINK2 http://freetype.sourceforge.net/freetype2/docs/glyphs/index.html,
- * FreeType Glyph Conventions) for a detailed description of
- * font metrics related issues.
- */
- TypeMetric getTypeMetrics(string text)
- {
- TypeMetric metric;
- DrawInfo* drawInfo = options.drawInfo;
- copyString(drawInfo.text, text);
- scope(exit) copyString(drawInfo.text, null);
- GetMultilineTypeMetrics(imageRef, drawInfo, &metric);
- DMagickException.throwException(&(imageRef.exception));
- return metric;
- }
- /**
- * applies a Hald color lookup table to the image. A Hald color lookup
- * table is a 3-dimensional color cube mapped to 2 dimensions. Create
- * it with the HALD coder. You can apply any color transformation to
- * the Hald image and then use this method to apply the transform to
- * the image.
- *
- * Params:
- * haldImage = The image, which is replaced by indexed CLUT values.
- * channel = The channels to aply the CLUT to.
- *
- * See_Also:
- * $(XREF Image, clut) which provides color value replacement of
- * the individual color channels, usally involving a simplier
- * gray-scale image. E.g: gray-scale to color replacement, or
- * modification by a histogram mapping.
- */
- void haldClut(Image haldImage, ChannelType channel = ChannelType.DefaultChannels)
- {
- HaldClutImageChannel(imageRef, channel, haldImage.imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * A funhouse mirror effect.
- *
- * Params:
- * amount = Defines the extend of the effect.
- * The value may be positive for implosion,
- * or negative for explosion.
- */
- void implode(double amount = 0.5)
- {
- MagickCoreImage* image =
- ImplodeImage(imageRef, amount, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Replaces the pixels in the specified area with pixel data
- * from the supplied array.
- *
- * Params:
- * area = Location in the image to store the pixels.
- * pixels = An array of pixels defined by map.
- * 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.
- */
- void importPixels(T)(Geometry area, T[] pixels, string map = "RGBA")
- {
- StorageType storage = getStorageType!(T);
- ImportImagePixels(imageRef,
- area.xOffset, area.yOffset,
- area.width, area.height,
- toStringz(map), storage, pixels.ptr);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Adjusts the levels of an image by scaling the colors falling between
- * specified white and black points to the full available quantum range.
- * The parameters provided represent the black, mid, and white points.
- * Colors darker than the black point are set to zero. Colors brighter
- * than the white point are set to the maximum quantum value.
- *
- * It is typically used to improve image contrast, or to provide a
- * controlled linear threshold for the image. If the black and white
- * points are set to the minimum and maximum values found in the image,
- * the image can be normalized. or by swapping black and white values,
- * negate the image.
- *
- * Params:
- * blackPoint = Specifies the darkest color in the image.
- * whitePoint = Specifies the lightest color in the image.
- * gamma = Specifies the gamma correction to apply to the image.
- * channel = The channels to level.
- */
- void level(
- Quantum blackPoint = 0,
- Quantum whitePoint = QuantumRange,
- double gamma = 1,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- LevelImageChannel(imageRef, channel, blackPoint, whitePoint, gamma);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * applies the reversed level operation to just the channels specified.
- * It compresses the full range of color values, so that they lie between
- * the given black and white points. Gamma is applied before the values
- * are mapped.
- *
- * It can be used for example de-contrast a greyscale image to the exact
- * levels specified. Or by using specific levels for each channel of an
- * image you can convert a gray-scale image to any linear color gradient,
- * according to those levels.
- *
- * Params:
- * blackPoint = Specifies the darkest color in the image.
- * whitePoint = Specifies the lightest color in the image.
- * gamma = Specifies the gamma correction to apply to the image.
- * channel = The channels to level.
- */
- void levelize(
- Quantum blackPoint = 0,
- Quantum whitePoint = QuantumRange,
- double gamma = 1,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- LevelizeImageChannel(imageRef, channel, blackPoint, whitePoint, gamma);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Discards any pixels below the black point and above the white
- * point and levels the remaining pixels.
- *
- * Params:
- * blackPoint = Specifies the darkest color in the image.
- * whitePoint = Specifies the lightest color in the image.
- */
- void linearStretch(Quantum blackPoint, Quantum whitePoint)
- {
- LinearStretchImage(imageRef, blackPoint, whitePoint);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Rescale image with seam carving. To use this method, you must
- * have installed and configured ImageMagick to use the
- * $(LINK2 http://liblqr.wikidot.com/, Liquid Rescale Library).
- *
- * Params:
- * columns = The desired width.
- * rows = The desired height.
- * deltaX = Maximum seam transversal step (0 means straight seams).
- * rigidity = Introduce a bias for non-straight seams (typically 0).
- */
- void liquidRescale(Geometry size, size_t rows, double deltaX = 0, double rigidity = 0)
- {
- size = size.toAbsolute(columns, rows);
- MagickCoreImage* image =
- LiquidRescaleImage(imageRef, size.width, size.height, deltaX, rigidity, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * A convenience method that scales an image proportionally to
- * twice its size.
- */
- void magnify()
- {
- MagickCoreImage* image = MagnifyImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Applies a digital filter that improves the quality of a noisy image.
- * Each pixel is replaced by the median in a set of neighboring pixels
- * as defined by radius.
- *
- * Params:
- * radius = The filter radius. Values larger than 8 or 9 may take
- * longer than you want to wait, and will not have
- * significantly better results than much smaller values.
- */
- void medianFilter(size_t radius = 0)
- {
- static if ( is(typeof(StatisticImage)) )
- {
- MagickCoreImage* image =
- StatisticImage(imageRef, StatisticType.MedianStatistic, radius, radius, DMagickExceptionInfo());
- }
- else
- {
- MagickCoreImage* image =
- MedianFilterImage(imageRef, radius, DMagickExceptionInfo());
- }
- imageRef = ImageRef(image);
- }
- /**
- * A convenience method that scales an image proportionally to
- * half its size.
- */
- void minify()
- {
- MagickCoreImage* image = MinifyImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Modulate percent hue, saturation, and brightness of an image.
- * Modulation of saturation and brightness is as a ratio of the current
- * value (1 ( == 100% ) for no change).
- *
- * Params:
- * brightness = The percentage of change in the brightness.
- * saturation = The percentage of change in the saturation.
- * hue = The percentage of change in the hue.
- */
- void modulate(double brightness = 1, double saturation = 1, double hue = 1)
- {
- string args = std.string.format("%s,%s,%s", brightness*100, saturation*100, hue*100);
- ModulateImage(imageRef, toStringz(args));
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Simulates motion blur. We convolve the image with a Gaussian operator
- * of the given radius and standard deviation (sigma). Use a radius of 0
- * and motion_blur selects a suitable radius for you. Angle gives the
- * angle of the blurring motion.
- *
- * Params:
- * radius = The radius of the Gaussian operator.
- * sigma = The standard deviation of the Gaussian operator.
- * Must be non-0.
- * angle = The angle (in degrees) of the blurring motion.
- * channel = The affected channels.
- */
- void motionBlur(
- double radius = 0,
- double sigma = 1,
- double angle = 0,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- MotionBlurImageChannel(imageRef, channel, radius, sigma, angle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Negates the colors in the reference image.
- *
- * Params:
- * grayscale = If true, only negate grayscale pixels
- * within the image.
- * channel = The affected channels.
- */
- void negate(bool grayscale = false, ChannelType channel = ChannelType.DefaultChannels)
- {
- NegateImageChannel(imageRef, channel, grayscale);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Enhances the contrast of a color image by adjusting the pixel
- * color to span the entire range of colors available.
- */
- void normalize(ChannelType channel = ChannelType.DefaultChannels)
- {
- NormalizeImageChannel(imageRef, channel);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Applies a special effect filter that simulates an oil painting.
- * Each pixel is replaced by the most frequent color occurring in a
- * circular region defined by radius.
- */
- void oilPaint(double radius = 3)
- {
- MagickCoreImage* image =
- OilPaintImage(imageRef, radius, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Set or attenuate the opacity channel in the image.
- * If the image pixels are opaque then they are set to the specified
- * opacity value, otherwise they are blended with the supplied opacity
- * value.
- */
- void opacity(Quantum value)
- {
- SetImageOpacity(imageRef, value);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Changes all pixels having the target color to the fill color.
- *
- * Params:
- * target = The color to be replaced.
- * fill = The replacement color.
- * invert = If true, the target pixels are all the pixels
- * that are not the target color.
- * channel = The affected channels.
- */
- void opaque(Color target, Color fill, bool invert = false, ChannelType channel = ChannelType.CompositeChannels)
- {
- MagickPixelPacket magickTarget;
- MagickPixelPacket magickFill;
-
- GetMagickPixelPacket(imageRef, &magickTarget);
- GetMagickPixelPacket(imageRef, &magickFill);
- setMagickPixelPacket(&magickTarget, target);
- setMagickPixelPacket(&magickFill, fill);
- OpaquePaintImageChannel(imageRef, channel, &magickTarget, &magickFill, invert);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Dithers the image to a predefined pattern.
- *
- * Params:
- * map = The map argument can be any of the strings
- * listed by this command:
- * --------------------
- * convert -list Threshold
- * --------------------
- * See_Also: $(LINK2 http://www.imagemagick.org/script/command-line-options.php#ordered-dither,
- * ImageMagick's -ordered-dither option).
- */
- void orderedDither(string map)
- {
- OrderedPosterizeImage(imageRef, toStringz(map), DMagickExceptionInfo());
- }
- /**
- * Ping is similar to read except only enough of the image is read to
- * determine the image columns, rows, and filesize. The columns, rows,
- * and fileSize attributes are valid after invoking ping.
- * The image data is not valid after calling ping.
- */
- void ping(string filename)
- {
- options.filename = filename;
- MagickCoreImage* image = PingImages(options.imageInfo, DMagickExceptionInfo());
- //Make sure a single image (frame) is read.
- if ( image.next !is null )
- {
- MagickCoreImage* nextImage;
- nextImage = image.next;
- image.next = null;
- nextImage.previous = null;
- DestroyImageList(nextImage);
- }
- imageRef = ImageRef(image);
- }
- ///ditto
- void ping(void[] blob)
- {
- MagickCoreImage* image =
- PingBlob(options.imageInfo, blob.ptr, blob.length, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Produce an image that looks like a Polaroid® instant picture.
- * If the image has a "Caption" property, the value is used as a caption.
- *
- * Params:
- * angle = The resulting image is rotated by this amount,
- * measured in degrees.
- */
- void polaroid(double angle)
- {
- MagickCoreImage* image =
- PolaroidImage(imageRef, options.drawInfo, angle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Reduces the image to a limited number of colors for a "poster" effect.
- *
- * Params:
- * levels = Number of color levels allowed in each channel.
- * Very low values (2, 3, or 4) have the most
- * visible effect.
- * dither = If true, dither the image.
- */
- void posterize(size_t levels = 4, bool dither = false)
- {
- PosterizeImage(imageRef, levels, dither);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Creates an image that contains 9 small versions of the receiver
- * image. The center image is the unchanged receiver. The other 8
- * images are variations created by transforming the receiver according
- * to the specified preview type with varying parameters.
- *
- * A preview image is an easy way to "try out" a transformation method.
- */
- Image preview(PreviewType preview)
- {
- MagickCoreImage* image =
- PreviewImage(imageRef, preview, DMagickExceptionInfo());
- return new Image(image, options.clone());
- }
- /**
- * Execute the named process module, passing any arguments arguments.
- * An exception is thrown if the requested process module does not exist,
- * fails to load, or fails during execution.
- *
- * Params:
- * name = The name of a module.
- * arguments = The arguments to pass to the module.
- */
- void process(string name, string[] arguments)
- {
- MagickCoreImage* image = imageRef;
- const(char)*[] args = new const(char)*[arguments.length];
- foreach( i, arg; arguments )
- args[i] = toStringz(arg);
- InvokeDynamicImageFilter(toStringz(name), &image, cast(int)args.length, args.ptr, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Analyzes the colors within a reference image and chooses a fixed
- * number of colors to represent the image. The goal of the algorithm
- * is to minimize the difference between the input and output image
- * while minimizing the processing time.
- *
- * Params:
- * measureError = Set to true to calculate quantization errors
- * when quantizing the image. These can be accessed
- * with: normalizedMeanError, normalizedMaxError
- * and meanErrorPerPixel.
- */
- void quantize(bool measureError = false)
- {
- options.quantizeInfo.measure_error = measureError;
- QuantizeImage(options.quantizeInfo, imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Creates a simulated three-dimensional button-like effect by
- * lightening and darkening the edges of the image.
- *
- * Params:
- * width = The width of the raised edge in pixels.
- * height = The height of the raised edge in pixels.
- * raised = If true, the image is raised, otherwise lowered.
- */
- void raise(size_t width, size_t height, bool raised = true)
- {
- RectangleInfo raiseInfo;
- raiseInfo.width = width;
- raiseInfo.height = height;
- RaiseImage(imageRef, &raiseInfo, raised);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Changes the value of individual pixels based on the intensity of
- * each pixel compared to a random threshold. The result is a
- * low-contrast, two color image.
- *
- * Params:
- * thresholds = A geometry string containing LOWxHIGH thresholds.
- * The string is in the form `XxY'. The Y value may be
- * omitted, in which case it is assigned the value
- * QuantumRange-X. If an % appears in the string then
- * the values are assumed to be percentages of
- * QuantumRange. If the string contains 2x2, 3x3, or
- * 4x4, then an ordered dither of order 2, 3, or 4
- * will be performed instead.
- * channel = The affected channels.
- */
- void randomThreshold(Geometry thresholds, ChannelType channel = ChannelType.DefaultChannels)
- {
- RandomThresholdImageChannel(imageRef, channel, toStringz(thresholds.toString()), DMagickExceptionInfo());
- }
- /**
- * Read an Image by reading from the file or
- * URL specified by filename.
- */
- void read(string filename)
- {
- options.filename = filename;
- MagickCoreImage* image = ReadImage(options.imageInfo, DMagickExceptionInfo());
- //Make sure a single image (frame) is read.
- if ( image.next !is null )
- {
- MagickCoreImage* nextImage;
- nextImage = image.next;
- image.next = null;
- nextImage.previous = null;
- DestroyImageList(nextImage);
- }
- imageRef = ImageRef(image);
- }
- /**
- * Read an Image by reading from the file or
- * URL specified by filename with the specified size.
- * Usefull for images that don't specify their size.
- */
- void read(string filename, Geometry size)
- {
- options.size = size;
- read(filename);
- }
- /**
- * Reads 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.
- */
- void read(void[] blob)
- {
- MagickCoreImage* image =
- BlobToImage(options.imageInfo, blob.ptr, blob.length, DMagickExceptionInfo());
- //Make sure a single image (frame) is read.
- if ( image.next !is null )
- {
- MagickCoreImage* nextImage;
- nextImage = image.next;
- image.next = null;
- nextImage.previous = null;
- DestroyImageList(nextImage);
- }
- imageRef = ImageRef(image);
- }
- ///ditto
- void read(void[] blob, Geometry size)
- {
- options.size = size;
- read(blob);
- }
- ///ditto
- void read(void[] blob, Geometry size, size_t depth)
- {
- options.size = size;
- options.depth = depth;
- read(blob);
- }
- ///ditto
- void read(void[] blob, Geometry size, size_t depth, string magick)
- {
- options.size = size;
- options.depth = depth;
- options.magick = magick;
- //Also set the filename to the image format
- options.filename = magick ~":";
- read(blob);
- }
- ///ditto
- void read(void[] blob, Geometry size, string magick)
- {
- options.size = size;
- options.magick = magick;
- //Also set the filename to the image format
- options.filename = magick ~":";
- read(blob);
- }
- /**
- * Reads an image from an array of pixels.
- *
- * Params:
- * width = The number of columns in the image.
- * height = 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.
- */
- void read(T)(size_t width, size_t height, string map, T[] pixels)
- {
- StorageType storage = getStorageType!(T);
- MagickCoreImage* image =
- ConstituteImage(width, height, toStringz(map), storage, pixels.ptr, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Smooths the contours of an image while still preserving edge
- * information. The algorithm works by replacing each pixel with its
- * neighbor closest in value.
- *
- * Params:
- * radius = A neighbor is defined by radius. Use a radius of 0
- * and reduceNoise selects a suitable radius for you.
- */
- void reduceNoise(size_t radius = 0)
- {
- static if ( is(typeof(StatisticImage)) )
- {
- MagickCoreImage* image =
- StatisticImage(imageRef, StatisticType.NonpeakStatistic, radius, radius, DMagickExceptionInfo());
- }
- else
- {
- MagickCoreImage* image =
- ReduceNoiseImage(imageRef, radius, DMagickExceptionInfo());
- }
- imageRef = ImageRef(image);
- }
- /**
- * Reduce the number of colors in img to the colors used by reference.
- * If a dither method is set then the given colors are dithered over
- * the image as necessary, otherwise the closest color
- * (in RGB colorspace) is selected to replace that pixel in the image.
- */
- void remap(Image reference)
- {
- RemapImage(options.quantizeInfo, imageRef, reference.imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Resize image in terms of its pixel size, so that when displayed at
- * the given resolution it will be the same size in terms of real world
- * units as the original image at the original resolution.
- *
- * Params:
- * xResolution = the target horizontal resolution
- * yResolution = the target vertical resolution
- * filter = The filter to use when resizing.
- * blur = Values > 1 increase the blurriness.
- * Values < 1 increase the sharpness.
- */
- void resample(
- double xResolution,
- double yResolution,
- FilterTypes filter = FilterTypes.LanczosFilter,
- double blur = 1)
- {
- MagickCoreImage* image =
- ResampleImage(imageRef, xResolution, yResolution, filter, blur, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * scales an image to the desired dimensions, using the given filter.
- *
- * Params:
- * size = The desired width and height.
- * filter = The filter to use when resizing.
- * blur = Values > 1 increase the blurriness.
- * Values < 1 increase the sharpness.
- */
- void resize(Geometry size, FilterTypes filter = FilterTypes.LanczosFilter, double blur = 1)
- {
- size = size.toAbsolute(columns, rows);
- MagickCoreImage* image =
- ResizeImage(imageRef, size.width, size.height, filter, blur, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Offsets an image as defined by xOffset and yOffset.
- */
- void roll(ssize_t xOffset, ssize_t yOffset)
- {
- MagickCoreImage* image =
- RollImage(imageRef, xOffset, yOffset, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Rotate the image by specified number of degrees. Rotated images are
- * usually larger than the originals and have 'empty' triangular corners.
- * Empty triangles left over from shearing the image are filled with the
- * background color defined by the 'backgroundColor' property
- * of the image.
- *
- * Params:
- * degrees = The number of degrees to rotate the image. Positive
- * angles rotate counter-clockwise (right-hand rule),
- * while negative angles rotate clockwise.
- */
- void rotate(double degrees)
- {
- MagickCoreImage* image =
- RotateImage(imageRef, degrees, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Applies a rotational blur to the image.
- *
- * Params:
- * angle = The angle of the rotational blur, in degrees.
- * channel = If no channels are specified, blurs all the channels.
- */
- void rotationalBlur(double angle, ChannelType channel = ChannelType.DefaultChannels)
- {
- static if ( is(typeof(RotationalBlurImage)) )
- {
- MagickCoreImage* image =
- RotationalBlurImageChannel(imageRef, channel, angle, DMagickExceptionInfo());
- }
- else
- {
- MagickCoreImage* image =
- RadialBlurImageChannel(imageRef, channel, angle, DMagickExceptionInfo());
- }
- imageRef = ImageRef(image);
- }
- /** ditto */
- alias rotationalBlur radialBlur;
- /**
- * scales an image to the desired dimensions with pixel sampling.
- * Unlike other scaling methods, this method does not introduce any
- * additional color into the scaled image.
- */
- void sample(Geometry size)
- {
- size = size.toAbsolute(columns, rows);
- MagickCoreImage* image =
- SampleImage(imageRef, size.width, size.height, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Resize image by using simple ratio algorithm.
- */
- void scale(Geometry size)
- {
- size = size.toAbsolute(columns, rows);
- MagickCoreImage* image =
- ScaleImage(imageRef, size.width, size.height, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Segments an image by analyzing the histograms of the color
- * components and identifying units that are homogeneous with the
- * fuzzy c-means technique. Also uses quantizeColorSpace and
- * verbose image properties.
- *
- * Params:
- * clusterThreshold =
- * The number of pixels in each cluster must exceed the
- * the cluster threshold to be considered valid.
- * smoothingThreshold =
- * The smoothing threshold eliminates noise in the second
- * derivative of the histogram. As the value is increased,
- * you can expect a smoother second derivative.
- */
- void segment(double clusterThreshold = 1, double smoothingThreshold = 1.5)
- {
- SegmentImage(imageRef, options.quantizeColorSpace, options.verbose, clusterThreshold, smoothingThreshold);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Selectively blur pixels within a contrast threshold.
- *
- * Params:
- * radius = The radius of the Gaussian in pixels,
- * not counting the center pixel.
- * sigma = The standard deviation of the Laplacian, in pixels.
- * threshold = Threshold level represented as a percentage
- * of the quantum range.
- * channel = The channels to blur.
- */
- void selectiveBlur(
- double radius,
- double sigma,
- double threshold,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- SelectiveBlurImageChannel(imageRef, channel, radius, sigma, threshold, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * applies a special effect to the image, similar to the effect achieved
- * in a photo darkroom by sepia toning. A threshold of 80% is a good
- * starting point for a reasonable tone.
- *
- * Params:
- * threshold = Threshold ranges from 0 to QuantumRange and is
- * a measure of the extent of the sepia toning.
- * A value lower than 1 is treated as a percentage.
- */
- void sepiatone(double threshold = QuantumRange)
- {
- if ( threshold < 1 )
- threshold *= QuantumRange;
- MagickCoreImage* image =
- SepiaToneImage(imageRef, threshold, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * shines a distant light on an image to create a three-dimensional
- * effect. You control the positioning of the light with azimuth and
- * elevation.
- *
- * Params:
- * azimuth = The amount of degrees off the X axis.
- * elevation = The amount of pixels above the Z axis.
- * shading = If true, shade shades the intensity of each pixel.
- */
- void shade(double azimuth = 30, double elevation = 30, bool shading = false)
- {
- MagickCoreImage* image =
- ShadeImage(imageRef, shading, azimuth, elevation, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Simulates a shadow from the specified image and returns it.
- * This method only works when the image has opaque parts and
- * transparent parts. Note that the resulting image is just the shadow.
- *
- * Params:
- * xOffset = The shadow x offset.
- * yOffset = The shadow y offset.
- * sigma = The standard deviation of the Gaussian operator used
- * to produce the shadow. The higher the number, the
- * "blurrier" the shadow, but the longer it takes to
- * produce the shadow.
- * opacity = The percent opacity of the shadow.
- * A number between 0.1 and 1.0
- * Returns: The shadows for this image.
- */
- Image shadowImage(ssize_t xOffset, ssize_t yOffset, double sigma = 4, double opacity = 1)
- {
- MagickCoreImage* image =
- ShadowImage(imageRef, opacity, sigma, xOffset, yOffset, DMagickExceptionInfo());
- return new Image(image);
- }
- /**
- * Sharpens an image. We convolve 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
- * sharpen 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 sharpen(double radius = 0, double sigma = 1, ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- SharpenImageChannel(imageRef, channel, radius, sigma, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Removes pixels from the edges of the image,
- * leaving the center rectangle.
- *
- * Params:
- * geometry = The region of the image to crop.
- */
- void shave(Geometry geometry)
- {
- RectangleInfo rectangle = geometry.rectangleInfo;
- MagickCoreImage* image = ShaveImage(imageRef, &rectangle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Shearing slides one edge of an image along the X or Y axis, creating
- * a parallelogram. An X direction shear slides an edge along the X axis,
- * while a Y direction shear slides an edge along the Y axis. The amount
- * of the shear is controlled by a shear angle. For X direction shears,
- * xShearAngle is measured relative to the Y axis, and similarly, for Y
- * direction shears yShearAngle is measured relative to the X axis.
- * Empty triangles left over from shearing the image are filled with
- * the background color.
- */
- void shear(double xShearAngle, double yShearAngle)
- {
- MagickCoreImage* image =
- ShearImage(imageRef, xShearAngle, yShearAngle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Adjusts the contrast of an image channel with a non-linear sigmoidal
- * contrast algorithm. Increases the contrast of the image using a
- * sigmoidal transfer function without saturating highlights or shadows.
- *
- * Params:
- * contrast = indicates how much to increase the contrast
- * (0 is none; 3 is typical; 20 is pushing it)
- * midpoint = indicates where midtones fall in the resultant
- * image (0 is white; 50% is middle-gray; 100% is black).
- * Specify an apsulute number of pixels or an
- * percentage by passing a value between 1 and 0
- * sharpen = Increase or decrease image contrast.
- * channel = The channels to adjust.
- */
- void sigmoidalContrast(
- double contrast = 3,
- double midpoint = 50,
- bool sharpen = false,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- if ( midpoint < 1 )
- midpoint *= QuantumRange;
- SigmoidalContrastImageChannel(imageRef, channel, sharpen, contrast, midpoint);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Simulates a pencil sketch. For best results start with
- * a grayscale image.
- *
- * Params:
- * radius = The radius of the Gaussian, in pixels, not counting
- * the center pixel.
- * sigma = The standard deviation of the Gaussian, in pixels.
- * angle = The angle toward which the image is sketched.
- */
- void sketch(double radius = 0, double sigma = 1, double angle = 0)
- {
- MagickCoreImage* image =
- SketchImage(imageRef, radius, sigma, angle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Applies a special effect to the image similar to the effect achieved
- * in a photo darkroom by selectively exposing areas of photo sensitive
- * paper to light.
- *
- * Params:
- * threshold = The extent of the solarization.
- * channel = The channels to adjust. Anything other than
- * ChannelType.DefaultChannels requires ImageMagick 6.8.0
- * ot higher.
- */
- void solarize(Quantum threshold, ChannelType channel = ChannelType.DefaultChannels)
- {
- static if ( is(typeof(SolarizeImageChannel)) )
- {
- SolarizeImageChannel(imageRef, channel, threshold, DMagickExceptionInfo());
- }
- else
- {
- SolarizeImage(imageRef, threshold);
- DMagickException.throwException(&(imageRef.exception));
- }
- }
- /**
- * Fills the image with the specified color or colors, starting at
- * the x,y coordinates associated with the color and using the specified
- * interpolation method.
- *
- * Params:
- * method = The method to fill in the gradient between the
- * control points.
- * args = A series of control points, and there Color.
- *
- * See_Also: $(LINK2 http://www.imagemagick.org/Usage/canvas/#sparse-color,
- * Sparse Points of Color) at Examples of ImageMagick Usage.
- */
- void sparseColor(SparseColorMethod method, Tuple!(size_t, "x", size_t, "y", Color, "color")[] args ...)
- {
- double[] argv = new double[args.length * 6];
- foreach( i, arg; args )
- {
- double[] values = argv[i*6 .. i*6+6];
- values[0] = arg.x;
- values[1] = arg.y;
- values[2] = arg.color.redQuantum / QuantumRange;
- values[3] = arg.color.greenQuantum / QuantumRange;
- values[4] = arg.color.blueQuantum / QuantumRange;
- values[5] = arg.color.opacityQuantum / QuantumRange;
- }
- MagickCoreImage* image =
- SparseColorImage(imageRef,
- ChannelType.DefaultChannels,
- method, argv.length,
- argv.ptr, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Splice the background color into the image as defined by the geometry.
- * This method is the opposite of chop.
- */
- void splice(Geometry geometry)
- {
- RectangleInfo rectangle = geometry.rectangleInfo;
- MagickCoreImage* image = SpliceImage(imageRef, &rectangle, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Randomly displaces each pixel in a block defined by the
- * radius parameter.
- */
- void spread(double radius = 3)
- {
- MagickCoreImage* image =
- SpreadImage(imageRef, radius, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Makes each pixel the min / max / median / mode / etc. of the
- * neighborhood of the specified width and height.
- *
- * Params:
- * type = The type pf statistic to apply.
- * width = The width of the pixel neighborhood.
- * height = The height of the pixel neighborhood.
- */
- void statistic()(StatisticType type, size_t width, size_t height)
- {
- static if ( is(typeof(StatisticImage)) )
- {
- MagickCoreImage* image =
- StatisticImage(imageRef, type, width, height, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- else
- {
- static assert(0, "dmagick.Image.Image.statistic requires MagickCore version >= 6.6.9");
- }
- }
- /**
- * Hides a digital watermark in the receiver. You can retrieve the
- * watermark by reading the file with the stegano: prefix, thereby
- * proving the authenticity of the file.
- *
- * The watermarked image must be saved in a lossless RGB format such
- * as MIFF, or PNG. You cannot save a watermarked image in a lossy
- * format such as JPEG or a pseudocolor format such as GIF. Once
- * written, the file must not be modified or processed in any way.
- *
- * Params:
- * watermark = An image or imagelist to be used as the watermark.
- * The watermark must be grayscale and should be
- * substantially smaller than the receiver. The recovery
- * time is proportional to the size of the watermark.
- * offset = The starting position within the receiver at which
- * the watermark will be hidden. When you retrieve the
- * watermark from the file, you must supply this value,
- * along with the width and height of the watermark, in
- * the size optional parameter to the read method.
- */
- void stegano(Image watermark, ssize_t offset)
- {
- imageRef.offset = offset;
- MagickCoreImage* image =
- SteganoImage(imageRef, watermark.imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Combines two images and produces a single image that is the composite
- * of a left and right image of a stereo pair. Special red-green stereo
- * glasses are required to view this effect.
- */
- void stereo(Image rightImage)
- {
- MagickCoreImage* image =
- StereoImage(imageRef, rightImage.imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Strips an image of all profiles and comments.
- */
- void strip()
- {
- StripImage(imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * synchronizes image properties with the image profiles. Currently
- * we only support updating the EXIF resolution and orientation.
- */
- void syncProfiles()
- {
- SyncImageProfiles(imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Swirls the pixels about the center of the image, where degrees
- * indicates the sweep of the arc through which each pixel is moved.
- * You get a more dramatic effect as the degrees move from 1 to 360.
- */
- void swirl(double degrees)
- {
- MagickCoreImage* image =
- SwirlImage(imageRef, degrees, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Changes the value of individual pixels based on the intensity of
- * each pixel compared to threshold. The result is a high-contrast,
- * two color image.
- *
- * See_Also: $(XREF Image, bilevel).
- */
- //TODO: deprecated ?
- void threshold(Quantum value)
- {
- bilevel(value);
- }
- /**
- * changes the size of an image to the given dimensions and removes
- * any associated profiles. The goal is to produce small low cost
- * thumbnail images suited for display on the Web.
- */
- void thumbnail(Geometry size)
- {
- size = size.toAbsolute(columns, rows);
- MagickCoreImage* image =
- ThumbnailImage(imageRef, size.width, size.height, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Creates a Binary Large OBject, a direct-to-memory
- * version of the image.
- *
- * if an image format is selected which is capable of supporting
- * fewer colors than the original image or quantization has been
- * requested, the original image will be quantized to fewer colors.
- * Use a copy of the original if this is a problem.
- *
- * Params:
- * magick = specifies the image format to write.
- * depth = specifies the image depth.
- */
- void[] toBlob(string magick = null, size_t depth = 0)
- {
- size_t length;
- ExceptionInfo* exceptionInfo = AcquireExceptionInfo();
- if ( magick !is null )
- this.magick = magick;
- if ( depth != 0 )
- this.depth = depth;
- string originalFilename = filename;
- filename = this.magick ~ ":";
- scope(exit) filename = originalFilename;
- void* blob = ImageToBlob(options.imageInfo, imageRef, &length, exceptionInfo);
- DMagickException.throwException(exceptionInfo);
- void[] dBlob = blob[0 .. length].dup;
- RelinquishMagickMemory(blob);
- return dBlob;
- }
- unittest
- {
- Image example = new Image(Geometry(100, 100), new Color("green"));
- example.toBlob("jpg");
- }
- /**
- * Changes the opacity value of all the pixels that match color to
- * the value specified by opacity. By default the pixel must match
- * exactly, but you can specify a tolerance level by setting the fuzz
- * attribute on the image.
- *
- * Params:
- * target = The target color.
- * opacity = The desired opacity.
- * invert = If true, all pixels outside the range
- * are set to opacity.
- */
- void transparent(Color color, Quantum opacity = TransparentOpacity, bool invert = false)
- {
- MagickPixelPacket target;
- GetMagickPixelPacket(imageRef, &target);
- setMagickPixelPacket(&target, color);
- TransparentPaintImage(imageRef, &target, opacity, invert);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Changes the opacity value associated with any pixel between low and
- * high to the value defined by opacity.
- *
- * As there is one fuzz value for the all the channels, the transparent
- * method is not suitable for the operations like chroma, where the
- * tolerance for similarity of two color components (RGB) can be
- * different, Thus we define this method take two target pixels (one
- * low and one high) and all the pixels of an image which are lying
- * between these two pixels are made transparent.
- *
- * Params:
- * low = The low end of the pixel range.
- * high = The high end of the pixel range.
- * opacity = The desired opacity.
- * invert = If true, all pixels outside the range
- * are set to opacity.
- */
- void transparentChroma(Color low, Color high, Quantum opacity = TransparentOpacity, bool invert = false)
- {
- MagickPixelPacket lowTarget;
- MagickPixelPacket highTarget;
- GetMagickPixelPacket(imageRef, &lowTarget);
- setMagickPixelPacket(&lowTarget, low);
- GetMagickPixelPacket(imageRef, &highTarget);
- setMagickPixelPacket(&highTarget, high);
- TransparentPaintImageChroma(imageRef, &lowTarget, &highTarget, opacity, invert);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Creates a horizontal mirror image by reflecting the pixels around
- * the central y-axis while rotating them by 90 degrees.
- */
- void transpose()
- {
- MagickCoreImage* image = TransposeImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Creates a vertical mirror image by reflecting the pixels around
- * the central x-axis while rotating them by 270 degrees
- */
- void transverse()
- {
- MagickCoreImage* image = TransverseImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Removes the edges that are exactly the same color as the corner
- * pixels. Use the fuzz property to make trim remove edges that are
- * nearly the same color as the corner pixels.
- */
- void trim()
- {
- MagickCoreImage* image = TrimImage(imageRef, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Constructs a new image with one pixel for each unique color in the
- * image. The new image has 1 row. The row has 1 column for each unique
- * pixel in the image.
- */
- Image uniqueColors()
- {
- MagickCoreImage* image = UniqueImageColors(imageRef, DMagickExceptionInfo());
- return new Image(image);
- }
- /**
- * Sharpens an image. We convolve 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
- * unsharpMask selects a suitable radius for you.
- *
- * Params:
- * radius = The radius of the Gaussian operator.
- * sigma = The standard deviation of the Gaussian operator.
- * amount = The percentage of the blurred image to be added
- * to the receiver, specified as a fraction between 0
- * and 1.0. A good starting value is 1.0
- * threshold = The threshold needed to apply the amount, specified
- * as a fraction between 0 and 1.0.
- * channel = The channels to sharpen.
- */
- void unsharpMask(
- double radius = 0,
- double sigma = 1,
- double amount = 1,
- double threshold = 0.05,
- ChannelType channel = ChannelType.DefaultChannels)
- {
- MagickCoreImage* image =
- UnsharpMaskImageChannel(imageRef, channel, radius, sigma, amount, threshold, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Get a view into the image. The ImageView can be used to modify
- * individual pixels of the image.
- *
- * Params:
- * area = The area accessible through the view.
- */
- dmagick.ImageView.ImageView view(Geometry area = Geometry.init )
- {
- if ( area == Geometry.init )
- {
- area.width = columns;
- area.height = rows;
- }
- return new dmagick.ImageView.ImageView(this, area);
- }
- /**
- * Gradually shades the edges of the image by transforming the pixels
- * into the background color.
- *
- * Larger values of sigma increase the blurring at the expense of
- * increased execution time. In general, radius should be larger than
- * sigma, although if radius is 0 then ImageMagick will choose a suitable
- * value. Sigma must be non-zero. Choose a very small value for sigma to
- * produce a "hard" edge.
- *
- * Params:
- * xOffset = Influences the amount of background color in the
- * horizontal dimension.
- * yOffset = Influences the amount of background color in the
- * vertical dimension.
- * radius = The radius of the pixel neighborhood.
- * sigma = The standard deviation of the Gaussian, in pixels.
- */
- void vignette(ssize_t xOffset, ssize_t yOffset, double radius = 0, double sigma = 10)
- {
- MagickCoreImage* image =
- VignetteImage(imageRef, radius, sigma, xOffset, yOffset, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Creates a "ripple" effect in the image by shifting the pixels
- * vertically along a sine wave whose amplitude and wavelength is
- * specified by the given parameters.Creates a "ripple" effect in the
- * image by shifting the pixels vertically along a sine wave whose
- * amplitude and wavelength is specified by the given parameters.
- */
- void wave(double amplitude = 25, double wavelength = 150)
- {
- MagickCoreImage* image =
- WaveImage(imageRef, amplitude, wavelength, DMagickExceptionInfo());
- imageRef = ImageRef(image);
- }
- /**
- * Forces all pixels above the threshold into white while leaving
- * all pixels below the threshold unchanged.
- *
- * Params:
- * threshold = The threshold value for red green and blue.
- * channel = One or more channels to adjust.
- */
- void whiteThreshold(Quantum threshold, ChannelType channel = ChannelType.DefaultChannels)
- {
- whiteThreshold(threshold, threshold, threshold, 0, channel);
- }
- ///ditto
- void whiteThreshold(
- 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);
- WhiteThresholdImageChannel(
- imageRef, channel, toStringz(thresholds), DMagickExceptionInfo()
- );
- }
- /**
- * Writes the image to the specified file. ImageMagick
- * determines image format from the prefix or extension.
- *
- * if an image format is selected which is capable of supporting
- * fewer colors than the original image or quantization has been
- * requested, the original image will be quantized to fewer colors.
- * Use a copy of the original if this is a problem.
- */
- void write(string filename)
- {
- this.filename = filename;
- WriteImage(options.imageInfo, imageRef);
- DMagickException.throwException(&(imageRef.exception));
- }
- /**
- * Set a flag to indicate whether or not to use alpha channel data.
- */
- void alpha(AlphaChannelType type)
- {
- SetImageAlphaChannel(imageRef, type);
- }
- ///ditto
- bool alpha() const
- {
- return GetImageAlphaChannel(imageRef) != 0;
- }
- /**
- * Number time which must expire before displaying the
- * next image in an animated sequence.
- */
- void animationDelay(Duration delay)
- {
- imageRef.delay = cast(size_t)(delay.total!"msecs"() * imageRef.ticks_per_second) / 1000;
- }
- ///ditto
- Duration animationDelay() const
- {
- return dur!"msecs"((imageRef.delay * 1000) / imageRef.ticks_per_second);
- }
- /**
- * Number of iterations to loop an animation.
- */
- void animationIterations(size_t iterations)
- {
- imageRef.iterations = iterations;
- }
- ///ditto
- size_t animationIterations() const
- {
- return imageRef.iterations;
- }
- /**
- * Set the image background color. The default is "white".
- */
- void backgroundColor(string color)
- {
- backgroundColor = new Color(color);
- }
- ///ditto
- void backgroundColor(Color color)
- {
- options.backgroundColor(color);
- imageRef.background_color = color.pixelPacket;
- }
- ///ditto
- Color backgroundColor() const
- {
- return options.backgroundColor;
- }
- /**
- * Set the image border color. The default is "#dfdfdf".
- */
- void borderColor(string color)
- {
- borderColor = new Color(color);
- }
- ///ditto
- void borderColor(Color color)
- {
- options.borderColor = color;
- imageRef.border_color = color.pixelPacket;
- }
- ///ditto
- Color borderColor() const
- {
- return options.borderColor;
- }
- /**
- * Return smallest bounding box enclosing non-border pixels.
- * The current fuzz value is used when discriminating between pixels.
- */
- Geometry boundingBox() const
- {
- RectangleInfo box = GetImageBoundingBox(imageRef, DMagickExceptionInfo());
- return Geometry(box);
- }
- /**
- * Pixel cache threshold in megabytes. Once this threshold is exceeded,
- * all subsequent pixels cache operations are to/from disk.
- * This is a static method and the attribute it sets is shared
- * by all Image objects
- */
- static void cacheThreshold(size_t threshold)
- {
- SetMagickResourceLimit(ResourceType.MemoryResource, threshold);
- }
- /**
- * returns true if any pixel in the image has been altered
- * since it was first constituted.
- */
- bool changed() const
- {
- return IsTaintImage(imageRef) != 0;
- }
- /**
- * Channel modulus depth. The channel modulus depth represents
- * the minimum number of bits required to support the channel without loss.
- * Setting the channel's modulus depth modifies the channel (i.e. discards
- * resolution) if the requested modulus depth is less than the current
- * modulus depth, otherwise the channel is not altered. There is no
- * attribute associated with the modulus depth so the current modulus
- * depth is obtained by inspecting the pixels. As a result, the depth
- * returned may be less than the most recently set channel depth.
- * Subsequent image processing may result in increasing the channel depth.
- */
- //TODO: Is this a property?
- void channelDepth(ChannelType channel, size_t depth)
- {
- SetImageChannelDepth(imageRef, channel, depth);
- }
- ///ditto
- size_t channelDepth(ChannelType channel) const
- {
- size_t depth = GetImageChannelDepth(imageRef, channel, DMagickExceptionInfo());
- return depth;
- }
- /**
- * The red, green, blue, and white-point chromaticity values.
- */
- void chromaticity(ChromaticityInfo chroma)
- {
- imageRef.chromaticity = chroma;
- }
- ///ditto
- ChromaticityInfo chromaticity() const
- {
- return imageRef.chromaticity;
- }
- /**
- * The image's storage class. If DirectClass then the pixels
- * contain valid RGB or CMYK colors. If PseudoClass then the
- * image has a colormap referenced by the pixel's index member.
- */
- void classType(ClassType type)
- {
- if ( imageRef.storage_class == ClassType.PseudoClass && type == ClassType.DirectClass )
- {
- SyncImage(imageRef);
- colormap() = null;
- }
- else if ( imageRef.storage_class == ClassType.DirectClass && type == ClassType.PseudoClass )
- {
- options.quantizeColors = MaxColormapSize;
- quantize();
- }
- imageRef.storage_class = type;
- }
- ///ditto
- ClassType classType() const
- {
- return imageRef.storage_class;
- }
- /**
- * Associate a clip mask image with the current image.
- * The clip mask image must have the same dimensions as the current
- * image or an exception is thrown. Clipping occurs wherever pixels are
- * transparent in the clip mask image. Clipping Pass an invalid image
- * to unset an existing clip mask.
- */
- void clipMask(const(Image) image)
- {
- if ( image is null )
- {
- SetImageClipMask(imageRef, null);
- return;
- }
- //Throw a chatchable exception when the size differs.
- if ( image.columns != columns || image.rows != rows )
- throw new ImageException("image size differs");
- SetImageClipMask(imageRef, image.imageRef);
- }
- ///ditto
- Image clipMask() const
- {
- MagickCoreImage* image = CloneImage(imageRef.clip_mask, 0, 0, true, DMagickExceptionInfo());
- return new Image(image);
- }
- /**
- * Access the image color map.
- * Only ClassType.PsseudoClass images have a colormap.
- * ----------------------------------
- * Color color = image.colormap[2];
- * image.colormap()[2] = color;
- * ----------------------------------
- * To asign the complete colormap at once:
- * ----------------------------------
- * Color[] colors = new Colors[255];
- * image.colormap() = colors;
- * //Or
- * image.colormap.size = 255;
- * foreach(i, color; colors)
- * image.colormap()[i] = color;
- * ----------------------------------
- * Bugs: because of dmd bug 2152 the parentheses are needed when assigning;
- */
- auto colormap()
- {
- struct Colormap
- {
- Image img;
- this(Image img)
- {
- this.img = img;
- }
- Color opIndex(uint index)
- {
- if ( index >= img.colormapSize )
- throw new Exception("Index out of bounds");
- return new Color(img.imageRef.colormap[index]);
- }
- void opIndexAssign(Color value, size_t index)
- {
- if ( index >= img.colormapSize )
- throw new Exception("Index out of bounds");
- img.imageRef.colormap[index] = value.pixelPacket;
- }
- void opAssign(Color[] colors)
- {
- img.colormapSize = colors.length;
- if ( colors.length == 0 )
- return;
- foreach(i, color; colors)
- this[i] = color;
- }
- void opOpAssign(string op)(Color color) if ( op == "~" )
- {
- img.colormapSize = img.colormapSize + 1;
- this[img.colormapSize] = color;
- }
- void opOpAssign(string op)(Color[] colors) if ( op == "~" )
- {
- uint oldSize = img.colormapSize;
- img.colormapSize = oldSize + colors.length;
- foreach ( i; oldSize..img.colormapSize)
- this[i] = colors[i];
- }
- /**
- * compresses the colormap by removing any
- * duplicate or unused color entries.
- */
- void compress()
- {
- CompressImageColormap(img.imageRef);
- DMagickException.throwException(&(img.imageRef.exception));
- }
- size_t size()
- {
- return img.colormapSize;
- }
- void size(size_t s)
- {
- img.colormapSize = s;
- }
- }
- return Colormap(this);
- }
- /**
- * The number of colors in the colormap. Only meaningful for PseudoClass images.
- *
- * Setting the colormap size may extend or truncate the colormap.
- * The maximum number of supported entries is specified by the
- * MaxColormapSize constant, and is dependent on the value of
- * QuantumDepth when ImageMagick is compiled. An exception is thrown
- * if more entries are requested than may be supported.
- * Care should be taken when truncating the colormap to ensure that
- * the image colormap indexes reference valid colormap entries.
- */
- void colormapSize(size_t size)
- {
- if ( size > MaxColormapSize )
- throw new OptionException(
- "the size of the colormap can't exceed MaxColormapSize");
- if ( size == 0 && imageRef.colors > 0 )
- {
- imageRef.colormap = cast(PixelPacket*)RelinquishMagickMemory( imageRef.colormap );
- imageRef.colors = 0;
- return;
- }
- if ( imageRef.colormap is null )
- {
- AcquireImageColormap(imageRef, size);
- imageRef.colors = 0;
- }
- else
- {
- imageRef.colormap = cast(PixelPacket*)
- ResizeMagickMemory(imageRef.colormap, size * PixelPacket.sizeof);
- }
- //Initialize the colors as black.
- foreach ( i; imageRef.colors .. size )
- {
- imageRef.colormap[i].blue = 0;
- imageRef.colormap[i].green = 0;
- imageRef.colormap[i].red = 0;
- imageRef.colormap[i].opacity = 0;
- }
- imageRef.colors = size;
- }
- ///ditto
- size_t colormapSize() const
- {
- return imageRef.colors;
- }
- /**
- * The colorspace used to represent the image pixel colors.
- * Image pixels are always stored as RGB(A) except for the case of CMY(K).
- */
- void colorspace(ColorspaceType type)
- {
- TransformImageColorspace(imageRef, type);
- options.colorspace = type;
- }
- ///ditto
- ColorspaceType colorspace() const
- {
- return imageRef.colorspace;
- }
- /**
- * The width of the image in pixels.
- */
- size_t columns() const
- {
- return imageRef.columns;
- }
- /**
- * Composition operator to be used when composition is
- * implicitly used (such as for image flattening).
- */
- void compose(CompositeOperator op)
- {
- imageRef.compose = op;
- }
- ///ditto
- CompositeOperator compose() const
- {
- return imageRef.compose;
- }
- /**
- * The image compression type. The default is the
- * compression type of the specified image file.
- */
- void compression(CompressionType type)
- {
- imageRef.compression = type;
- options.compression = type;
- }
- ///ditto
- CompressionType compression() const
- {
- return imageRef.compression;
- }
- /**
- * The vertical and horizontal resolution in pixels of the image.
- * This option specifies an image density when decoding
- * a Postscript or Portable Document page.
- *
- * The default is "72x72".
- */
- void density(Geometry value)
- {
- options.density = value;
- imageRef.x_resolution = value.width;
- imageRef.y_resolution = ( value.width != 0 ) ? value.width : value.height;
- }
- ///ditto
- Geometry density() const
- {
- ssize_t width = cast(ssize_t)rndtol(imageRef.x_resolution);
- ssize_t height = cast(ssize_t)rndtol(imageRef.y_resolution);
- return Geometry(width, height);
- }
- /**
- * Image depth. Used to specify the bit depth when reading or writing
- * raw images or when the output format supports multiple depths.
- * Defaults to the quantum depth that ImageMagick is compiled with.
- */
- void depth(size_t value)
- {
- if ( value > MagickQuantumDepth)
- value = MagickQuantumDepth;
- imageRef.depth = value;
- options.depth = value;
- }
- ///ditto
- size_t depth() const
- {
- return imageRef.depth;
- }
- /**
- * Tile names from within an image montage.
- * Only valid after calling montage or reading a MIFF file
- * which contains a directory.
- */
- string directory() const
- {
- return to!(string)(imageRef.directory);
- }
- /**
- * Specify (or obtain) endian option for formats which support it.
- */
- void endian(EndianType type)
- {
- imageRef.endian = type;
- options.endian = type;
- }
- ///ditto
- EndianType endian() const
- {
- return imageRef.endian;
- }
- /**
- * The EXIF profile.
- */
- void exifProfile(void[] blob)
- {
- StringInfo* profile = AcquireStringInfo(blob.length);
- SetStringInfoDatum(profile, cast(ubyte*)blob.ptr);
- SetImageProfile(imageRef, "exif", profile);
- DestroyStringInfo(profile);
- }
- ///ditto
- void[] exifProfile() const
- {
- const(StringInfo)* profile = GetImageProfile(imageRef, "exif");
- if ( profile is null )
- return null;
- return GetStringInfoDatum(profile)[0 .. GetStringInfoLength(profile)].dup;
- }
- /**
- * The image filename.
- */
- void filename(string str)
- {
- copyString(imageRef.filename, str);
- options.filename = str;
- }
- ///ditto
- string filename() const
- {
- return imageRef.filename[0 .. strlen(imageRef.filename.ptr)].idup;
- }
- /**
- * The image filesize in bytes.
- */
- MagickSizeType fileSize() const
- {
- return GetBlobSize(imageRef);
- }
- /**
- * Filter to use when resizing image. The reduction filter employed
- * has a significant effect on the time required to resize an image
- * and the resulting quality. The default filter is Lanczos which has
- * been shown to produce high quality results when reducing most images.
- */
- void filter(FilterTypes type)
- {
- imageRef.filter = type;
- }
- ///ditto
- FilterTypes filter() const
- {
- return imageRef.filter;
- }
- /**
- * The image encoding format. For example, "GIF" or "PNG".
- */
- string format() const
- {
- const(MagickInfo)* info = GetMagickInfo(imageRef.magick.ptr, DMagickExceptionInfo());
- return to!(string)( info.description );
- }
- /**
- * Colors within this distance are considered equal.
- * A number of algorithms search for a target color.
- * By default the color must be exact. Use this option to match
- * colors that are close to the target color in RGB space.
- */
- void fuzz(double f)
- {
- options.fuzz = f;
- imageRef.fuzz = f;
- }
- ///ditto
- double fuzz() const
- {
- return options.fuzz;
- }
- /**
- * Gamma level of the image. The same color image displayed on
- * two different workstations may look different due to differences
- * in the display monitor. Use gamma correction to adjust for this
- * color difference.
- */
- double gamma() const
- {
- return imageRef.gamma;
- }
- /**
- * Preferred size of the image when encoding.
- */
- void geometry(string str)
- {
- copyString(imageRef.geometry, str);
- }
- ///ditto
- void geometry(Geometry value)
- {
- geometry(value.toString());
- }
- ///ditto
- Geometry geometry() const
- {
- return Geometry( to!(string)(imageRef.geometry) );
- }
- /**
- * GIF disposal method. This attribute is used to control how
- * successive images are rendered (how the preceding image
- * is disposed of) when creating a GIF animation.
- */
- void gifDisposeMethod(DisposeType type)
- {
- imageRef.dispose = type;
- }
- ///ditto
- DisposeType gifDisposeMethod() const
- {
- return imageRef.dispose;
- }
- /**
- * Returns true if all the pixels in the image have the same red,
- * green, and blue intensities.
- */
- bool gray()
- {
- return dmagick.c.attribute.IsGrayImage(imageRef, DMagickExceptionInfo()) == 1;
- }
- /**
- * Computes the number of times each unique color appears in the image.
- * You may want to quantize the image before using this property.
- *
- * Returns: A associative array. Each key reprecents a color in the Image.
- * The value is the number of times the color apears in the image.
- */
- MagickSizeType[Color] histogram() const
- {
- size_t count;
- MagickSizeType[Color] hashMap;
- ColorPacket* colorPackets;
- colorPackets = GetImageHistogram(imageRef, &count, DMagickExceptionInfo());
- foreach ( packet; colorPackets[0 .. count] )
- {
- hashMap[new Color(packet.pixel)] = packet.count;
- }
- RelinquishMagickMemory(colorPackets);
- return hashMap;
- }
- /**
- * ICC color profile.
- */
- void iccColorProfile(void[] blob)
- {
- profile("icm", blob);
- }
- ///ditto
- void[] iccColorProfile() const
- {
- return profile("icm");
- }
- /**
- * Specify the _type of interlacing scheme for raw image formats
- * such as RGB or YUV. NoInterlace means do not _interlace,
- * LineInterlace uses scanline interlacing, and PlaneInterlace
- * uses plane interlacing. PartitionInterlace is like PlaneInterlace
- * except the different planes are saved to individual files
- * (e.g. image.R, image.G, and image.B). Use LineInterlace or
- * PlaneInterlace to create an interlaced GIF or
- * progressive JPEG image. The default is NoInterlace.
- */
- void interlace(InterlaceType type)
- {
- imageRef.interlace = type;
- options.interlace = type;
- }
- ///ditto
- InterlaceType interlace() const
- {
- return imageRef.interlace;
- }
- /**
- * The International Press Telecommunications Council profile.
- */
- void iptcProfile(void[] blob)
- {
- profile("iptc", blob);
- }
- ///ditto
- void[] iptcProfile() const
- {
- return profile("iptc");
- }
- /**
- * Image format (e.g. "GIF")
- */
- void magick(string str)
- {
- copyString(imageRef.magick, str);
- options.magick = str;
- }
- ///ditto
- string magick() const
- {
- if ( imageRef.magick[0] !is '\0' )
- {
- return imageRef.magick[0 .. strlen(imageRef.magick.ptr)].idup;
- }
- return options.magick;
- }
- /**
- * Set the image transparent color. The default is "#bdbdbd".
- */
- void matteColor(string color)
- {
- matteColor = new Color(color);
- }
- ///ditto
- void matteColor(Color color)
- {
- imageRef.matte_color = color.pixelPacket;
- options.matteColor = color;
- }
- ///ditto
- Color matteColor() const
- {
- return new Color(imageRef.matte_color);
- }
- /**
- * The mean error per pixel computed when an image is color reduced.
- * This parameter is only valid if verbose is set to true and the
- * image has just been quantized.
- */
- double meanErrorPerPixel() const
- {
- return imageRef.error.mean_error_per_pixel;
- }
- /**
- * Image modulus depth (minimum number of bits required to
- * support red/green/blue components without loss of accuracy).
- * The pixel modulus depth may be decreased by supplying a value
- * which is less than the current value, updating the pixels
- * (reducing accuracy) to the new depth. The pixel modulus depth
- * can not be increased over the current value using this method.
- */
- void modulusDepth(size_t depth)
- {
- SetImageDepth(imageRef, depth);
- options.depth = depth;
- }
- ///ditto
- size_t modulusDepth() const
- {
- size_t depth = GetImageDepth(imageRef, DMagickExceptionInfo());
- return depth;
- }
- /**
- * Establish a progress monitor. Most Image and ImageList methods
- * will periodically call the monitor with arguments indicating the
- * progress of the method.
- *
- * The delegate receves the folowing $(B parameters): $(BR)
- * $(TABLE
- * $(ROW string $(I methodName), The name of the monitored method.)
- * $(ROW long $(I offset ), A number between 0 and extent that
- * identifies how much of the operation has been completed
- * (or, in some cases, remains to be completed).)
- * $(ROW ulong $(I extent ), The number of quanta needed to
- * complete the operation.)
- * )
- */
- void monitor(bool delegate(string methodName, long offset, ulong extent) progressMonitor)
- {
- if ( this.progressMonitor is null )
- SetImageProgressMonitor(imageRef, cast(MagickProgressMonitor)&ImageProgressMonitor, cast(void*)this);
- this.progressMonitor = progressMonitor;
- if ( progressMonitor is null )
- SetImageProgressMonitor(imageRef, null, null);
- }
- ///ditto
- bool delegate(string, long, ulong) monitor()
- {
- return progressMonitor;
- }
- static extern(C) MagickBooleanType ImageProgressMonitor(
- const(char)* methodName,
- MagickOffsetType offset,
- MagickSizeType extend,
- Image image)
- {
- return image.progressMonitor(to!(string)(methodName), offset, extend);
- }
- /**
- * Tile size and offset within an image montage.
- * Only valid for images produced by montage.
- */
- Geometry montageGeometry() const
- {
- return Geometry( to!(string)(imageRef.geometry) );
- }
- /**
- * The normalized max error per pixel computed when
- * an image is color reduced. This parameter is only
- * valid if verbose is set to true and the image
- * has just been quantized.
- */
- double normalizedMaxError() const
- {
- return imageRef.error.normalized_maximum_error;
- }
- /**
- * The normalized mean error per pixel computed when
- * an image is color reduced. This parameter is only
- * valid if verbose is set to true and the image
- * has just been quantized.
- */
- double normalizedMeanError() const
- {
- return imageRef.error.normalized_mean_error;
- }
- /**
- * Sets the value of the image property. An image may have any number
- * of properties. ImageMagick predefines some properties, including
- * attribute, label, caption, comment, signature, and in some cases EXIF.
- */
- void opDispatch(string property)(string value)
- if ( property != "popFront" )
- {
- SetImageProperty(imageRef, toStringz(property), toStringz(value));
- return;
- }
- /**
- * Returns the value of the image property.
- */
- auto opDispatch(string property)()
- if ( property != "popFront" )
- {
- return to!(string)(GetImageProperty(imageRef, toStringz(property)));
- }
- unittest
- {
- Image image = new Image();
- image.comment = "unittest";
- assert(image.comment == "unittest");
- }
- /**
- * Image orientation. Supported by some file formats
- * such as DPX and TIFF. Useful for turning the right way up.
- */
- void orientation(OrientationType orientation)
- {
- imageRef.orientation = orientation;
- }
- ///ditto
- OrientationType orientation() const
- {
- return imageRef.orientation;
- }
- /**
- * When compositing, this attribute describes the position
- * of this image with respect to the underlying image.
- *
- * Use this option to specify the dimensions and position of
- * the Postscript page in dots per inch or a TEXT page in pixels.
- * This option is typically used in concert with density.
- *
- * Page may also be used to position a GIF image
- * (such as for a scene in an animation).
- */
- void page(Geometry geometry)
- {
- options.page = geometry;
- imageRef.page = geometry.rectangleInfo;
- }
- ///ditto
- Geometry page() const
- {
- return Geometry(imageRef.page);
- }
- /**
- * The pixel color interpolation method. Some methods (such
- * as wave, swirl, implode, and composite) use the pixel color
- * interpolation method to determine how to blend adjacent pixels.
- */
- void pixelInterpolationMethod(InterpolatePixelMethod method)
- {
- imageRef.interpolate = method;
- }
- ///ditto
- InterpolatePixelMethod pixelInterpolationMethod() const
- {
- return imageRef.interpolate;
- }
- /**
- * Get/set/remove a named profile. Valid names include "*",
- * "8BIM", "ICM", "IPTC", or a user/format-defined profile name.
- */
- void profile(string name, void[] blob)
- {
- ProfileImage(imageRef, toStringz(name), blob.ptr, blob.length, false);
- }
- ///ditto
- void[] profile(string name) const
- {
- const(StringInfo)* profile = GetImageProfile(imageRef, toStringz(name));
- if ( profile is null )
- return null;
- return GetStringInfoDatum(profile)[0 .. GetStringInfoLength(profile)].dup;
- }
- /**
- * JPEG/MIFF/PNG compression level (default 75).
- */
- void quality(size_t quality)
- {
- imageRef.quality = quality;
- options.quality = quality;
- }
- ///ditto
- size_t quality() const
- {
- return imageRef.quality;
- }
- /**
- * The type of rendering intent.
- * See_Also:
- * $(LINK http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm)
- */
- void renderingIntent(RenderingIntent intent)
- {
- imageRef.rendering_intent = intent;
- }
- ///ditto
- RenderingIntent renderingIntent() const
- {
- return imageRef.rendering_intent;
- }
- /**
- * Units of image resolution
- */
- void resolutionUnits(ResolutionType type)
- {
- imageRef.units = type;
- options.resolutionUnits = type;
- }
- ///ditto
- ResolutionType resolutionUnits() const
- {
- return options.resolutionUnits;
- }
- /**
- * The scene number assigned to the image the last
- * time the image was written to a multi-image image file.
- */
- void scene(size_t value)
- {
- imageRef.scene = value;
- }
- ///ditto
- size_t scene() const
- {
- return imageRef.scene;
- }
- /**
- * The height of the image in pixels.
- */
- size_t rows() const
- {
- return imageRef.rows;
- }
- /**
- * Width and height of a image.
- */
- Geometry size() const
- {
- return Geometry(imageRef.columns, imageRef.rows);
- }
- /**
- * Number of colors in the image.
- */
- size_t totalColors() const
- {
- size_t colors = GetNumberColors(imageRef, null, DMagickExceptionInfo());
- return colors;
- }
- /**
- * Image type.
- */
- void type(ImageType imageType)
- {
- options.type = imageType;
- SetImageType(imageRef, imageType);
- }
- ///ditto
- ImageType type() const
- {
- if (options.type != ImageType.UndefinedType )
- return options.type;
- ImageType imageType = GetImageType(imageRef, DMagickExceptionInfo());
- return imageType;
- }
- /**
- * Specify how "virtual pixels" behave. Virtual pixels are
- * pixels that are outside the boundaries of the image.
- * Methods such as blurImage, sharpen, and wave use virtual pixels.
- */
- void virtualPixelMethod(VirtualPixelMethod method)
- {
- options.virtualPixelMethod = method;
- SetImageVirtualPixelMethod(imageRef, method);
- }
- ///ditto
- VirtualPixelMethod virtualPixelMethod() const
- {
- return GetImageVirtualPixelMethod(imageRef);
- }
- /**
- * Horizontal resolution of the image.
- */
- double xResolution() const
- {
- return imageRef.x_resolution;
- }
- /**
- * Vertical resolution of the image.
- */
- double yResolution() const
- {
- return imageRef.y_resolution;
- }
- private void setMagickPixelPacket(MagickPixelPacket* magick, Color color)
- {
- magick.red = color.redQuantum;
- magick.green = color.greenQuantum;
- magick.blue = color.blueQuantum;
- magick.opacity = color.opacityQuantum;
- }
- private string wordWrap(string text, Geometry boundingBox)
- {
- size_t pos;
- string[] lines;
- if ( text.empty )
- return text;
- double lineHeight = getTypeMetrics([text[0]]).height;
- size_t maxLines = cast(size_t)(boundingBox.height / lineHeight);
- while ( !text.empty )
- {
- for ( size_t i; i < text.length; i++ )
- {
- if ( isWhite(text[i]) || i == text.length-1 )
- {
- TypeMetric metric = getTypeMetrics(text[0..i]);
- if ( metric.width > boundingBox.width )
- {
- if ( pos == 0 )
- pos = i;
- break;
- }
- pos = i;
- if ( text[i] == '\n' )
- break;
- if ( i == text.length-1 )
- pos++;
- }
- }
- lines ~= text[0 .. pos].strip();
- text = text[min(pos+1, text.length) .. $];
- pos = 0;
- if ( lines.length == maxLines )
- break;
- }
- return join(lines, "\n");
- }
- unittest
- {
- Image img = new Image(Geometry(200, 200), new Color());
- img.options.font = "/usr/share/fonts/TTF/DejaVuSans.ttf";
- string wraped = img.wordWrap("Lorem ipsum dolor sit amet.", Geometry(100, 200));
- assert(wraped == "Lorem ipsum\ndolor sit amet.");
- }
- private template getStorageType(T)
- {
- static if ( is( T == byte) )
- {
- enum getStorageType = StorageType.CharPixel;
- }
- else static if ( is( T == short) )
- {
- enum getStorageType = StorageType.ShortPixel;
- }
- else static if ( is( T == int) )
- {
- enum getStorageType = StorageType.IntegerPixel;
- }
- else static if ( is( T == long) )
- {
- enum getStorageType = StorageType.LongPixel;
- }
- else static if ( is( T == float) )
- {
- enum getStorageType = StorageType.FloatPixel;
- }
- else static if ( is( T == double) )
- {
- enum getStorageType = StorageType.DoublePixel;
- }
- else
- {
- static assert(false, "Unsupported type");
- }
- }
- unittest
- {
- StorageType storage = getStorageType!(int);
- assert( storage == StorageType.IntegerPixel );
- }
- }
- /*
- * Initialize ImageMagick, causes an access violation on Windows.
- */
- version (Posix)
- {
- shared static this()
- {
- MagickCoreGenesis(null, false);
- }
- shared static ~this()
- {
- MagickCoreTerminus();
- }
- }