1 /**
2  * A class to expose ImageInfo QuantizeInfo and DrawInfo
3  *
4  * Copyright: Mike Wey 2011
5  * License:   zlib (See accompanying LICENSE file)
6  * Authors:   Mike Wey
7  */
8 
9 module dmagick.Options;
10 
11 import std.conv;
12 import std.math;
13 import std.string;
14 import core.stdc.stdio;
15 import core.stdc.string;
16 
17 import dmagick.Color;
18 import dmagick.Geometry;
19 import dmagick.Image;
20 import dmagick.Utils;
21 
22 import dmagick.c.cacheView;
23 import dmagick.c.colorspace;
24 import dmagick.c.compress;
25 import dmagick.c.draw;
26 import dmagick.c.geometry;
27 import dmagick.c.image;
28 import dmagick.c.list;
29 import dmagick.c.magickType;
30 import dmagick.c.memory;
31 import dmagick.c.option;
32 import dmagick.c.quantize;
33 import dmagick.c.quantum;
34 import dmagick.c.type;
35 
36 /// See_Also: $(CXREF quantize, _DitherMethod)
37 public alias dmagick.c.quantize.DitherMethod DitherMethod;
38 
39 //These symbols are publicly imported by dmagick.Image.
40 private alias dmagick.c.geometry.AffineMatrix AffineMatrix;
41 private alias dmagick.c.colorspace.ColorspaceType ColorspaceType;
42 private alias dmagick.c.compress.CompressionType CompressionType;
43 private alias dmagick.c.quantum.EndianType EndianType;
44 private alias dmagick.c.image.ImageType ImageType;
45 private alias dmagick.c.image.InterlaceType InterlaceType;
46 private alias dmagick.c.image.ResolutionType ResolutionType;
47 private alias dmagick.c.cacheView.VirtualPixelMethod VirtualPixelMethod;
48 
49 /**
50  * A class that wraps ImageInfo, DrawInfo and QuantizeInfo
51  */
52 class Options
53 {
54 	ImageInfo*    imageInfo;
55 	QuantizeInfo* quantizeInfo;
56 	DrawInfo*     drawInfo;
57 
58 	this()
59 	{
60 		imageInfo = cast(ImageInfo*)AcquireMagickMemory(ImageInfo.sizeof);
61 		quantizeInfo = cast(QuantizeInfo*)AcquireMagickMemory(QuantizeInfo.sizeof);
62 		drawInfo = cast(DrawInfo*)AcquireMagickMemory(DrawInfo.sizeof);
63 
64 		//Initialize with defaults.
65 		GetImageInfo(imageInfo);
66 		GetDrawInfo(imageInfo, drawInfo);
67 		GetQuantizeInfo(quantizeInfo);
68 
69 		//In D strings are UTF encoded.
70 		textEncoding("UTF-8");
71 	}
72 
73 	this(const(ImageInfo)* imageInfo, const(QuantizeInfo)* quantizeInfo, const(DrawInfo)* drawInfo)
74 	{
75 		this.imageInfo = CloneImageInfo(imageInfo);
76 		this.quantizeInfo = CloneQuantizeInfo(quantizeInfo);
77 		this.drawInfo = CloneDrawInfo(imageInfo, drawInfo);
78 	}
79 
80 	~this()
81 	{
82 		imageInfo = DestroyImageInfo(imageInfo);
83 		quantizeInfo = DestroyQuantizeInfo(quantizeInfo);
84 		drawInfo = DestroyDrawInfo(drawInfo);
85 	}
86 
87 	Options clone() const
88 	{
89 		return new Options(imageInfo, quantizeInfo, drawInfo);
90 	}
91 
92 	/+***************************************************************
93 	 * ImageInfo fields
94 	 ***************************************************************+/
95 
96 	/**
97 	 * Join images into a single multi-image file.
98 	 */
99 	void adjoin(bool flag)
100 	{
101 		imageInfo.adjoin = flag;
102 	}
103 	///ditto
104 	bool adjoin() const
105 	{
106 		return imageInfo.adjoin == 1;
107 	}
108 
109 	/**
110 	 * Set the image background color. The default is "white".
111 	 */
112 	void backgroundColor(string color)
113 	{
114 		backgroundColor = new Color(color);
115 	}
116 	///ditto	
117 	void backgroundColor(Color color)
118 	{
119 		imageInfo.background_color = color.pixelPacket;	
120 	}
121 	///ditto
122 	Color backgroundColor() const
123 	{
124 		return new Color(imageInfo.background_color);
125 	}
126 
127 	/**
128 	 * Set a texture to tile onto the image background.
129 	 * Corresponds to the -texture option to ImageMagick's
130 	 * convert and mogrify commands.
131 	 */
132 	void backgroundTexture(string str)
133 	{
134 		copyString(imageInfo.texture, str);
135 	}
136 	///ditto
137 	string backgroundTexture() const
138 	{
139 		return to!(string)(imageInfo.texture);
140 	}
141 
142 	/**
143 	 * Set the image border color. The default is "#dfdfdf".
144 	 */
145 	void borderColor(string color)
146 	{
147 		borderColor = new Color(color);
148 	}
149 	///ditto
150 	void borderColor(Color color)
151 	{
152 		imageInfo.border_color = color.pixelPacket;
153 		drawInfo.border_color = color.pixelPacket;
154 	}
155 	///ditto
156 	Color borderColor() const
157 	{
158 		return new Color(imageInfo.border_color);
159 	}
160 
161 	/**
162 	 * Specifies the image pixel interpretation.
163 	 */
164 	void colorspace(ColorspaceType space)
165 	{
166 		imageInfo.colorspace = space;
167 	}
168 	///ditto
169 	ColorspaceType colorspace() const
170 	{
171 		return imageInfo.colorspace;
172 	}
173 
174 	/**
175 	 * Specifies the type of _compression used when writing the image.
176 	 * Only some image formats support _compression. For those that do,
177 	 * only some _compression types are supported. If you specify an
178 	 * _compression type that is not supported, the default _compression
179 	 * type (usually NoCompression) is used instead.
180 	 */
181 	void compression(CompressionType compress)
182 	{
183 		imageInfo.compression = compress;
184 	}
185 	///ditto
186 	CompressionType compression() const
187 	{
188 		return imageInfo.compression;
189 	}
190 
191 	//void ddebug(bool d)
192 	//{
193 	//
194 	//}
195 	//ditto
196 	//bool ddebug()
197 	//{
198 	//
199 	//}
200 
201 	/**
202 	 * Define an option. Use this method to set options for
203 	 * reading or writing certain image formats. The list of
204 	 * supported options changes from release to release.
205 	 * For a list of the valid image formats, keys, and values,
206 	 * refer to the documentation for the -define option for the
207 	 * release of ImageMagick installed on your system.
208 	 * Params:
209 	 *     format = An image format name such as "ps" or "tiff".
210 	 *     key    = A string that identifies the option.
211 	 *     vaule  = The value of the option.
212 	 */
213 	void define(string format, string key, string value = "")
214 	{
215 		string option = format ~":"~ key ~ "\0";
216 
217 		SetImageOption(imageInfo, option.ptr, toStringz(value));
218 	}
219 
220 	//TODO: opindex / opiindexassign for the options.
221 
222 	/**
223 	 * Delete an option definition set by define.
224 	 * This is not the same as setting the option to a null value.
225 	 * The undefine method removes the option name from the list
226 	 * of options for the specified format.
227 	 *     format = An image format name such as "ps" or "tiff".
228 	 *     key    = A string that identifies the option.
229 	 */
230 	void undefine(string format, string key)
231 	{
232 		string option = format ~":"~ key ~ "\0";
233 
234 		DeleteImageOption(imageInfo, option.ptr);
235 	}
236 
237 	/**
238 	 * Specifies the vertical and horizontal resolution in pixels.
239 	 * The default _density is "72.0x72.0". This attribute can be used
240 	 * when writing JBIG, PCL, PS, PS2, and PS3 format images.
241 	 * 
242 	 * This attribute can also be used to specify the width and height
243 	 * of HISTOGRAM format images. For HISTOGRAM, the default is 256x200.
244 	 */
245 	void density(string str)
246 	{
247 		copyString(imageInfo.density, str);
248 	}
249 	///ditto
250 	void density(Geometry geometry)
251 	{
252 		density(geometry.toString());
253 	}
254 	///ditto
255 	Geometry density() const
256 	{
257 		return Geometry( to!(string)(imageInfo.density) );
258 	}
259 
260 	/**
261 	 * Specifies the image _depth
262 	 * 
263 	 * Either 8, 16, or 32. You can specify 16 and 32
264 	 * only when ImageMagick was compiled with a QuantumDepth
265 	 * that allows these _depth values.
266 	 */
267 	void depth(size_t d)
268 	{
269 		imageInfo.depth = d;
270 	}
271 	///ditto
272 	size_t depth() const
273 	{
274 		return imageInfo.depth;
275 	}
276 
277 	/**
278 	 * This attribute can be used when writing GIF images.
279 	 * 
280 	 * Apply Floyd/Steinberg error diffusion to the image.
281 	 * The basic strategy of dithering is to trade intensity
282 	 * resolution for spatial resolution by averaging the intensities
283 	 * of several neighboring pixels. Images which suffer from severe
284 	 * contouring when reducing colors can be improved with this option.
285 	 */
286 	void dither(bool d)
287 	{
288 		imageInfo.dither = d;
289 		quantizeInfo.dither = d;
290 	}
291 	///ditto
292 	size_t dither() const
293 	{
294 		return imageInfo.dither;
295 	}
296 
297 	/**
298 	 * Specify the endianess of the image when reading the image file.
299 	 */
300 	void endian(EndianType type)
301 	{
302 		imageInfo.endian = type;
303 	}
304 	///ditto
305 	EndianType endian() const
306 	{
307 		return imageInfo.endian;
308 	}
309 
310 	/**
311 	 * Image _file descriptor.
312 	 */
313 	void file(FILE* f)
314 	{
315 		imageInfo.file = f;
316 	}
317 	///ditto
318 	FILE* file()
319 	{
320 		return imageInfo.file;
321 	}
322 
323 	/**
324 	 * Image _filename/path.
325 	 */
326 	void filename(string str)
327 	{
328 		copyString(imageInfo.filename, str);
329 	}
330 	///ditto
331 	string filename() const
332 	{
333 		return imageInfo.filename[0 .. strlen(imageInfo.filename.ptr)].idup;
334 	}
335 
336 	/**
337 	 * The _font name or filename.
338 	 * You can tag a _font to specify whether it is a Postscript,
339 	 * Truetype, or OPTION1 _font. For example, Arial.ttf is a
340 	 * Truetype _font, ps:helvetica is Postscript, and x:fixed is OPTION1.
341 	 * 
342 	 * The _font name can be a complete filename such as
343 	 * "/mnt/windows/windows/fonts/Arial.ttf". The _font name can
344 	 * also be a fully qualified X font name such as
345 	 * "-urw-times-medium-i-normal--0-0-0-0-p-0-iso8859-13".
346 	 */
347 	void font(string str)
348 	{
349 		copyString(imageInfo.font, str);
350 		copyString(drawInfo.font, str);
351 	}
352 	///ditto
353 	string font() const
354 	{
355 		return to!(string)(drawInfo.font);
356 	}
357 
358 	/**
359 	 * Text rendering font point size
360 	 */
361 	void fontSize(double size)
362 	{
363 		imageInfo.pointsize = size;
364 		drawInfo.pointsize = size;
365 	}
366 	///ditto
367 	double fontSize() const
368 	{
369 		return drawInfo.pointsize;
370 	}
371 
372 	/**
373 	 * Colors within this distance are considered equal. 
374 	 * A number of algorithms search for a target  color.
375 	 * By default the color must be exact. Use this option to match
376 	 * colors that are close to the target color in RGB space.
377 	 */
378 	void fuzz(double f)
379 	{
380 		imageInfo.fuzz = f;
381 	}
382 	///ditto
383 	double fuzz() const
384 	{
385 		return imageInfo.fuzz;
386 	}
387 
388 	/**
389 	 * Specify the _type of interlacing scheme for raw image formats
390 	 * such as RGB or YUV. NoInterlace means do not _interlace,
391 	 * LineInterlace uses scanline interlacing, and PlaneInterlace
392 	 * uses plane interlacing. PartitionInterlace is like PlaneInterlace
393 	 * except the different planes are saved to individual files
394 	 * (e.g. image.R, image.G, and image.B). Use LineInterlace or
395 	 * PlaneInterlace to create an interlaced GIF or
396 	 * progressive JPEG image. The default is NoInterlace.
397 	 */
398 	void interlace(InterlaceType type)
399 	{
400 		imageInfo.interlace = type;
401 	}
402 	///ditto
403 	InterlaceType interlace() const
404 	{
405 		return imageInfo.interlace;
406 	}
407 
408 	/**
409 	 * Image format (e.g. "GIF")
410 	 */
411 	void magick(string str)
412 	{
413 		copyString(imageInfo.magick, str);
414 	}
415 	///ditto
416 	string magick() const
417 	{
418 		return imageInfo.magick[0 .. strlen(imageInfo.magick.ptr)].idup;
419 	}
420 
421 	/**
422 	 * Set the image transparent color. The default is "#bdbdbd".
423 	 */
424 	void matteColor(string color)
425 	{
426 		matteColor = new Color(color);
427 	}
428 	///ditto
429 	void matteColor(Color color)
430 	{
431 		imageInfo.matte_color = color.pixelPacket;
432 	}
433 	///ditto
434 	Color matteColor() const
435 	{
436 		return new Color(imageInfo.matte_color);
437 	}
438 
439 	/**
440 	 * Transform the image to black and white on input.
441 	 * Only the EPT, PDF, and PS formats respect this attribute.
442 	 */
443 	void monochrome(bool m)
444 	{
445 		imageInfo.monochrome = m;
446 	}
447 	///ditto
448 	bool monochrome() const
449 	{
450 		return imageInfo.monochrome == 1;
451 	}
452 
453 	/**
454 	 * Use this option to specify the dimensions and position
455 	 * of the Postscript _page in dots per inch or in pixels.
456 	 * This option is typically used in concert with density.
457 	 * 
458 	 * Page may also be used to position a GIF image
459 	 * (such as for a scene in an animation)
460 	 * The default is "612x792"
461 	 */
462 	void page(string str)
463 	{
464 		copyString(imageInfo.page, str);
465 	}
466 	///ditto
467 	void page(Geometry geometry)
468 	{
469 		page(geometry.toString());
470 	}
471 	///ditto
472 	Geometry page() const
473 	{
474 		return Geometry( to!(string)(imageInfo.page) );
475 	}
476 
477 	/**
478 	 * The compression level for JPEG, MPEG, JPEG-2000,
479 	 * MIFF, MNG, and PNG image format.
480 	 * The default is 75
481 	 */
482 	void quality(size_t q)
483 	{
484 		imageInfo.quality = q;
485 	}
486 	///ditto
487 	size_t quality() const
488 	{
489 		return imageInfo.quality;
490 	}
491 
492 	/**
493 	 * Units of image resolution.
494 	 */
495 	void resolutionUnits(ResolutionType type)
496 	{
497 		imageInfo.units = type;
498 	}
499 	///ditto
500 	ResolutionType resolutionUnits() const
501 	{
502 		return imageInfo.units;
503 	}
504 
505 	/**
506 	 * sampling factors used by JPEG or MPEG-2 encoder and
507 	 * YUV decoder/encoder.
508 	 * 
509 	 * This attribute specifies the sampling factors to be used
510 	 * by the JPEG encoder for chroma downsampling.
511 	 * If this attribute is omitted, the JPEG library will use its
512 	 * own default values. When reading or writing the YUV format and
513 	 * when writing the M2V (MPEG-2) format, use sampling-factor="2x1"
514 	 * to specify the 4:2:2 downsampling method.
515 	 */
516 	void samplingFactor(string str)
517 	{
518 		copyString(imageInfo.sampling_factor, str);
519 	}
520 	///ditto
521 	string samplingFactor() const
522 	{
523 		return to!(string)(imageInfo.sampling_factor);
524 	}
525 
526 	/**
527 	 * Set the width and height of the image when reading a
528 	 * built-in image format that does not have an inherent _size,
529 	 * or when reading an image from a multi-resolution file format
530 	 * such as Photo CD, JBIG, or JPEG.
531 	 */
532 	void size(string str)
533 	{
534 		copyString(imageInfo.size, str);
535 	}
536 	///ditto
537 	void size(Geometry geometry)
538 	{
539 		size(geometry.toString());
540 	}
541 	///ditto
542 	Geometry size() const
543 	{
544 		return Geometry( to!(string)(imageInfo.size) );
545 	}
546 
547 	/**
548 	 * Subimage of an image sequence
549 	 */
550 	void subImage(size_t num)
551 	{
552 		imageInfo.scene = num;
553 	}
554 	///ditto
555 	size_t subImage() const
556 	{
557 		return imageInfo.scene;
558 	}
559 
560 	/**
561 	 * Number of images relative to the base image
562 	 */
563 	void subRange(size_t num)
564 	{
565 		imageInfo.number_scenes = num;
566 	}
567 	///ditto
568 	size_t subRange() const
569 	{
570 		return imageInfo.number_scenes;
571 	}
572 
573 	/**
574 	 * Image _type.
575 	 */
576 	void type(ImageType t)
577 	{
578 		imageInfo.type = t;
579 	}
580 	///ditto
581 	ImageType type() const
582 	{
583 		return imageInfo.type;
584 	}
585 
586 	/**
587 	 * Print detailed information about the image.
588 	 */
589 	void verbose(bool v)
590 	{
591 		imageInfo.verbose = v;
592 	}
593 	///ditto
594 	bool verbose() const
595 	{
596 		return imageInfo.verbose == 1;
597 	}
598 
599 	/**
600 	 * FlashPix viewing parameters.
601 	 */
602 	void view(string str)
603 	{
604 		copyString(imageInfo.view, str);
605 	}
606 	///ditto
607 	string view() const
608 	{
609 		return to!(string)(imageInfo.view);
610 	}
611 
612 	/**
613 	 * Image virtual pixel _method.
614 	 */
615 	void virtualPixelMethod(VirtualPixelMethod method)
616 	{
617 		imageInfo.virtual_pixel_method = method;
618 	}
619 	///ditto
620 	VirtualPixelMethod virtualPixelMethod() const
621 	{
622 		return imageInfo.virtual_pixel_method;
623 	}
624 
625 	/**
626 	 * X11 display to display to obtain fonts from or, to capture image from.
627 	 */
628 	void x11Display(string str)
629 	{
630 		copyString(imageInfo.server_name, str);
631 		drawInfo.server_name = imageInfo.server_name;
632 	}
633 	///ditto
634 	string x11Display() const
635 	{
636 		return to!(string)(imageInfo.server_name);
637 	}
638 
639 	//OrientationType orientation;
640 	//MagickBooleanType temporary,
641 	//MagickBooleanType affirm,
642 	//MagickBooleanType antialias;
643 	//char* extract,
644 	//char* scenes;
645 	//size_t colors;
646 	//PreviewType preview_type;
647 	//ssize_t group;
648 	//MagickBooleanType ping,
649 	//char* authenticate;
650 	//ChannelType channel;
651 	//void* options;
652 	//MagickProgressMonitor progress_monitor;
653 	//void* client_data,
654 	//void* cache;
655 	//StreamHandler stream;
656 	//void* blob;
657 	//size_t length;
658 	//char[MaxTextExtent] unique,
659 	//char[MaxTextExtent] zero,
660 	//size_t signature;
661 	//PixelPacket transparent_color;
662 	//void* profile;
663 	//MagickBooleanType synchronize;
664 
665 	/+***************************************************************
666 	 * DrawInfo fields
667 	 ***************************************************************+/
668 
669 	void affine(AffineMatrix affine)
670 	{
671 		drawInfo.affine = affine;
672 	}
673 	AffineMatrix affine() const
674 	{
675 		return drawInfo.affine;
676 	}
677 
678 	/**
679 	 * Origin of coordinate system to use when annotating or drawing
680 	 */
681 	void transformOrigin (double tx, double ty)
682 	{
683 		AffineMatrix affine;
684 		affine.sx = 1.0;
685 		affine.rx = 0.0;
686 		affine.ry = 0.0;
687 		affine.sy = 1.0;
688 		affine.tx = tx;
689 		affine.ty = ty;
690 
691 		drawInfo.affine = multiplyMatrix(drawInfo.affine, affine);
692 	}
693 
694 	/**
695 	 * Rotation to use when annotating or drawing
696 	 */
697 	void transformRotation(double angle)
698 	{
699 		AffineMatrix affine;
700 		affine.sx = cos(degreesToRadians(angle % 360.0));
701 		affine.rx = sin(degreesToRadians(angle % 360.0));
702 		affine.ry = -affine.rx;
703 		affine.sy =  affine.sx;
704 		affine.tx = 0.0;
705 		affine.ty = 0.0;
706 
707 		drawInfo.affine = multiplyMatrix(drawInfo.affine, affine);
708 	}
709 
710 	/**
711 	 * Scale to use when annotating or drawing
712 	 */
713 	void transformScale(double sx, double sy)
714 	{
715 		AffineMatrix affine;
716 		affine.sx = sx;
717 		affine.rx = 0.0;
718 		affine.ry = 0.0;
719 		affine.sy = sy;
720 		affine.tx = 0.0;
721 		affine.ty = 0.0;
722 
723 		drawInfo.affine = multiplyMatrix(drawInfo.affine, affine);
724 	}
725 
726 	/**
727 	 * Shear to use in X axis when annotating or drawing
728 	 */
729 	void transformShearX(double skewx)
730 	{
731 		AffineMatrix affine;
732 		affine.sx = 1.0;
733 		affine.rx = 0.0;
734 		affine.ry = tan(degreesToRadians(skewx % 360.0));
735 		affine.sy = 1.0;
736 		affine.tx = 0.0;
737 		affine.ty = 0.0;
738 
739 		drawInfo.affine = multiplyMatrix(drawInfo.affine, affine);
740 	}
741 
742 	/**
743 	 * Shear to use in X axis when annotating or drawing
744 	 */
745 	void transformShearY(double skewy)
746 	{
747 		AffineMatrix affine;
748 		affine.sx = 1.0;
749 		affine.rx = tan(degreesToRadians(skewy % 360.0));
750 		affine.ry = 0.0;
751 		affine.sy = 1.0;
752 		affine.tx = 0.0;
753 		affine.ty = 0.0;
754 
755 		drawInfo.affine = multiplyMatrix(drawInfo.affine, affine);
756 	}
757 
758 	/**
759 	 * Reset transformation parameters to default
760 	 */
761 	void transformReset()
762 	{
763 		drawInfo.affine.sx = 1.0;
764 		drawInfo.affine.rx = 0.0;
765 		drawInfo.affine.ry = 0.0;
766 		drawInfo.affine.sy = 1.0;
767 		drawInfo.affine.tx = 0.0;
768 		drawInfo.affine.ty = 0.0;
769 	}
770 
771 	/**
772 	 * Returns the product of two Affine matrices
773 	 * The AffineMatrix looks like this:
774 	 * -----------
775 	 * | sx rx 0 |
776 	 * | ry sy 0 |
777 	 * | tx ty 1 |
778 	 * -----------
779 	 */
780 	AffineMatrix multiplyMatrix(AffineMatrix a, AffineMatrix b)
781 	{
782 		AffineMatrix result;
783 
784 		result.sx = a.sx * b.sx + a.rx * b.ry;
785 		result.rx = a.sx * b.rx + a.rx * b.sy;
786 		result.ry = a.ry * b.sx + a.sy * b.ry;
787 		result.sy = a.ry * b.rx + a.sy * b.sy;
788 		result.tx = a.tx * b.sx + a.ty * b.ry + b.tx;
789 		result.ty = a.tx * b.rx + a.ty * b.sy + b.ty;
790 
791 		return result;
792 	}
793 
794 	/**
795 	 * Control antialiasing of rendered Postscript
796 	 * and Postscript or TrueType fonts. The default is true.
797 	 */
798 	void antialias(bool antialias)
799 	{
800 		drawInfo.text_antialias = antialias;
801 	}
802 	///ditto
803 	bool antialias() const
804 	{
805 		return drawInfo.text_antialias == 1;
806 	}
807 
808 	/**
809 	 * If set, causes the text to be drawn over a box of the specified color.
810 	 */
811 	void boxColor(string color)
812 	{
813 		boxColor = new Color(color);
814 	}
815 	///ditto
816 	void boxColor(Color color)
817 	{
818 		drawInfo.undercolor = color.pixelPacket;
819 	}
820 	///ditto
821 	Color boxColor() const
822 	{
823 		return new Color(drawInfo.undercolor);
824 	}
825 
826 	/**
827 	 * Color to use when filling drawn objects.
828 	 * The default is "black".
829 	 */
830 	void fillColor(string color)
831 	{
832 		fillColor = new Color(color);
833 	}
834 	///ditto
835 	void fillColor(Color color)
836 	{
837 		drawInfo.fill = color.pixelPacket;
838 	}
839 	///ditto
840 	Color fillColor() const
841 	{
842 		return new Color(drawInfo.fill);
843 	}
844 
845 	/**
846 	 * Pattern image to use when filling drawn objects.
847 	 */
848 	//TODO: investigate if we need to clone the image.
849 	void fillPattern(dmagick.Image.Image pattern)
850 	{
851 		if (drawInfo.fill_pattern)
852 			drawInfo.fill_pattern = DestroyImageList(drawInfo.fill_pattern);
853 
854 		drawInfo.fill_pattern = ReferenceImage(pattern.imageRef);
855 	}
856 	///ditto
857 	const(dmagick.Image.Image) fillPattern() const
858 	{
859 		return new dmagick.Image.Image(ReferenceImage((cast(DrawInfo*)drawInfo).fill_pattern));
860 	}
861 
862 	/**
863 	 * Rule to use when filling drawn objects.
864 	 */
865 	void fillRule(FillRule rule)
866 	{
867 		drawInfo.fill_rule = rule;
868 	}
869 	///ditto
870 	FillRule fillRule() const
871 	{
872 		return drawInfo.fill_rule;
873 	}
874 
875 	/**
876 	 * Specify the font family, such as "arial" or "helvetica".
877 	 */
878 	void fontFamily(string type)
879 	{
880 		copyString(drawInfo.family, type);
881 	}
882 	///ditto
883 	string fontFamily() const
884 	{
885 		return to!(string)(drawInfo.family);
886 	}
887 
888 	/**
889 	 * Specify the spacing between text characters.
890 	 */
891 	void fontStretch(StretchType type)
892 	{
893 		drawInfo.stretch = type;
894 	}
895 	///ditto
896 	StretchType fontStretch() const
897 	{
898 		return drawInfo.stretch;
899 	}
900 
901 	/**
902 	 * Specify the font style, i.e. italic, oblique, or normal.
903 	 */
904 	void fontStyle(StyleType type)
905 	{
906 		drawInfo.style = type;
907 	}
908 	///ditto
909 	StyleType fontStyle() const
910 	{
911 		return drawInfo.style;
912 	}
913 
914 	/**
915 	 * Specify the font weight.
916 	 */
917 	void fontWeight(size_t weight)
918 	{
919 		drawInfo.weight = type;
920 	}
921 	///ditto
922 	size_t fontWeight() const
923 	{
924 		return drawInfo.weight;
925 	}
926 
927 	/**
928 	 * Enable or disable anti-aliasing when drawing object outlines.
929 	 */
930 	void strokeAntialias(bool antialias)
931 	{
932 		drawInfo.stroke_antialias = antialias;
933 	}
934 	///ditto
935 	bool strokeAntialias() const
936 	{
937 		return drawInfo.stroke_antialias == 1;
938 	}
939 
940 	/**
941 	 * Color to use when drawing object outlines.
942 	 */
943 	void strokeColor(string color)
944 	{
945 		strokeColor = new Color(color);
946 	}
947 	///ditto
948 	void strokeColor(Color color)
949 	{
950 		drawInfo.stroke = color.pixelPacket;
951 	}
952 	///ditto
953 	Color strokeColor() const
954 	{
955 		return new Color(drawInfo.stroke);
956 	}
957 
958 	/**
959 	 * The initial distance into the dash pattern. The units are pixels.
960 	 */
961 	void strokeDashOffset(double offset)
962 	{
963 		drawInfo.dash_offset = offset;
964 	}
965 	///ditto
966 	double strokeDashOffset() const
967 	{
968 		return drawInfo.dash_offset;
969 	}
970 
971 	/**
972 	 * Describe a _pattern of dashes to be used when stroking paths.
973 	 * The arguments are a list of pixel widths of
974 	 * alternating dashes and gaps.
975 	 * All elements must be > 0.
976 	 */
977 	void strokeDashPattern(const(double)[] pattern)
978 	{
979 		if ( drawInfo.dash_pattern !is null )
980 			RelinquishMagickMemory(drawInfo.dash_pattern);
981 
982 		if ( pattern is null )
983 			return;
984 
985 		drawInfo.dash_pattern = cast(double*)AcquireMagickMemory((pattern.length+1) * double.sizeof);
986 		drawInfo.dash_pattern[0 .. pattern.length] = pattern;
987 		drawInfo.dash_pattern[pattern.length] = 0.0;
988 	}
989 	///ditto
990 	double[] strokeDashPattern() const
991 	{
992 		size_t x;
993 		for (x = 0; drawInfo.dash_pattern[x] == 0.0; x++ ) {}
994 
995 		double[] pattern = new double[x];
996 		pattern[] = drawInfo.dash_pattern[0 .. x];
997 
998 		return pattern;
999 	}
1000 
1001 	/**
1002 	 * Specify how the line ends should be drawn.
1003 	 */
1004 	void strokeLineCap(LineCap cap)
1005 	{
1006 		drawInfo.linecap = cap;
1007 	}
1008 	///ditto
1009 	LineCap strokeLineCap() const
1010 	{
1011 		return drawInfo.linecap;
1012 	}
1013 
1014 	/**
1015 	 * Specify how corners are drawn.
1016 	 */
1017 	void strokeLineJoin(LineJoin join)
1018 	{
1019 		drawInfo.linejoin = join;
1020 	}
1021 	///ditto
1022 	LineJoin lineJoin() const
1023 	{
1024 		return drawInfo.linejoin;
1025 	}
1026 
1027 	/**
1028 	 * Specify a constraint on the length of the "miter"
1029 	 * formed by two lines meeting at an angle. If the angle
1030 	 * if very sharp, the miter could be very long relative
1031 	 * to the line thickness. The miter _limit is a _limit on
1032 	 * the ratio of the miter length to the line width.
1033 	 * The default is 4.
1034 	 */
1035 	void strokeMiterlimit(size_t limit)
1036 	{
1037 		drawInfo.miterlimit = limit;
1038 	}
1039 	///ditto
1040 	size_t strokeMiterlimit() const
1041 	{
1042 		return drawInfo.miterlimit;
1043 	}
1044 
1045 	/**
1046 	 * Pattern image to use while drawing object stroke
1047 	 */
1048 	//TODO: investigate if we need to clone the image.
1049 	void strokePattern(dmagick.Image.Image pattern)
1050 	{
1051 		if (drawInfo.stroke_pattern)
1052 			drawInfo.stroke_pattern = DestroyImageList(drawInfo.stroke_pattern);
1053 
1054 		drawInfo.stroke_pattern = ReferenceImage(pattern.imageRef);
1055 	}
1056 	///ditto
1057 	const(dmagick.Image.Image) strokePattern() const
1058 	{
1059 		return new dmagick.Image.Image(ReferenceImage((cast(DrawInfo*)drawInfo).stroke_pattern));
1060 	}
1061 
1062 	/**
1063 	 * Stroke _width for use when drawing vector objects
1064 	 */
1065 	void strokeWidth(double width)
1066 	{
1067 		drawInfo.stroke_width = width;
1068 	}
1069 	///ditto
1070 	double strokeWidth() const
1071 	{
1072 		return drawInfo.stroke_width;
1073 	}
1074 
1075 	/**
1076 	 * The text density in the x and y directions. The default is "72x72".
1077 	 */
1078 	void textDensity(string str)
1079 	{
1080 		copyString(imageInfo.density, str);
1081 	}
1082 	///ditto
1083 	void textDensity(Geometry geometry)
1084 	{
1085 		textDensity(geometry.toString);
1086 	}
1087 	///ditto
1088 	Geometry textDensity() const
1089 	{
1090 		return Geometry( to!(string)(imageInfo.density) );
1091 	}
1092 
1093 	/**
1094 	 * Specify the code set to use for text annotations.
1095 	 * The only character encoding which may be specified at
1096 	 * this time is "UTF-8" for representing Unicode as a
1097 	 * sequence of bytes. Specify an empty string to use
1098 	 * ASCII encoding. Successful text annotation using
1099 	 * Unicode may require fonts designed to support Unicode.
1100 	 * The default is "UTF-8"
1101 	 */
1102 	void textEncoding(string str)
1103 	{
1104 		copyString(drawInfo.encoding, str);
1105 	}
1106 	///ditto
1107 	string textEncoding() const
1108 	{
1109 		return to!(string)(drawInfo.encoding);
1110 	}
1111 
1112 	//char* primitive,
1113 	//char* geometry;
1114 	//RectangleInfo viewbox;
1115 	//GravityType gravity;
1116 	//GradientInfo gradient;
1117 	//MagickBooleanType tile,
1118 	//DecorationType decorate;
1119 	//CompositeOperator compose;
1120 	//char* text;
1121 	//size_t face;
1122 	//char* metrics,
1123 	//AlignType align;
1124 	//char* clip_mask;
1125 	//SegmentInfo bounds;
1126 	//ClipPathUnits clip_units;
1127 	//Quantum opacity;
1128 	//MagickBooleanType render;
1129 	//ElementReference element_reference;
1130 	//MagickBooleanType ddebug;
1131 	//size_t signature;
1132 	//double kerning,
1133 	//double interword_spacing,
1134 	//double interline_spacing;
1135 	//DirectionType direction;
1136 
1137 	/+***************************************************************
1138 	 * QuantizeInfo fields
1139 	 ***************************************************************+/
1140 
1141 
1142 	/**
1143 	 * Preferred number of _colors in the image.
1144 	 * The actual number of _colors in the image may be less
1145 	 * than your request, but never more. Images with less
1146 	 * unique _colors than specified with this option will have
1147 	 * any duplicate or unused _colors removed.
1148 	 */
1149 	void quantizeColors(size_t colors)
1150 	{
1151 		quantizeInfo.number_colors = colors;
1152 	}
1153 	///ditto
1154 	size_t quantizeColors() const
1155 	{
1156 		return quantizeInfo.number_colors;
1157 	}
1158 
1159 	/**
1160 	 * Colorspace to quantize colors in.
1161 	 * Empirical evidence suggests that distances in color spaces
1162 	 * such as YUV or YIQ correspond to perceptual color differences
1163 	 * more closely than do distances in RGB space. These color spaces
1164 	 * may give better results when color reducing an image.
1165 	 * The default is RGB
1166 	 */
1167 	void quantizeColorSpace(ColorspaceType type)
1168 	{
1169 		quantizeInfo.colorspace = type;
1170 	}
1171 	///ditto
1172 	ColorspaceType quantizeColorSpace() const
1173 	{
1174 		return quantizeInfo.colorspace;
1175 	}
1176 
1177 	/**
1178 	 * The basic strategy of dithering is to trade intensity resolution for
1179 	 * spatial resolution by averaging the intensities of several neighboring
1180 	 * pixels. Images which suffer from severe contouring when reducing
1181 	 * colors can be improved with this option. 
1182 	 */
1183 	void quantizeDitherMethod(DitherMethod method)
1184 	{
1185 		quantizeInfo.dither_method = method;
1186 	}
1187 	///ditto
1188 	DitherMethod quantizeDitherMethod() const
1189 	{
1190 		return quantizeInfo.dither_method;
1191 	}
1192 
1193 	/**
1194 	 * Depth of the quantization color classification tree.
1195 	 * Values of 0 or 1 allow selection of the optimal tree _depth
1196 	 * for the color reduction algorithm. Values between 2 and 8
1197 	 * may be used to manually adjust the tree _depth.
1198 	 */
1199 	void quantizeTreeDepth(size_t depth)
1200 	{
1201 		quantizeInfo.tree_depth = depth;
1202 	}
1203 	///ditto
1204 	size_t quantizeTreeDepth() const
1205 	{
1206 		return quantizeInfo.tree_depth;
1207 	}
1208 
1209 	//MagickBooleanType measure_error;
1210 	//size_t signature;
1211 }