]> granicus.if.org Git - imagemagick/blob - Magick++/lib/Image.cpp
(no commit message)
[imagemagick] / Magick++ / lib / Image.cpp
1 // This may look like C code, but it is really -*- C++ -*-
2 //
3 // Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
4 //
5 // Implementation of Image
6 //
7
8 #define MAGICKCORE_IMPLEMENTATION  1
9 #define MAGICK_PLUSPLUS_IMPLEMENTATION 1
10
11 #include "Magick++/Include.h"
12 #include <cstdlib>
13 #include <string>
14 #include <string.h>
15 #include <errno.h>
16 #include <math.h>
17 #if !defined(__WINDOWS__)
18 #include <strings.h>
19 #endif
20
21 using namespace std;
22
23 #include "Magick++/Image.h"
24 #include "Magick++/Functions.h"
25 #include "Magick++/Pixels.h"
26 #include "Magick++/Options.h"
27 #include "Magick++/ImageRef.h"
28
29 #define AbsoluteValue(x)  ((x) < 0 ? -(x) : (x))
30 #define MagickPI  3.14159265358979323846264338327950288419716939937510
31 #define DegreesToRadians(x)  (MagickPI*(x)/180.0)
32
33 MagickDLLDeclExtern const char *Magick::borderGeometryDefault = "6x6+0+0";
34 MagickDLLDeclExtern const char *Magick::frameGeometryDefault  = "25x25+6+6";
35 MagickDLLDeclExtern const char *Magick::raiseGeometryDefault  = "6x6+0+0";
36
37 static bool magick_initialized=false;
38
39 //
40 // Explicit template instantiations
41 //
42
43 //
44 // Friend functions to compare Image objects
45 //
46
47 MagickDLLDecl int Magick::operator == ( const Magick::Image& left_,
48                                         const Magick::Image& right_ )
49 {
50   // If image pixels and signature are the same, then the image is identical
51   return ( ( left_.rows() == right_.rows() ) &&
52            ( left_.columns() == right_.columns() ) &&
53            ( left_.signature() == right_.signature() )
54            );
55 }
56 MagickDLLDecl int Magick::operator != ( const Magick::Image& left_,
57                                         const Magick::Image& right_ )
58 {
59   return ( ! (left_ == right_) );
60 }
61 MagickDLLDecl int Magick::operator >  ( const Magick::Image& left_,
62                                         const Magick::Image& right_ )
63 {
64   return ( !( left_ < right_ ) && ( left_ != right_ ) );
65 }
66 MagickDLLDecl int Magick::operator <  ( const Magick::Image& left_,
67                                         const Magick::Image& right_ )
68 {
69   // If image pixels are less, then image is smaller
70   return ( ( left_.rows() * left_.columns() ) <
71            ( right_.rows() * right_.columns() )
72            );
73 }
74 MagickDLLDecl int Magick::operator >= ( const Magick::Image& left_,
75                                         const Magick::Image& right_ )
76 {
77   return ( ( left_ > right_ ) || ( left_ == right_ ) );
78 }
79 MagickDLLDecl int Magick::operator <= ( const Magick::Image& left_,
80                                         const Magick::Image& right_ )
81 {
82   return ( ( left_ < right_ ) || ( left_ == right_ ) );
83 }
84
85 //
86 // Image object implementation
87 //
88
89 // Construct from image file or image specification
90 Magick::Image::Image( const std::string &imageSpec_ )
91   : _imgRef(new ImageRef)
92 {
93   try
94     {
95       // Initialize, Allocate and Read images
96       read( imageSpec_ );
97     }
98   catch ( const Warning & /*warning_*/ )
99     {
100       // FIXME: need a way to report warnings in constructor
101     }
102   catch ( const Error & /*error_*/ )
103     {
104       // Release resources
105       delete _imgRef;
106       throw;
107     }
108 }
109
110 // Construct a blank image canvas of specified size and color
111 Magick::Image::Image( const Geometry &size_,
112                       const Color &color_ )
113   : _imgRef(new ImageRef)
114 {
115   // xc: prefix specifies an X11 color string
116   std::string imageSpec("xc:");
117   imageSpec += color_;
118
119   try
120     {
121       // Set image size
122       size( size_ );
123
124       // Initialize, Allocate and Read images
125       read( imageSpec );
126     }
127   catch ( const Warning & /*warning_*/ )
128     {
129       // FIXME: need a way to report warnings in constructor
130     }
131   catch ( const Error & /*error_*/ )
132     {
133       // Release resources
134       delete _imgRef;
135       throw;
136     }
137 }
138
139 // Construct Image from in-memory BLOB
140 Magick::Image::Image ( const Blob &blob_ )
141   : _imgRef(new ImageRef)
142 {
143   try
144     {
145       // Initialize, Allocate and Read images
146       read( blob_ );
147     }
148   catch ( const Warning & /*warning_*/ )
149     {
150       // FIXME: need a way to report warnings in constructor
151     }
152   catch ( const Error & /*error_*/ )
153     {
154       // Release resources
155       delete _imgRef;
156       throw;
157     }
158 }
159
160 // Construct Image of specified size from in-memory BLOB
161 Magick::Image::Image ( const Blob &blob_,
162                        const Geometry &size_ )
163   : _imgRef(new ImageRef)
164 {
165   try
166     {
167       // Read from Blob
168       read( blob_, size_ );
169     }
170   catch ( const Warning & /*warning_*/ )
171     {
172       // FIXME: need a way to report warnings in constructor
173     }
174   catch ( const Error & /*error_*/ )
175     {
176       // Release resources
177       delete _imgRef;
178       throw;
179     }
180 }
181
182 // Construct Image of specified size and depth from in-memory BLOB
183 Magick::Image::Image ( const Blob &blob_,
184                        const Geometry &size_,
185                        const unsigned int depth_ )
186   : _imgRef(new ImageRef)
187 {
188   try
189     {
190       // Read from Blob
191       read( blob_, size_, depth_ );
192     }
193   catch ( const Warning & /*warning_*/ )
194     {
195       // FIXME: need a way to report warnings in constructor
196     }
197   catch ( const Error & /*error_*/ )
198     {
199       // Release resources
200       delete _imgRef;
201       throw;
202     }
203 }
204
205 // Construct Image of specified size, depth, and format from in-memory BLOB
206 Magick::Image::Image ( const Blob &blob_,
207                        const Geometry &size_,
208                        const unsigned int depth_,
209                        const std::string &magick_ )
210   : _imgRef(new ImageRef)
211 {
212   try
213     {
214       // Read from Blob
215       read( blob_, size_, depth_, magick_ );
216     }
217   catch ( const Warning & /*warning_*/ )
218     {
219       // FIXME: need a way to report warnings in constructor
220     }
221   catch ( const Error & /*error_*/ )
222     {
223       // Release resources
224       delete _imgRef;
225       throw;
226     }
227 }
228
229 // Construct Image of specified size, and format from in-memory BLOB
230 Magick::Image::Image ( const Blob &blob_,
231                        const Geometry &size_,
232                        const std::string &magick_ )
233   : _imgRef(new ImageRef)
234 {
235   try
236     {
237       // Read from Blob
238       read( blob_, size_, magick_ );
239     }
240   catch ( const Warning & /*warning_*/ )
241     {
242       // FIXME: need a way to report warnings in constructor
243     }
244   catch ( const Error & /*error_*/ )
245     {
246       // Release resources
247       delete _imgRef;
248       throw;
249     }
250 }
251
252 // Construct an image based on an array of raw pixels, of specified
253 // type and mapping, in memory
254 Magick::Image::Image ( const unsigned int width_,
255                        const unsigned int height_,
256                        const std::string &map_,
257                        const StorageType type_,
258                        const void *pixels_ )
259   : _imgRef(new ImageRef)
260 {
261   try
262     {
263       read( width_, height_, map_.c_str(), type_, pixels_ );
264     }
265   catch ( const Warning & /*warning_*/ )
266     {
267       // FIXME: need a way to report warnings in constructor
268     }
269   catch ( const Error & /*error_*/ )
270     {
271       // Release resources
272       delete _imgRef;
273       throw;
274     }
275 }
276
277 // Default constructor
278 Magick::Image::Image( void )
279   : _imgRef(new ImageRef)
280 {
281 }
282
283 // Destructor
284 /* virtual */
285 Magick::Image::~Image()
286 {
287   bool doDelete = false;
288   {
289     Lock( &_imgRef->_mutexLock );
290     if ( --_imgRef->_refCount == 0 )
291       doDelete = true;
292   }
293
294   if ( doDelete )
295     {
296       delete _imgRef;
297     }
298   _imgRef = 0;
299 }
300
301 // Adaptive-blur image
302 void Magick::Image::adaptiveBlur( const double radius_, const double sigma_ )
303 {
304   ExceptionInfo exceptionInfo;
305   GetExceptionInfo( &exceptionInfo );
306   MagickCore::Image* newImage =
307     AdaptiveBlurImage( image(), radius_, sigma_, &exceptionInfo);
308   replaceImage( newImage );
309   throwException( exceptionInfo );
310   (void) DestroyExceptionInfo( &exceptionInfo );
311 }
312
313 // Local adaptive threshold image
314 // http://www.dai.ed.ac.uk/HIPR2/adpthrsh.htm
315 // Width x height define the size of the pixel neighborhood
316 // offset = constant to subtract from pixel neighborhood mean
317 void Magick::Image::adaptiveThreshold ( const unsigned int width_,
318                                         const unsigned int height_,
319                                         const unsigned int offset_ )
320 {
321   ExceptionInfo exceptionInfo;
322   GetExceptionInfo( &exceptionInfo );
323   MagickCore::Image* newImage =
324     AdaptiveThresholdImage( constImage(), width_, height_, offset_, &exceptionInfo );
325   replaceImage( newImage );
326   throwException( exceptionInfo );
327   (void) DestroyExceptionInfo( &exceptionInfo );
328 }
329
330 // Add noise to image
331 void Magick::Image::addNoise( const NoiseType noiseType_ )
332 {
333   ExceptionInfo exceptionInfo;
334   GetExceptionInfo( &exceptionInfo );
335   MagickCore::Image* newImage =
336     AddNoiseImage ( image(),
337                     noiseType_,
338                     &exceptionInfo );
339   replaceImage( newImage );
340   throwException( exceptionInfo );
341   (void) DestroyExceptionInfo( &exceptionInfo );
342 }
343
344 void Magick::Image::addNoiseChannel( const ChannelType channel_,
345                                      const NoiseType noiseType_ )
346 {
347   ExceptionInfo exceptionInfo;
348   GetExceptionInfo( &exceptionInfo );
349   MagickCore::Image* newImage =
350     AddNoiseImageChannel ( image(),
351                            channel_,
352                            noiseType_,
353                            &exceptionInfo );
354   replaceImage( newImage );
355   throwException( exceptionInfo );
356   (void) DestroyExceptionInfo( &exceptionInfo );
357 }
358
359 // Affine Transform image
360 void Magick::Image::affineTransform ( const DrawableAffine &affine_ )
361 {
362   ExceptionInfo exceptionInfo;
363   GetExceptionInfo( &exceptionInfo );
364   
365   AffineMatrix _affine;
366   _affine.sx = affine_.sx();
367   _affine.sy = affine_.sy();
368   _affine.rx = affine_.rx();
369   _affine.ry = affine_.ry();
370   _affine.tx = affine_.tx();  
371   _affine.ty = affine_.ty();
372   
373   MagickCore::Image* newImage =
374     AffineTransformImage( image(), &_affine, &exceptionInfo);     
375   replaceImage( newImage );
376   throwException( exceptionInfo );
377   (void) DestroyExceptionInfo( &exceptionInfo );
378 }
379
380 // Annotate using specified text, and placement location
381 void Magick::Image::annotate ( const std::string &text_,
382                                const Geometry &location_ )
383 {
384   annotate ( text_, location_,  NorthWestGravity, 0.0 );
385 }
386 // Annotate using specified text, bounding area, and placement gravity
387 void Magick::Image::annotate ( const std::string &text_,
388                                const Geometry &boundingArea_,
389                                const GravityType gravity_ )
390 {
391   annotate ( text_, boundingArea_, gravity_, 0.0 );
392 }
393 // Annotate with text using specified text, bounding area, placement
394 // gravity, and rotation.
395 void Magick::Image::annotate ( const std::string &text_,
396                                const Geometry &boundingArea_,
397                                const GravityType gravity_,
398                                const double degrees_ )
399 {
400   modifyImage();
401
402   DrawInfo *drawInfo
403     = options()->drawInfo();
404   
405   drawInfo->text = const_cast<char *>(text_.c_str());
406
407   char boundingArea[MaxTextExtent];
408
409   drawInfo->geometry = 0;
410   if ( boundingArea_.isValid() ){
411     if ( boundingArea_.width() == 0 || boundingArea_.height() == 0 )
412       {
413         FormatMagickString( boundingArea, MaxTextExtent, "+%u+%u",
414                       boundingArea_.xOff(), boundingArea_.yOff() );
415       }
416     else
417       {
418         (void) CopyMagickString( boundingArea, string(boundingArea_).c_str(),
419           MaxTextExtent);
420       }
421     drawInfo->geometry = boundingArea;
422   }
423
424   drawInfo->gravity = gravity_;
425
426   AffineMatrix oaffine = drawInfo->affine;
427   if ( degrees_ != 0.0)
428     {
429         AffineMatrix affine;
430         affine.sx=1.0;
431         affine.rx=0.0;
432         affine.ry=0.0;
433         affine.sy=1.0;
434         affine.tx=0.0;
435         affine.ty=0.0;
436
437         AffineMatrix current = drawInfo->affine;
438         affine.sx=cos(DegreesToRadians(fmod(degrees_,360.0)));
439         affine.rx=sin(DegreesToRadians(fmod(degrees_,360.0)));
440         affine.ry=(-sin(DegreesToRadians(fmod(degrees_,360.0))));
441         affine.sy=cos(DegreesToRadians(fmod(degrees_,360.0)));
442
443         drawInfo->affine.sx=current.sx*affine.sx+current.ry*affine.rx;
444         drawInfo->affine.rx=current.rx*affine.sx+current.sy*affine.rx;
445         drawInfo->affine.ry=current.sx*affine.ry+current.ry*affine.sy;
446         drawInfo->affine.sy=current.rx*affine.ry+current.sy*affine.sy;
447         drawInfo->affine.tx=current.sx*affine.tx+current.ry*affine.ty
448           +current.tx;
449     }
450
451   AnnotateImage( image(), drawInfo );
452
453   // Restore original values
454   drawInfo->affine = oaffine;
455   drawInfo->text = 0;
456   drawInfo->geometry = 0;
457
458   throwImageException();
459 }
460 // Annotate with text (bounding area is entire image) and placement gravity.
461 void Magick::Image::annotate ( const std::string &text_,
462                                const GravityType gravity_ )
463 {
464   modifyImage();
465
466   DrawInfo *drawInfo
467     = options()->drawInfo();
468
469   drawInfo->text = const_cast<char *>(text_.c_str());
470
471   drawInfo->gravity = gravity_;
472
473   AnnotateImage( image(), drawInfo );
474
475   drawInfo->gravity = NorthWestGravity;
476   drawInfo->text = 0;
477
478   throwImageException();
479 }
480
481 // Blur image
482 void Magick::Image::blur( const double radius_, const double sigma_ )
483 {
484   ExceptionInfo exceptionInfo;
485   GetExceptionInfo( &exceptionInfo );
486   MagickCore::Image* newImage =
487     BlurImage( image(), radius_, sigma_, &exceptionInfo);
488   replaceImage( newImage );
489   throwException( exceptionInfo );
490   (void) DestroyExceptionInfo( &exceptionInfo );
491 }
492
493 void Magick::Image::blurChannel( const ChannelType channel_,
494                                  const double radius_, const double sigma_ )
495 {
496   ExceptionInfo exceptionInfo;
497   GetExceptionInfo( &exceptionInfo );
498   MagickCore::Image* newImage =
499     BlurImageChannel( image(), channel_,radius_, sigma_, &exceptionInfo);
500   replaceImage( newImage );
501   throwException( exceptionInfo );
502   (void) DestroyExceptionInfo( &exceptionInfo );
503 }
504
505 // Add border to image
506 // Only uses width & height
507 void Magick::Image::border( const Geometry &geometry_ )
508 {
509   RectangleInfo borderInfo = geometry_;
510   ExceptionInfo exceptionInfo;
511   GetExceptionInfo( &exceptionInfo );
512   MagickCore::Image* newImage =
513     BorderImage( image(), &borderInfo, &exceptionInfo);
514   replaceImage( newImage );
515   throwException( exceptionInfo );
516   (void) DestroyExceptionInfo( &exceptionInfo );
517 }
518
519 // Extract channel from image
520 void Magick::Image::channel ( const ChannelType channel_ )
521 {
522   modifyImage();
523   SeparateImageChannel ( image(), channel_ );
524   throwImageException();
525 }
526
527 // Set or obtain modulus channel depth
528 void Magick::Image::channelDepth ( const ChannelType channel_,
529                                    const unsigned int depth_)
530 {
531   modifyImage();
532   SetImageChannelDepth( image(), channel_, depth_);
533   throwImageException();
534 }
535 unsigned int Magick::Image::channelDepth ( const ChannelType channel_ )
536 {
537   unsigned int channel_depth;
538
539   ExceptionInfo exceptionInfo;
540   GetExceptionInfo( &exceptionInfo );
541   channel_depth=GetImageChannelDepth( constImage(), channel_,
542                                       &exceptionInfo );
543   throwException( exceptionInfo );
544   (void) DestroyExceptionInfo( &exceptionInfo );
545   return channel_depth;
546 }
547
548
549 // Charcoal-effect image
550 void Magick::Image::charcoal( const double radius_, const double sigma_ )
551 {
552   ExceptionInfo exceptionInfo;
553   GetExceptionInfo( &exceptionInfo );
554   MagickCore::Image* newImage =
555     CharcoalImage( image(), radius_, sigma_, &exceptionInfo );
556   replaceImage( newImage );
557   throwException( exceptionInfo );
558   (void) DestroyExceptionInfo( &exceptionInfo );
559 }
560
561 // Chop image
562 void Magick::Image::chop( const Geometry &geometry_ )
563 {
564   RectangleInfo chopInfo = geometry_;
565   ExceptionInfo exceptionInfo;
566   GetExceptionInfo( &exceptionInfo );
567   MagickCore::Image* newImage =
568     ChopImage( image(), &chopInfo, &exceptionInfo);
569   replaceImage( newImage );
570   throwException( exceptionInfo );
571   (void) DestroyExceptionInfo( &exceptionInfo );
572 }
573
574 // contains one or more color corrections and applies the correction to the
575 // image.
576 void Magick::Image::cdl ( const std::string &cdl_ )
577 {
578   modifyImage();
579   (void) ColorDecisionListImage( image(), cdl_.c_str() );
580   throwImageException();
581 }
582
583 // Colorize
584 void Magick::Image::colorize ( const unsigned int opacityRed_,
585                                const unsigned int opacityGreen_,
586                                const unsigned int opacityBlue_,
587                                const Color &penColor_ )
588 {
589   if ( !penColor_.isValid() )
590   {
591     throwExceptionExplicit( OptionError,
592                             "Pen color argument is invalid");
593   }
594
595   char opacity[MaxTextExtent];
596   FormatMagickString(opacity,MaxTextExtent,"%u/%u/%u",opacityRed_,opacityGreen_,opacityBlue_);
597
598   ExceptionInfo exceptionInfo;
599   GetExceptionInfo( &exceptionInfo );
600   MagickCore::Image* newImage =
601   ColorizeImage ( image(), opacity,
602                   penColor_, &exceptionInfo );
603   replaceImage( newImage );
604   throwException( exceptionInfo );
605   (void) DestroyExceptionInfo( &exceptionInfo );
606 }
607 void Magick::Image::colorize ( const unsigned int opacity_,
608                                const Color &penColor_ )
609 {
610   colorize( opacity_, opacity_, opacity_, penColor_ );
611 }
612
613 // Compare current image with another image
614 // Sets meanErrorPerPixel, normalizedMaxError, and normalizedMeanError
615 // in the current image. False is returned if the images are identical.
616 bool Magick::Image::compare ( const Image &reference_ )
617 {
618   modifyImage();
619   Image ref = reference_;
620   ref.modifyImage();
621   return static_cast<bool>(IsImagesEqual(image(), ref.image()));
622 }
623
624 // Composite two images
625 void Magick::Image::composite ( const Image &compositeImage_,
626                                 const int xOffset_,
627                                 const int yOffset_,
628                                 const CompositeOperator compose_ )
629 {
630   // Image supplied as compositeImage is composited with current image and
631   // results in updating current image.
632   modifyImage();
633
634   CompositeImage( image(),
635                   compose_,
636                   compositeImage_.constImage(),
637                   xOffset_,
638                   yOffset_ );
639   throwImageException();
640 }
641 void Magick::Image::composite ( const Image &compositeImage_,
642                                 const Geometry &offset_,
643                                 const CompositeOperator compose_ )
644 {
645   modifyImage();
646
647   long x = offset_.xOff();
648   long y = offset_.yOff();
649   unsigned long width = columns();
650   unsigned long height = rows();
651
652   ParseMetaGeometry (static_cast<std::string>(offset_).c_str(),
653                       &x, &y,
654                       &width, &height );
655
656   CompositeImage( image(),
657                   compose_,
658                   compositeImage_.constImage(),
659                   x, y );
660   throwImageException();
661 }
662 void Magick::Image::composite ( const Image &compositeImage_,
663                                 const GravityType gravity_,
664                                 const CompositeOperator compose_ )
665 {
666   modifyImage();
667
668   RectangleInfo geometry;
669
670   SetGeometry(compositeImage_.constImage(), &geometry);
671   GravityAdjustGeometry(columns(), rows(), gravity_, &geometry);
672
673   CompositeImage( image(),
674                   compose_,
675                   compositeImage_.constImage(),
676                   geometry.x, geometry.y );
677   throwImageException();
678 }
679
680 // Contrast image
681 void Magick::Image::contrast ( const unsigned int sharpen_ )
682 {
683   modifyImage();
684   ContrastImage ( image(), (MagickBooleanType) sharpen_ );
685   throwImageException();
686 }
687
688 // Convolve image.  Applies a general image convolution kernel to the image.
689 //  order_ represents the number of columns and rows in the filter kernel.
690 //  kernel_ is an array of doubles representing the convolution kernel.
691 void Magick::Image::convolve ( const unsigned int order_,
692                                const double *kernel_ )
693 {
694   ExceptionInfo exceptionInfo;
695   GetExceptionInfo( &exceptionInfo );
696   MagickCore::Image* newImage =
697   ConvolveImage ( image(), order_,
698                   kernel_, &exceptionInfo );
699   replaceImage( newImage );
700   throwException( exceptionInfo );
701   (void) DestroyExceptionInfo( &exceptionInfo );
702 }
703
704 // Crop image
705 void Magick::Image::crop ( const Geometry &geometry_ )
706 {
707   RectangleInfo cropInfo = geometry_;
708   ExceptionInfo exceptionInfo;
709   GetExceptionInfo( &exceptionInfo );
710   MagickCore::Image* newImage =
711     CropImage( image(),
712                &cropInfo,
713                &exceptionInfo);
714   replaceImage( newImage );
715   throwException( exceptionInfo );
716   (void) DestroyExceptionInfo( &exceptionInfo );
717 }
718
719 // Cycle Color Map
720 void Magick::Image::cycleColormap ( const int amount_ )
721 {
722   modifyImage();
723   CycleColormapImage( image(), amount_ );
724   throwImageException();
725 }
726
727 // Despeckle
728 void Magick::Image::despeckle ( void )
729 {
730   ExceptionInfo exceptionInfo;
731   GetExceptionInfo( &exceptionInfo );
732   MagickCore::Image* newImage =
733     DespeckleImage( image(), &exceptionInfo );
734   replaceImage( newImage );
735   throwException( exceptionInfo );
736   (void) DestroyExceptionInfo( &exceptionInfo );
737 }
738
739 // Display image
740 void Magick::Image::display( void )
741 {
742   DisplayImages( imageInfo(), image() );
743 }
744
745 // Distort image.  distorts an image using various distortion methods, by
746 // mapping color lookups of the source image to a new destination image
747 // usally of the same size as the source image, unless 'bestfit' is set to
748 // true.
749 void Magick::Image::distort ( const DistortImageMethod method_,
750                               const unsigned long number_arguments_,
751                               const double *arguments_,
752                               const bool bestfit_ )
753 {
754   ExceptionInfo exceptionInfo;
755   GetExceptionInfo( &exceptionInfo );
756   MagickCore::Image* newImage = DistortImage ( image(), method_,
757     number_arguments_, arguments_, bestfit_ == true ? MagickTrue : MagickFalse,
758     &exceptionInfo );
759   replaceImage( newImage );
760   throwException( exceptionInfo );
761   (void) DestroyExceptionInfo( &exceptionInfo );
762 }
763
764 // Draw on image using single drawable
765 void Magick::Image::draw ( const Magick::Drawable &drawable_ )
766 {
767   modifyImage();
768
769   DrawingWand *wand = DrawAllocateWand( options()->drawInfo(), image());
770
771   if(wand)
772     {
773       drawable_.operator()(wand);
774
775       if( constImage()->exception.severity == UndefinedException)
776         DrawRender(wand);
777
778       wand=DestroyDrawingWand(wand);
779     }
780
781   throwImageException();
782 }
783
784 // Draw on image using a drawable list
785 void Magick::Image::draw ( const std::list<Magick::Drawable> &drawable_ )
786 {
787   modifyImage();
788
789   DrawingWand *wand = DrawAllocateWand( options()->drawInfo(), image());
790
791   if(wand)
792     {
793       for( std::list<Magick::Drawable>::const_iterator p = drawable_.begin();
794            p != drawable_.end(); p++ )
795         {
796           p->operator()(wand);
797           if( constImage()->exception.severity != UndefinedException)
798             break;
799         }
800
801       if( constImage()->exception.severity == UndefinedException)
802         DrawRender(wand);
803
804       wand=DestroyDrawingWand(wand);
805     }
806
807   throwImageException();
808 }
809
810 // Hilight edges in image
811 void Magick::Image::edge ( const double radius_ )
812 {
813   ExceptionInfo exceptionInfo;
814   GetExceptionInfo( &exceptionInfo );
815   MagickCore::Image* newImage =
816     EdgeImage( image(), radius_, &exceptionInfo );
817   replaceImage( newImage );
818   throwException( exceptionInfo );
819   (void) DestroyExceptionInfo( &exceptionInfo );
820 }
821
822 // Emboss image (hilight edges)
823 void Magick::Image::emboss ( const double radius_, const double sigma_ )
824 {
825   ExceptionInfo exceptionInfo;
826   GetExceptionInfo( &exceptionInfo );
827   MagickCore::Image* newImage =
828     EmbossImage( image(), radius_, sigma_, &exceptionInfo );
829   replaceImage( newImage );
830   throwException( exceptionInfo );
831   (void) DestroyExceptionInfo( &exceptionInfo );
832 }
833
834 // Enhance image (minimize noise)
835 void Magick::Image::enhance ( void )
836 {
837   ExceptionInfo exceptionInfo;
838   GetExceptionInfo( &exceptionInfo );
839   MagickCore::Image* newImage =
840     EnhanceImage( image(), &exceptionInfo );
841   replaceImage( newImage );
842   throwException( exceptionInfo );
843   (void) DestroyExceptionInfo( &exceptionInfo );
844 }
845
846 // Equalize image (histogram equalization)
847 void Magick::Image::equalize ( void )
848 {
849   modifyImage();
850   EqualizeImage( image() );
851   throwImageException();
852 }
853
854 // Erase image to current "background color"
855 void Magick::Image::erase ( void )
856 {
857   modifyImage();
858   SetImageBackgroundColor( image() );
859   throwImageException();
860 }
861
862 // Extends image as defined by the geometry.
863 //
864 void Magick::Image::extent ( const Geometry &geometry_ )
865 {
866   RectangleInfo extentInfo = geometry_;
867   modifyImage();
868   SetImageExtent ( image(), extentInfo.width, extentInfo.height);
869   throwImageException();
870 }
871
872 // Flip image (reflect each scanline in the vertical direction)
873 void Magick::Image::flip ( void )
874 {
875   ExceptionInfo exceptionInfo;
876   GetExceptionInfo( &exceptionInfo );
877   MagickCore::Image* newImage =
878     FlipImage( image(), &exceptionInfo );
879   replaceImage( newImage );
880   throwException( exceptionInfo );
881   (void) DestroyExceptionInfo( &exceptionInfo );
882 }
883
884 // Flood-fill color across pixels that match the color of the
885 // target pixel and are neighbors of the target pixel.
886 // Uses current fuzz setting when determining color match.
887 void Magick::Image::floodFillColor( const unsigned int x_,
888                                     const unsigned int y_,
889                                     const Magick::Color &fillColor_ )
890 {
891   floodFillTexture( x_, y_, Image( Geometry( 1, 1), fillColor_ ) );
892 }
893 void Magick::Image::floodFillColor( const Geometry &point_,
894                                     const Magick::Color &fillColor_ )
895 {
896   floodFillTexture( point_, Image( Geometry( 1, 1), fillColor_) );
897 }
898
899 // Flood-fill color across pixels starting at target-pixel and
900 // stopping at pixels matching specified border color.
901 // Uses current fuzz setting when determining color match.
902 void Magick::Image::floodFillColor( const unsigned int x_,
903                                     const unsigned int y_,
904                                     const Magick::Color &fillColor_,
905                                     const Magick::Color &borderColor_ )
906 {
907   floodFillTexture( x_, y_, Image( Geometry( 1, 1), fillColor_),
908                     borderColor_ );
909 }
910 void Magick::Image::floodFillColor( const Geometry &point_,
911                                     const Magick::Color &fillColor_,
912                                     const Magick::Color &borderColor_ )
913 {
914   floodFillTexture( point_, Image( Geometry( 1, 1), fillColor_),
915                     borderColor_ );
916 }
917
918 // Floodfill pixels matching color (within fuzz factor) of target
919 // pixel(x,y) with replacement opacity value using method.
920 void Magick::Image::floodFillOpacity( const unsigned int x_,
921                                       const unsigned int y_,
922                                       const unsigned int opacity_,
923                                       const PaintMethod method_ )
924 {
925   modifyImage();
926   MagickPixelPacket target;
927   GetMagickPixelPacket(image(),&target);
928   PixelPacket pixel=static_cast<PixelPacket>(pixelColor(x_,y_));
929   target.red=pixel.red;
930   target.green=pixel.green;
931   target.blue=pixel.blue;
932   target.opacity=opacity_;
933   FloodfillPaintImage ( image(),
934                         DefaultChannels,
935                         options()->drawInfo(), // const DrawInfo *draw_info
936                         &target,
937                                         static_cast<long>(x_), static_cast<long>(y_),
938                         method_  == FloodfillMethod ? MagickFalse : MagickTrue);
939   throwImageException();
940 }
941
942 // Flood-fill texture across pixels that match the color of the
943 // target pixel and are neighbors of the target pixel.
944 // Uses current fuzz setting when determining color match.
945 void Magick::Image::floodFillTexture( const unsigned int x_,
946                                       const unsigned int y_,
947                                       const Magick::Image &texture_ )
948 {
949   modifyImage();
950
951   // Set drawing pattern
952   options()->fillPattern(texture_.constImage());
953
954   // Get pixel view
955   Pixels pixels(*this);
956   // Fill image
957   PixelPacket *p = pixels.get(x_, y_, 1, 1 );
958   MagickPixelPacket target;
959   GetMagickPixelPacket(constImage(),&target);
960   target.red=p->red;
961   target.green=p->green;
962   target.blue=p->blue;
963   if (p)
964     FloodfillPaintImage ( image(), // Image *image
965                           DefaultChannels,
966                           options()->drawInfo(), // const DrawInfo *draw_info
967                           &target, // const MagickPacket target
968                           static_cast<long>(x_), // const long x_offset
969                           static_cast<long>(y_), // const long y_offset
970                           MagickFalse // const PaintMethod method
971       );
972
973   throwImageException();
974 }
975 void Magick::Image::floodFillTexture( const Magick::Geometry &point_,
976                                       const Magick::Image &texture_ )
977 {
978   floodFillTexture( point_.xOff(), point_.yOff(), texture_ );
979 }
980
981 // Flood-fill texture across pixels starting at target-pixel and
982 // stopping at pixels matching specified border color.
983 // Uses current fuzz setting when determining color match.
984 void Magick::Image::floodFillTexture( const unsigned int x_,
985                                       const unsigned int y_,
986                                       const Magick::Image &texture_,
987                                       const Magick::Color &borderColor_ )
988 {
989   modifyImage();
990
991   // Set drawing fill pattern
992   options()->fillPattern(texture_.constImage());
993
994   MagickPixelPacket target;
995   GetMagickPixelPacket(constImage(),&target);
996   target.red=static_cast<PixelPacket>(borderColor_).red;
997   target.green=static_cast<PixelPacket>(borderColor_).green;
998   target.blue=static_cast<PixelPacket>(borderColor_).blue;
999   FloodfillPaintImage ( image(),
1000                         DefaultChannels,
1001                         options()->drawInfo(),
1002                         &target,
1003                         static_cast<long>(x_),
1004                         static_cast<long>(y_),
1005                         MagickTrue);
1006
1007   throwImageException();
1008 }
1009 void  Magick::Image::floodFillTexture( const Magick::Geometry &point_,
1010                                        const Magick::Image &texture_,
1011                                        const Magick::Color &borderColor_ )
1012 {
1013   floodFillTexture( point_.xOff(), point_.yOff(), texture_, borderColor_ );
1014 }
1015
1016 // Flop image (reflect each scanline in the horizontal direction)
1017 void Magick::Image::flop ( void )
1018 {
1019   ExceptionInfo exceptionInfo;
1020   GetExceptionInfo( &exceptionInfo );
1021   MagickCore::Image* newImage =
1022     FlopImage( image(), &exceptionInfo );
1023   replaceImage( newImage );
1024   throwException( exceptionInfo );
1025   (void) DestroyExceptionInfo( &exceptionInfo );
1026 }
1027
1028 // Frame image
1029 void Magick::Image::frame ( const Geometry &geometry_ )
1030 {
1031   FrameInfo info;
1032
1033   info.x           = static_cast<long>(geometry_.width());
1034   info.y           = static_cast<long>(geometry_.height());
1035   info.width       = columns() + ( static_cast<unsigned long>(info.x) << 1 );
1036   info.height      = rows() + ( static_cast<unsigned long>(info.y) << 1 );
1037   info.outer_bevel = geometry_.xOff();
1038   info.inner_bevel = geometry_.yOff();
1039
1040   ExceptionInfo exceptionInfo;
1041   GetExceptionInfo( &exceptionInfo );
1042   MagickCore::Image* newImage =
1043     FrameImage( image(), &info, &exceptionInfo );
1044   replaceImage( newImage );
1045   throwException( exceptionInfo );
1046   (void) DestroyExceptionInfo( &exceptionInfo );
1047 }
1048 void Magick::Image::frame ( const unsigned int width_,
1049                             const unsigned int height_,
1050                             const int outerBevel_, const int innerBevel_ )
1051 {
1052   FrameInfo info;
1053   info.x           = static_cast<long>(width_);
1054   info.y           = static_cast<long>(height_);
1055   info.width       = columns() + ( static_cast<unsigned long>(info.x) << 1 );
1056   info.height      = rows() + ( static_cast<unsigned long>(info.y) << 1 );
1057   info.outer_bevel = static_cast<long>(outerBevel_);
1058   info.inner_bevel = static_cast<long>(innerBevel_);
1059
1060   ExceptionInfo exceptionInfo;
1061   GetExceptionInfo( &exceptionInfo );
1062   MagickCore::Image* newImage =
1063     FrameImage( image(), &info, &exceptionInfo );
1064   replaceImage( newImage );
1065   throwException( exceptionInfo );
1066   (void) DestroyExceptionInfo( &exceptionInfo );
1067 }
1068
1069 // Convolve image.  Applies a mathematical expression to the image.
1070 void Magick::Image::fx ( const std::string expression,
1071                          const Magick::ChannelType channel )
1072 {
1073   ExceptionInfo exceptionInfo;
1074   GetExceptionInfo( &exceptionInfo );
1075   MagickCore::Image* newImage =
1076     FxImageChannel ( image(), channel, expression.c_str(), &exceptionInfo );
1077   replaceImage( newImage );
1078   throwException( exceptionInfo );
1079   (void) DestroyExceptionInfo( &exceptionInfo );
1080 }
1081
1082 // Gamma correct image
1083 void Magick::Image::gamma ( const double gamma_ )
1084 {
1085   char gamma[MaxTextExtent + 1];
1086   FormatMagickString( gamma, MaxTextExtent, "%3.6f", gamma_);
1087
1088   modifyImage();
1089   GammaImage ( image(), gamma );
1090 }
1091
1092 void Magick::Image::gamma ( const double gammaRed_,
1093                             const double gammaGreen_,
1094                             const double gammaBlue_ )
1095 {
1096   char gamma[MaxTextExtent + 1];
1097   FormatMagickString( gamma, MaxTextExtent, "%3.6f/%3.6f/%3.6f/",
1098                 gammaRed_, gammaGreen_, gammaBlue_);
1099
1100   modifyImage();
1101   GammaImage ( image(), gamma );
1102   throwImageException();
1103 }
1104
1105 // Gaussian blur image
1106 // The number of neighbor pixels to be included in the convolution
1107 // mask is specified by 'width_'. The standard deviation of the
1108 // gaussian bell curve is specified by 'sigma_'.
1109 void Magick::Image::gaussianBlur ( const double width_, const double sigma_ )
1110 {
1111   ExceptionInfo exceptionInfo;
1112   GetExceptionInfo( &exceptionInfo );
1113   MagickCore::Image* newImage =
1114     GaussianBlurImage( image(), width_, sigma_, &exceptionInfo );
1115   replaceImage( newImage );
1116   throwException( exceptionInfo );
1117   (void) DestroyExceptionInfo( &exceptionInfo );
1118 }
1119
1120 void Magick::Image::gaussianBlurChannel ( const ChannelType channel_,
1121                                           const double width_,
1122                                           const double sigma_ )
1123 {
1124   ExceptionInfo exceptionInfo;
1125   GetExceptionInfo( &exceptionInfo );
1126   MagickCore::Image* newImage =
1127     GaussianBlurImageChannel( image(), channel_, width_, sigma_, &exceptionInfo );
1128   replaceImage( newImage );
1129   throwException( exceptionInfo );
1130   (void) DestroyExceptionInfo( &exceptionInfo );
1131 }
1132
1133 // Apply a color lookup table (Hald CLUT) to the image.
1134 void  Magick::Image::haldClut ( const Image &clutImage_ )
1135 {
1136   modifyImage();
1137   (void) HaldClutImage( image(), clutImage_.constImage() );
1138   throwImageException();
1139 }
1140
1141 // Implode image
1142 void Magick::Image::implode ( const double factor_ )
1143 {
1144   ExceptionInfo exceptionInfo;
1145   GetExceptionInfo( &exceptionInfo );
1146   MagickCore::Image* newImage =
1147     ImplodeImage( image(), factor_, &exceptionInfo );
1148   replaceImage( newImage );
1149   throwException( exceptionInfo );
1150   (void) DestroyExceptionInfo( &exceptionInfo );
1151 }
1152
1153 // Level image. Adjust the levels of the image by scaling the colors
1154 // falling between specified white and black points to the full
1155 // available quantum range. The parameters provided represent the
1156 // black, mid (gamma), and white points.  The black point specifies
1157 // the darkest color in the image. Colors darker than the black point
1158 // are set to zero. Mid point (gamma) specifies a gamma correction to
1159 // apply to the image. White point specifies the lightest color in the
1160 // image.  Colors brighter than the white point are set to the maximum
1161 // quantum value. The black and white point have the valid range 0 to
1162 // QuantumRange while gamma has a useful range of 0 to ten.
1163 void Magick::Image::level ( const double black_point,
1164                             const double white_point,
1165                             const double gamma )
1166 {
1167   modifyImage();
1168   char levels[MaxTextExtent];
1169   FormatMagickString( levels, MaxTextExtent, "%g,%g,%g",black_point,white_point,gamma);
1170   (void) LevelImage( image(), levels );
1171   throwImageException();
1172 }
1173
1174 // Level image channel. Adjust the levels of the image channel by
1175 // scaling the values falling between specified white and black points
1176 // to the full available quantum range. The parameters provided
1177 // represent the black, mid (gamma), and white points.  The black
1178 // point specifies the darkest color in the image. Colors darker than
1179 // the black point are set to zero. Mid point (gamma) specifies a
1180 // gamma correction to apply to the image. White point specifies the
1181 // lightest color in the image.  Colors brighter than the white point
1182 // are set to the maximum quantum value. The black and white point
1183 // have the valid range 0 to QuantumRange while gamma has a useful range of
1184 // 0 to ten.
1185 void  Magick::Image::levelChannel ( const Magick::ChannelType channel,
1186                                     const double black_point,
1187                                     const double white_point,
1188                                     const double gamma )
1189 {
1190   modifyImage();
1191   (void) LevelImageChannel( image(), channel, black_point, white_point,
1192                             gamma );
1193   throwImageException();
1194 }
1195
1196 // Magnify image by integral size
1197 void Magick::Image::magnify ( void )
1198 {
1199   ExceptionInfo exceptionInfo;
1200   GetExceptionInfo( &exceptionInfo );
1201   MagickCore::Image* newImage =
1202     MagnifyImage( image(), &exceptionInfo );
1203   replaceImage( newImage );
1204   throwException( exceptionInfo );
1205   (void) DestroyExceptionInfo( &exceptionInfo );
1206 }
1207
1208 // Remap image colors with closest color from reference image
1209 void Magick::Image::map ( const Image &mapImage_ , const bool dither_ )
1210 {
1211   modifyImage();
1212   options()->quantizeDither( dither_ );
1213   RemapImage ( options()->quantizeInfo(), image(),
1214              mapImage_.constImage());
1215   throwImageException();
1216 }
1217 // Floodfill designated area with replacement opacity value
1218 void Magick::Image::matteFloodfill ( const Color &target_ ,
1219                                      const unsigned int opacity_,
1220                                      const int x_, const int y_,
1221                                      const Magick::PaintMethod method_ )
1222 {
1223   modifyImage();
1224   MagickPixelPacket target;
1225   GetMagickPixelPacket(constImage(),&target);
1226   target.red=static_cast<PixelPacket>(target_).red;
1227   target.green=static_cast<PixelPacket>(target_).green;
1228   target.blue=static_cast<PixelPacket>(target_).blue;
1229   target.opacity=opacity_;
1230   FloodfillPaintImage ( image(), OpacityChannel, options()->drawInfo(), &target,
1231     x_, y_, method_ == FloodfillMethod ? MagickFalse : MagickTrue);
1232   throwImageException();
1233 }
1234
1235 // Filter image by replacing each pixel component with the median
1236 // color in a circular neighborhood
1237 void Magick::Image::medianFilter ( const double radius_ )
1238 {
1239   ExceptionInfo exceptionInfo;
1240   GetExceptionInfo( &exceptionInfo );
1241   MagickCore::Image* newImage =
1242     MedianFilterImage ( image(), radius_, &exceptionInfo );
1243   replaceImage( newImage );
1244   throwException( exceptionInfo );
1245   (void) DestroyExceptionInfo( &exceptionInfo );
1246 }
1247
1248 // Reduce image by integral size
1249 void Magick::Image::minify ( void )
1250 {
1251   ExceptionInfo exceptionInfo;
1252   GetExceptionInfo( &exceptionInfo );
1253   MagickCore::Image* newImage =
1254     MinifyImage( image(), &exceptionInfo );
1255   replaceImage( newImage );
1256   throwException( exceptionInfo );
1257   (void) DestroyExceptionInfo( &exceptionInfo );
1258 }
1259
1260 // Modulate percent hue, saturation, and brightness of an image
1261 void Magick::Image::modulate ( const double brightness_,
1262                                const double saturation_,
1263                                const double hue_ )
1264 {
1265   char modulate[MaxTextExtent + 1];
1266   FormatMagickString( modulate, MaxTextExtent, "%3.6f,%3.6f,%3.6f",
1267                 brightness_, saturation_, hue_);
1268
1269   modifyImage();
1270   ModulateImage( image(), modulate );
1271   throwImageException();
1272 }
1273
1274 // Motion blur image with specified blur factor
1275 // The radius_ parameter specifies the radius of the Gaussian, in
1276 // pixels, not counting the center pixel.  The sigma_ parameter
1277 // specifies the standard deviation of the Laplacian, in pixels.
1278 // The angle_ parameter specifies the angle the object appears
1279 // to be comming from (zero degrees is from the right).
1280 void            Magick::Image::motionBlur ( const double radius_,
1281                                             const double sigma_,
1282                                             const double angle_ )
1283 {
1284   ExceptionInfo exceptionInfo;
1285   GetExceptionInfo( &exceptionInfo );
1286   MagickCore::Image* newImage =
1287     MotionBlurImage( image(), radius_, sigma_, angle_, &exceptionInfo);
1288   replaceImage( newImage );
1289   throwException( exceptionInfo );
1290   (void) DestroyExceptionInfo( &exceptionInfo );
1291 }
1292     
1293 // Negate image.  Set grayscale_ to true to effect grayscale values
1294 // only
1295 void Magick::Image::negate ( const bool grayscale_ )
1296 {
1297   modifyImage();
1298   NegateImage ( image(), grayscale_ == true ? MagickTrue : MagickFalse );
1299   throwImageException();
1300 }
1301
1302 // Normalize image
1303 void Magick::Image::normalize ( void )
1304 {
1305   modifyImage();
1306   NormalizeImage ( image() );
1307   throwImageException();
1308 }
1309
1310 // Oilpaint image
1311 void Magick::Image::oilPaint ( const double radius_ )
1312 {
1313   ExceptionInfo exceptionInfo;
1314   GetExceptionInfo( &exceptionInfo );
1315   MagickCore::Image* newImage =
1316     OilPaintImage( image(), radius_, &exceptionInfo );
1317   replaceImage( newImage );
1318   throwException( exceptionInfo );
1319   (void) DestroyExceptionInfo( &exceptionInfo );
1320 }
1321
1322 // Set or attenuate the opacity channel. If the image pixels are
1323 // opaque then they are set to the specified opacity value, otherwise
1324 // they are blended with the supplied opacity value.  The value of
1325 // opacity_ ranges from 0 (completely opaque) to QuantumRange. The defines
1326 // OpaqueOpacity and TransparentOpacity are available to specify
1327 // completely opaque or completely transparent, respectively.
1328 void Magick::Image::opacity ( const unsigned int opacity_ )
1329 {
1330   modifyImage();
1331   SetImageOpacity( image(), opacity_ );
1332 }
1333
1334 // Change the color of an opaque pixel to the pen color.
1335 void Magick::Image::opaque ( const Color &opaqueColor_,
1336                              const Color &penColor_ )
1337 {
1338   if ( !opaqueColor_.isValid() )
1339   {
1340     throwExceptionExplicit( OptionError,
1341                             "Opaque color argument is invalid" );
1342   }
1343   if ( !penColor_.isValid() )
1344   {
1345     throwExceptionExplicit( OptionError,
1346                             "Pen color argument is invalid" );
1347   }
1348
1349   modifyImage();
1350   std::string opaqueColor = opaqueColor_;
1351   std::string penColor = penColor_;
1352
1353   MagickPixelPacket opaque;
1354   MagickPixelPacket pen;
1355   (void) QueryMagickColor(std::string(opaqueColor_).c_str(),&opaque,&image()->exception);
1356   (void) QueryMagickColor(std::string(penColor_).c_str(),&pen,&image()->exception);
1357   OpaquePaintImage ( image(), &opaque, &pen, MagickFalse );
1358   throwImageException();
1359 }
1360
1361 // Ping is similar to read except only enough of the image is read to
1362 // determine the image columns, rows, and filesize.  Access the
1363 // columns(), rows(), and fileSize() attributes after invoking ping.
1364 // The image data is not valid after calling ping.
1365 void Magick::Image::ping ( const std::string &imageSpec_ )
1366 {
1367   options()->fileName( imageSpec_ );
1368   ExceptionInfo exceptionInfo;
1369   GetExceptionInfo( &exceptionInfo );
1370   MagickCore::Image* image =
1371     PingImage( imageInfo(), &exceptionInfo );
1372   replaceImage( image );
1373   throwException( exceptionInfo );
1374   (void) DestroyExceptionInfo( &exceptionInfo );
1375 }
1376
1377 // Ping is similar to read except only enough of the image is read
1378 // to determine the image columns, rows, and filesize.  Access the
1379 // columns(), rows(), and fileSize() attributes after invoking
1380 // ping.  The image data is not valid after calling ping.
1381 void Magick::Image::ping ( const Blob& blob_ )
1382 {
1383   ExceptionInfo exceptionInfo;
1384   GetExceptionInfo( &exceptionInfo );
1385   MagickCore::Image* image =
1386     PingBlob( imageInfo(), blob_.data(), blob_.length(), &exceptionInfo );
1387   replaceImage( image );
1388   throwException( exceptionInfo );
1389   (void) DestroyExceptionInfo( &exceptionInfo );
1390 }
1391
1392 // Execute a named process module using an argc/argv syntax similar to
1393 // that accepted by a C 'main' routine. An exception is thrown if the
1394 // requested process module doesn't exist, fails to load, or fails during
1395 // execution.
1396 void Magick::Image::process( std::string name_, const int argc, const char **argv )
1397 {
1398   modifyImage();
1399
1400   unsigned int status = 
1401     InvokeDynamicImageFilter( name_.c_str(), &image(), argc, argv,
1402       &image()->exception );
1403
1404   if (status == false)
1405     throwException( image()->exception );
1406 }
1407
1408 // Quantize colors in image using current quantization settings
1409 // Set measureError_ to true in order to measure quantization error
1410 void Magick::Image::quantize ( const bool measureError_  )
1411 {
1412   modifyImage();
1413  
1414   if (measureError_)
1415     options()->quantizeInfo()->measure_error=MagickTrue;
1416   else
1417     options()->quantizeInfo()->measure_error=MagickFalse;
1418
1419   QuantizeImage( options()->quantizeInfo(), image() );
1420
1421   throwImageException();
1422 }
1423
1424 // Apply an arithmetic or bitwise operator to the image pixel quantums.
1425 void Magick::Image::quantumOperator ( const ChannelType channel_,
1426                                       const MagickEvaluateOperator operator_,
1427                                       double rvalue_)
1428 {
1429   ExceptionInfo exceptionInfo;
1430   GetExceptionInfo( &exceptionInfo );
1431   EvaluateImageChannel( image(), channel_, operator_, rvalue_, &exceptionInfo);
1432   throwException( exceptionInfo );
1433   (void) DestroyExceptionInfo( &exceptionInfo );
1434 }
1435
1436 void Magick::Image::quantumOperator ( const int x_,const int y_,
1437                                       const unsigned int columns_,
1438                                       const unsigned int rows_,
1439                                       const ChannelType channel_,
1440                                       const MagickEvaluateOperator operator_,
1441                                       const double rvalue_)
1442 {
1443   ExceptionInfo exceptionInfo;
1444   GetExceptionInfo( &exceptionInfo );
1445   RectangleInfo geometry;
1446   geometry.width = columns_;
1447   geometry.height = rows_;
1448   geometry.x = x_;
1449   geometry.y = y_;
1450   MagickCore::Image *crop_image = CropImage( image(), &geometry,
1451     &exceptionInfo );
1452   EvaluateImageChannel( crop_image, channel_, operator_, rvalue_,
1453     &exceptionInfo );
1454   (void) CompositeImage( image(), image()->matte != MagickFalse ?
1455     OverCompositeOp : CopyCompositeOp, crop_image, geometry.x, geometry.y );
1456   crop_image = DestroyImageList(crop_image);
1457   throwException( exceptionInfo );
1458   (void) DestroyExceptionInfo( &exceptionInfo );
1459 }
1460
1461 // Raise image (lighten or darken the edges of an image to give a 3-D
1462 // raised or lowered effect)
1463 void Magick::Image::raise ( const Geometry &geometry_ ,
1464                             const bool raisedFlag_ )
1465 {
1466   RectangleInfo raiseInfo = geometry_;
1467   modifyImage();
1468   RaiseImage ( image(), &raiseInfo, raisedFlag_ == true ? MagickTrue : MagickFalse );
1469   throwImageException();
1470 }
1471
1472
1473 // Random threshold image.
1474 //
1475 // Changes the value of individual pixels based on the intensity
1476 // of each pixel compared to a random threshold.  The result is a
1477 // low-contrast, two color image.  The thresholds_ argument is a
1478 // geometry containing LOWxHIGH thresholds.  If the string
1479 // contains 2x2, 3x3, or 4x4, then an ordered dither of order 2,
1480 // 3, or 4 will be performed instead.  If a channel_ argument is
1481 // specified then only the specified channel is altered.  This is
1482 // a very fast alternative to 'quantize' based dithering.
1483 void Magick::Image::randomThreshold( const Geometry &thresholds_ )
1484 {
1485   randomThresholdChannel(thresholds_,DefaultChannels);
1486 }
1487 void Magick::Image::randomThresholdChannel( const Geometry &thresholds_,
1488                                             const ChannelType channel_ )
1489 {
1490   ExceptionInfo exceptionInfo;
1491   GetExceptionInfo( &exceptionInfo );
1492   modifyImage();
1493   (void) RandomThresholdImageChannel( image(),
1494                                       channel_,
1495                                       static_cast<std::string>(thresholds_).c_str(),
1496                                       &exceptionInfo );
1497   throwImageException();
1498   (void) DestroyExceptionInfo( &exceptionInfo );
1499 }
1500     
1501 // Read image into current object
1502 void Magick::Image::read ( const std::string &imageSpec_ )
1503 {
1504   options()->fileName( imageSpec_ );
1505
1506   ExceptionInfo exceptionInfo;
1507   GetExceptionInfo( &exceptionInfo );
1508   MagickCore::Image* image =
1509     ReadImage( imageInfo(), &exceptionInfo );
1510
1511   // Ensure that multiple image frames were not read.
1512   if ( image && image->next )
1513     {
1514       // Destroy any extra image frames
1515       MagickCore::Image* next = image->next;
1516       image->next = 0;
1517       next->previous = 0;
1518       DestroyImageList( next );
1519  
1520     }
1521   replaceImage( image );
1522   throwException( exceptionInfo );
1523   if ( image )
1524     throwException( image->exception );
1525   (void) DestroyExceptionInfo( &exceptionInfo );
1526 }
1527
1528 // Read image of specified size into current object
1529 void Magick::Image::read ( const Geometry &size_,
1530                            const std::string &imageSpec_ )
1531 {
1532   size( size_ );
1533   read( imageSpec_ );
1534 }
1535
1536 // Read image from in-memory BLOB
1537 void Magick::Image::read ( const Blob &blob_ )
1538 {
1539   ExceptionInfo exceptionInfo;
1540   GetExceptionInfo( &exceptionInfo );
1541   MagickCore::Image* image =
1542     BlobToImage( imageInfo(),
1543                  static_cast<const void *>(blob_.data()),
1544                  blob_.length(), &exceptionInfo );
1545   replaceImage( image );
1546   throwException( exceptionInfo );
1547   if ( image )
1548     throwException( image->exception );
1549   (void) DestroyExceptionInfo( &exceptionInfo );
1550 }
1551
1552 // Read image of specified size from in-memory BLOB
1553 void  Magick::Image::read ( const Blob &blob_,
1554                             const Geometry &size_ )
1555 {
1556   // Set image size
1557   size( size_ );
1558   // Read from Blob
1559   read( blob_ );
1560 }
1561
1562 // Read image of specified size and depth from in-memory BLOB
1563 void Magick::Image::read ( const Blob &blob_,
1564                            const Geometry &size_,
1565                            const unsigned int depth_ )
1566 {
1567   // Set image size
1568   size( size_ );
1569   // Set image depth
1570   depth( depth_ );
1571   // Read from Blob
1572   read( blob_ );
1573 }
1574
1575 // Read image of specified size, depth, and format from in-memory BLOB
1576 void Magick::Image::read ( const Blob &blob_,
1577                            const Geometry &size_,
1578                            const unsigned int depth_,
1579                            const std::string &magick_ )
1580 {
1581   // Set image size
1582   size( size_ );
1583   // Set image depth
1584   depth( depth_ );
1585   // Set image magick
1586   magick( magick_ );
1587   // Set explicit image format
1588   fileName( magick_ + ':');
1589   // Read from Blob
1590   read( blob_ );
1591 }
1592
1593 // Read image of specified size, and format from in-memory BLOB
1594 void Magick::Image::read ( const Blob &blob_,
1595                            const Geometry &size_,
1596                            const std::string &magick_ )
1597 {
1598   // Set image size
1599   size( size_ );
1600   // Set image magick
1601   magick( magick_ );
1602   // Set explicit image format
1603   fileName( magick_ + ':');
1604   // Read from Blob
1605   read( blob_ );
1606 }
1607
1608 // Read image based on raw pixels in memory (ConstituteImage)
1609 void Magick::Image::read ( const unsigned int width_,
1610                            const unsigned int height_,
1611                            const std::string &map_,
1612                            const StorageType type_,
1613                            const void *pixels_ )
1614 {
1615   ExceptionInfo exceptionInfo;
1616   GetExceptionInfo( &exceptionInfo );
1617   MagickCore::Image* image =
1618     ConstituteImage( width_, height_, map_.c_str(), type_, pixels_,
1619                      &exceptionInfo );
1620   replaceImage( image );
1621   throwException( exceptionInfo );
1622   if ( image )
1623     throwException( image->exception );
1624   (void) DestroyExceptionInfo( &exceptionInfo );
1625 }
1626
1627 // Apply a color matrix to the image channels.  The user supplied
1628 // matrix may be of order 1 to 5 (1x1 through 5x5).
1629 void Magick::Image::recolor (const unsigned int order_,
1630          const double *color_matrix_)
1631 {
1632   ExceptionInfo exceptionInfo;
1633   GetExceptionInfo( &exceptionInfo );
1634   MagickCore::Image* newImage =
1635     RecolorImage( image(), order_, color_matrix_, &exceptionInfo );
1636   replaceImage( newImage );
1637   throwException( exceptionInfo );
1638   (void) DestroyExceptionInfo( &exceptionInfo );
1639 }
1640
1641 // Reduce noise in image
1642 void Magick::Image::reduceNoise ( const double order_ )
1643 {
1644   ExceptionInfo exceptionInfo;
1645   GetExceptionInfo( &exceptionInfo );
1646   MagickCore::Image* newImage =
1647     ReduceNoiseImage( image(), order_, &exceptionInfo );
1648   replaceImage( newImage );
1649   throwException( exceptionInfo );
1650   (void) DestroyExceptionInfo( &exceptionInfo );
1651 }
1652
1653 // Resize image
1654 void Magick::Image::resize( const Geometry &geometry_ )
1655 {
1656   // Calculate new size.  This code should be supported using binary arguments
1657   // in the ImageMagick library.
1658   long x = 0;
1659   long y = 0;
1660   unsigned long width = columns();
1661   unsigned long height = rows();
1662
1663   ParseMetaGeometry (static_cast<std::string>(geometry_).c_str(),
1664                      &x, &y,
1665                      &width, &height );
1666
1667   ExceptionInfo exceptionInfo;
1668   GetExceptionInfo( &exceptionInfo );
1669   MagickCore::Image* newImage =
1670     ResizeImage( image(),
1671                width,
1672                height,
1673                image()->filter,
1674                1.0,
1675                &exceptionInfo);
1676   replaceImage( newImage );
1677   throwException( exceptionInfo );
1678   (void) DestroyExceptionInfo( &exceptionInfo );
1679 }
1680
1681 // Roll image
1682 void Magick::Image::roll ( const Geometry &roll_ )
1683 {
1684   long xOff = roll_.xOff();
1685   if ( roll_.xNegative() )
1686     xOff = 0 - xOff;
1687   long yOff = roll_.yOff();
1688   if ( roll_.yNegative() )
1689     yOff = 0 - yOff;
1690
1691   ExceptionInfo exceptionInfo;
1692   GetExceptionInfo( &exceptionInfo );
1693   MagickCore::Image* newImage =
1694     RollImage( image(), xOff, yOff, &exceptionInfo );
1695   replaceImage( newImage );
1696   throwException( exceptionInfo );
1697   (void) DestroyExceptionInfo( &exceptionInfo );
1698 }
1699 void Magick::Image::roll ( const unsigned int columns_,
1700                            const unsigned int rows_ )
1701 {
1702   ExceptionInfo exceptionInfo;
1703   GetExceptionInfo( &exceptionInfo );
1704   MagickCore::Image* newImage =
1705     RollImage( image(),
1706                static_cast<long>(columns_),
1707                static_cast<long>(rows_), &exceptionInfo );
1708   replaceImage( newImage );
1709   throwException( exceptionInfo );
1710   (void) DestroyExceptionInfo( &exceptionInfo );
1711 }
1712
1713 // Rotate image
1714 void Magick::Image::rotate ( const double degrees_ )
1715 {
1716   ExceptionInfo exceptionInfo;
1717   GetExceptionInfo( &exceptionInfo );
1718   MagickCore::Image* newImage =
1719     RotateImage( image(), degrees_, &exceptionInfo);
1720   replaceImage( newImage );
1721   throwException( exceptionInfo );
1722   (void) DestroyExceptionInfo( &exceptionInfo );
1723 }
1724
1725 // Sample image
1726 void Magick::Image::sample ( const Geometry &geometry_ )
1727 {
1728   long x = 0;
1729   long y = 0;
1730   unsigned long width = columns();
1731   unsigned long height = rows();
1732
1733   ParseMetaGeometry (static_cast<std::string>(geometry_).c_str(),
1734                       &x, &y,
1735                       &width, &height );
1736
1737   ExceptionInfo exceptionInfo;
1738   GetExceptionInfo( &exceptionInfo );
1739   MagickCore::Image* newImage =
1740     SampleImage( image(), width, height, &exceptionInfo );
1741   replaceImage( newImage );
1742   throwException( exceptionInfo );
1743   (void) DestroyExceptionInfo( &exceptionInfo );
1744 }
1745
1746 // Scale image
1747 void Magick::Image::scale ( const Geometry &geometry_ )
1748 {
1749   long x = 0;
1750   long y = 0;
1751   unsigned long width = columns();
1752   unsigned long height = rows();
1753
1754   ParseMetaGeometry (static_cast<std::string>(geometry_).c_str(),
1755                       &x, &y,
1756                       &width, &height );
1757
1758   ExceptionInfo exceptionInfo;
1759   GetExceptionInfo( &exceptionInfo );
1760   MagickCore::Image* newImage =
1761     ScaleImage( image(), width, height, &exceptionInfo );
1762   replaceImage( newImage );
1763   throwException( exceptionInfo );
1764   (void) DestroyExceptionInfo( &exceptionInfo );
1765 }
1766
1767 // Segment (coalesce similar image components) by analyzing the
1768 // histograms of the color components and identifying units that are
1769 // homogeneous with the fuzzy c-means technique.
1770 void Magick::Image::segment ( const double clusterThreshold_, 
1771                               const double smoothingThreshold_ )
1772 {
1773   modifyImage();
1774   SegmentImage ( image(),
1775                  options()->quantizeColorSpace(),
1776                  (MagickBooleanType) options()->verbose(),
1777                  clusterThreshold_,
1778                  smoothingThreshold_ );
1779   throwImageException();
1780   SyncImage( image() );
1781   throwImageException();
1782 }
1783
1784 // Shade image using distant light source
1785 void Magick::Image::shade ( const double azimuth_,
1786                             const double elevation_,
1787                             const bool   colorShading_ )
1788 {
1789   ExceptionInfo exceptionInfo;
1790   GetExceptionInfo( &exceptionInfo );
1791   MagickCore::Image* newImage =
1792     ShadeImage( image(),
1793                 colorShading_ == true ? MagickTrue : MagickFalse,
1794                 azimuth_,
1795                 elevation_,
1796                 &exceptionInfo);
1797   replaceImage( newImage );
1798   throwException( exceptionInfo );
1799   (void) DestroyExceptionInfo( &exceptionInfo );
1800 }
1801
1802 // Sharpen pixels in image
1803 void Magick::Image::sharpen ( const double radius_, const double sigma_ )
1804 {
1805   ExceptionInfo exceptionInfo;
1806   GetExceptionInfo( &exceptionInfo );
1807   MagickCore::Image* newImage =
1808     SharpenImage( image(),
1809                   radius_,
1810                   sigma_,
1811                   &exceptionInfo );
1812   replaceImage( newImage );
1813   throwException( exceptionInfo );
1814   (void) DestroyExceptionInfo( &exceptionInfo );
1815 }
1816
1817 void Magick::Image::sharpenChannel ( const ChannelType channel_,
1818                                      const double radius_, const double sigma_ )
1819 {
1820   ExceptionInfo exceptionInfo;
1821   GetExceptionInfo( &exceptionInfo );
1822   MagickCore::Image* newImage =
1823     SharpenImageChannel( image(),
1824                          channel_,
1825                          radius_,
1826                          sigma_,
1827                          &exceptionInfo );
1828   replaceImage( newImage );
1829   throwException( exceptionInfo );
1830   (void) DestroyExceptionInfo( &exceptionInfo );
1831 }
1832
1833 // Shave pixels from image edges.
1834 void Magick::Image::shave ( const Geometry &geometry_ )
1835 {
1836   RectangleInfo shaveInfo = geometry_;
1837   ExceptionInfo exceptionInfo;
1838   GetExceptionInfo( &exceptionInfo );
1839   MagickCore::Image* newImage =
1840     ShaveImage( image(),
1841                &shaveInfo,
1842                &exceptionInfo);
1843   replaceImage( newImage );
1844   throwException( exceptionInfo );
1845   (void) DestroyExceptionInfo( &exceptionInfo );
1846 }
1847
1848 // Shear image
1849 void Magick::Image::shear ( const double xShearAngle_,
1850                             const double yShearAngle_ )
1851 {
1852   ExceptionInfo exceptionInfo;
1853   GetExceptionInfo( &exceptionInfo );
1854   MagickCore::Image* newImage =
1855     ShearImage( image(),
1856                 xShearAngle_,
1857                 yShearAngle_,
1858                 &exceptionInfo );
1859   replaceImage( newImage );
1860   throwException( exceptionInfo );
1861   (void) DestroyExceptionInfo( &exceptionInfo );
1862 }
1863
1864 // Contrast image
1865 void Magick::Image::sigmoidalContrast ( const unsigned int sharpen_, const double contrast, const double midpoint )
1866 {
1867   modifyImage();
1868   (void) SigmoidalContrastImageChannel( image(), DefaultChannels, (MagickBooleanType) sharpen_, contrast, midpoint );
1869   throwImageException();
1870 }
1871
1872 // Solarize image (similar to effect seen when exposing a photographic
1873 // film to light during the development process)
1874 void Magick::Image::solarize ( const double factor_ )
1875 {
1876   modifyImage();
1877   SolarizeImage ( image(), factor_ );
1878   throwImageException();
1879 }
1880
1881 // Sparse color image, given a set of coordinates, interpolates the colors
1882 // found at those coordinates, across the whole image, using various methods.
1883 //
1884 void Magick::Image::sparseColor ( const ChannelType channel,
1885                                   const SparseColorMethod method,
1886                                   const unsigned long number_arguments,
1887                                   const double *arguments )
1888 {
1889   ExceptionInfo exceptionInfo;
1890   GetExceptionInfo( &exceptionInfo );
1891   MagickCore::Image* newImage = SparseColorImage ( image(), channel, method,
1892     number_arguments, arguments, &exceptionInfo );
1893   replaceImage( newImage );
1894   throwException( exceptionInfo );
1895   (void) DestroyExceptionInfo( &exceptionInfo );
1896 }
1897
1898 // Spread pixels randomly within image by specified ammount
1899 void Magick::Image::spread ( const unsigned int amount_ )
1900 {
1901   ExceptionInfo exceptionInfo;
1902   GetExceptionInfo( &exceptionInfo );
1903   MagickCore::Image* newImage =
1904     SpreadImage( image(),
1905                  amount_,
1906                  &exceptionInfo );
1907   replaceImage( newImage );
1908   throwException( exceptionInfo );
1909   (void) DestroyExceptionInfo( &exceptionInfo );
1910 }
1911
1912 // Add a digital watermark to the image (based on second image)
1913 void Magick::Image::stegano ( const Image &watermark_ )
1914 {
1915   ExceptionInfo exceptionInfo;
1916   GetExceptionInfo( &exceptionInfo );
1917   MagickCore::Image* newImage =
1918     SteganoImage( image(),
1919                   watermark_.constImage(),
1920                   &exceptionInfo);
1921   replaceImage( newImage );
1922   throwException( exceptionInfo );
1923   (void) DestroyExceptionInfo( &exceptionInfo );
1924 }
1925
1926 // Stereo image (left image is current image)
1927 void Magick::Image::stereo ( const Image &rightImage_ )
1928 {
1929   ExceptionInfo exceptionInfo;
1930   GetExceptionInfo( &exceptionInfo );
1931   MagickCore::Image* newImage =
1932     StereoImage( image(),
1933                  rightImage_.constImage(),
1934                  &exceptionInfo);
1935   replaceImage( newImage );
1936   throwException( exceptionInfo );
1937   (void) DestroyExceptionInfo( &exceptionInfo );
1938 }
1939
1940 // Swirl image
1941 void Magick::Image::swirl ( const double degrees_ )
1942 {
1943   ExceptionInfo exceptionInfo;
1944   GetExceptionInfo( &exceptionInfo );
1945   MagickCore::Image* newImage =
1946     SwirlImage( image(), degrees_,
1947                 &exceptionInfo);
1948   replaceImage( newImage );
1949   throwException( exceptionInfo );
1950   (void) DestroyExceptionInfo( &exceptionInfo );
1951 }
1952
1953 // Texture image
1954 void Magick::Image::texture ( const Image &texture_ )
1955 {
1956   modifyImage();
1957   TextureImage( image(), texture_.constImage() );
1958   throwImageException();
1959 }
1960
1961 // Threshold image
1962 void Magick::Image::threshold ( const double threshold_ )
1963 {
1964   modifyImage();
1965   BilevelImage( image(), threshold_ );
1966   throwImageException();
1967 }
1968
1969 // Transform image based on image geometry only
1970 void Magick::Image::transform ( const Geometry &imageGeometry_ )
1971 {
1972   modifyImage();
1973   TransformImage ( &(image()), 0,
1974                    std::string(imageGeometry_).c_str() );
1975   throwImageException();
1976 }
1977 // Transform image based on image and crop geometries
1978 void Magick::Image::transform ( const Geometry &imageGeometry_,
1979                                 const Geometry &cropGeometry_ )
1980 {
1981   modifyImage();
1982   TransformImage ( &(image()), std::string(cropGeometry_).c_str(),
1983                    std::string(imageGeometry_).c_str() );
1984   throwImageException();
1985 }
1986
1987 // Add matte image to image, setting pixels matching color to transparent
1988 void Magick::Image::transparent ( const Color &color_ )
1989 {
1990   if ( !color_.isValid() )
1991   {
1992     throwExceptionExplicit( OptionError,
1993                             "Color argument is invalid" );
1994   }
1995
1996   std::string color = color_;
1997
1998   MagickPixelPacket target;
1999   (void) QueryMagickColor(std::string(color_).c_str(),&target,&image()->exception);
2000   modifyImage();
2001   TransparentPaintImage ( image(), &target, TransparentOpacity, MagickFalse );
2002   throwImageException();
2003 }
2004
2005 // Add matte image to image, setting pixels matching color to transparent
2006 void Magick::Image::transparentChroma(const Color &colorLow_,
2007   const Color &colorHigh_)
2008 {
2009   if ( !colorLow_.isValid() || !colorHigh_.isValid() )
2010   {
2011     throwExceptionExplicit( OptionError,
2012                             "Color argument is invalid" );
2013   }
2014
2015   std::string colorLow = colorLow_;
2016   std::string colorHigh = colorHigh_;
2017
2018   MagickPixelPacket targetLow;
2019   MagickPixelPacket targetHigh;
2020   (void) QueryMagickColor(std::string(colorLow_).c_str(),&targetLow,
2021     &image()->exception);
2022   (void) QueryMagickColor(std::string(colorHigh_).c_str(),&targetHigh,
2023     &image()->exception);
2024   modifyImage();
2025   TransparentPaintImageChroma ( image(), &targetLow, &targetHigh,
2026     TransparentOpacity, MagickFalse );
2027   throwImageException();
2028 }
2029
2030
2031 // Trim edges that are the background color from the image
2032 void Magick::Image::trim ( void )
2033 {
2034   ExceptionInfo exceptionInfo;
2035   GetExceptionInfo( &exceptionInfo );
2036   MagickCore::Image* newImage =
2037     TrimImage( image(), &exceptionInfo);
2038   replaceImage( newImage );
2039   throwException( exceptionInfo );
2040   (void) DestroyExceptionInfo( &exceptionInfo );
2041 }
2042
2043 // Replace image with a sharpened version of the original image
2044 // using the unsharp mask algorithm.
2045 //  radius_
2046 //    the radius of the Gaussian, in pixels, not counting the
2047 //    center pixel.
2048 //  sigma_
2049 //    the standard deviation of the Gaussian, in pixels.
2050 //  amount_
2051 //    the percentage of the difference between the original and
2052 //    the blur image that is added back into the original.
2053 // threshold_
2054 //   the threshold in pixels needed to apply the diffence amount.
2055 void Magick::Image::unsharpmask ( const double radius_,
2056                                   const double sigma_,
2057                                   const double amount_,
2058                                   const double threshold_ )
2059 {
2060   ExceptionInfo exceptionInfo;
2061   GetExceptionInfo( &exceptionInfo );
2062   MagickCore::Image* newImage =
2063     UnsharpMaskImage( image(),
2064                       radius_,
2065                       sigma_,
2066                       amount_,
2067                       threshold_,
2068                       &exceptionInfo );
2069   replaceImage( newImage );
2070   throwException( exceptionInfo );
2071   (void) DestroyExceptionInfo( &exceptionInfo );
2072 }
2073
2074 void Magick::Image::unsharpmaskChannel ( const ChannelType channel_,
2075                                          const double radius_,
2076                                          const double sigma_,
2077                                          const double amount_,
2078                                          const double threshold_ )
2079 {
2080   ExceptionInfo exceptionInfo;
2081   GetExceptionInfo( &exceptionInfo );
2082   MagickCore::Image* newImage =
2083     UnsharpMaskImageChannel( image(),
2084                              channel_,
2085                              radius_,
2086                              sigma_,
2087                              amount_,
2088                              threshold_,
2089                              &exceptionInfo );
2090   replaceImage( newImage );
2091   throwException( exceptionInfo );
2092   (void) DestroyExceptionInfo( &exceptionInfo );
2093 }
2094
2095 // Map image pixels to a sine wave
2096 void Magick::Image::wave ( const double amplitude_, const double wavelength_ )
2097 {
2098   ExceptionInfo exceptionInfo;
2099   GetExceptionInfo( &exceptionInfo );
2100   MagickCore::Image* newImage =
2101     WaveImage( image(),
2102                amplitude_,
2103                wavelength_,
2104                &exceptionInfo);
2105   replaceImage( newImage );
2106   throwException( exceptionInfo );
2107   (void) DestroyExceptionInfo( &exceptionInfo );
2108 }
2109
2110 // Write image to file
2111 void Magick::Image::write( const std::string &imageSpec_ )
2112 {
2113   modifyImage();
2114   fileName( imageSpec_ );
2115   WriteImage( imageInfo(), image() );
2116   throwImageException();
2117 }
2118
2119 // Write image to in-memory BLOB
2120 void Magick::Image::write ( Blob *blob_ )
2121 {
2122   modifyImage();
2123   size_t length = 2048; // Efficient size for small images
2124   ExceptionInfo exceptionInfo;
2125   GetExceptionInfo( &exceptionInfo );
2126   void* data = ImageToBlob( imageInfo(),
2127                             image(),
2128                             &length,
2129                             &exceptionInfo);
2130   throwException( exceptionInfo );
2131   blob_->updateNoCopy( data, length, Blob::MallocAllocator );
2132   throwImageException();
2133   (void) DestroyExceptionInfo( &exceptionInfo );
2134 }
2135 void Magick::Image::write ( Blob *blob_,
2136                             const std::string &magick_ )
2137 {
2138   modifyImage();
2139   magick(magick_);
2140   size_t length = 2048; // Efficient size for small images
2141   ExceptionInfo exceptionInfo;
2142   GetExceptionInfo( &exceptionInfo );
2143   void* data = ImageToBlob( imageInfo(),
2144                             image(),
2145                             &length,
2146                             &exceptionInfo);
2147   throwException( exceptionInfo );
2148   blob_->updateNoCopy( data, length, Blob::MallocAllocator );
2149   throwImageException();
2150   (void) DestroyExceptionInfo( &exceptionInfo );
2151 }
2152 void Magick::Image::write ( Blob *blob_,
2153                             const std::string &magick_,
2154                             const unsigned int depth_ )
2155 {
2156   modifyImage();
2157   magick(magick_);
2158   depth(depth_);
2159   size_t length = 2048; // Efficient size for small images
2160   ExceptionInfo exceptionInfo;
2161   GetExceptionInfo( &exceptionInfo );
2162   void* data = ImageToBlob( imageInfo(),
2163                             image(),
2164                             &length,
2165                             &exceptionInfo);
2166   throwException( exceptionInfo );
2167   blob_->updateNoCopy( data, length, Blob::MallocAllocator );
2168   throwImageException();
2169   (void) DestroyExceptionInfo( &exceptionInfo );
2170 }
2171
2172 // Write image to an array of pixels with storage type specified
2173 // by user (ExportImagePixels), e.g.
2174 // image.write( 0, 0, 640, 1, "RGB", 0, pixels );
2175 void Magick::Image::write ( const int x_,
2176                             const int y_,
2177                             const unsigned int columns_,
2178                             const unsigned int rows_,
2179                             const std::string &map_,
2180                             const StorageType type_,
2181                             void *pixels_ )
2182 {
2183   ExceptionInfo exceptionInfo;
2184   GetExceptionInfo( &exceptionInfo );
2185   ExportImagePixels( image(), x_, y_, columns_, rows_, map_.c_str(), type_,
2186                  pixels_,
2187     &exceptionInfo);
2188   throwException( exceptionInfo );
2189   (void) DestroyExceptionInfo( &exceptionInfo );
2190 }
2191
2192 // Zoom image
2193 void Magick::Image::zoom( const Geometry &geometry_ )
2194 {
2195   // Calculate new size.  This code should be supported using binary arguments
2196   // in the ImageMagick library.
2197   long x = 0;
2198   long y = 0;
2199   unsigned long width = columns();
2200   unsigned long height = rows();
2201
2202   ParseMetaGeometry (static_cast<std::string>(geometry_).c_str(),
2203                      &x, &y,
2204                      &width, &height );
2205
2206   ExceptionInfo exceptionInfo;
2207   GetExceptionInfo( &exceptionInfo );
2208   MagickCore::Image* newImage =
2209     ZoomImage( image(),
2210                width,
2211                height,
2212                &exceptionInfo);
2213   replaceImage( newImage );
2214   throwException( exceptionInfo );
2215   (void) DestroyExceptionInfo( &exceptionInfo );
2216 }
2217
2218 /*
2219  * Methods for setting image attributes
2220  *
2221  */
2222
2223 // Join images into a single multi-image file
2224 void Magick::Image::adjoin ( const bool flag_ )
2225 {
2226   modifyImage();
2227   options()->adjoin( flag_ );
2228 }
2229 bool Magick::Image::adjoin ( void ) const
2230 {
2231   return constOptions()->adjoin();
2232 }
2233
2234 // Remove pixel aliasing
2235 void Magick::Image::antiAlias( const bool flag_ )
2236 {
2237   modifyImage();
2238   options()->antiAlias( static_cast<unsigned int>(flag_) );
2239 }
2240 bool Magick::Image::antiAlias( void )
2241 {
2242   return static_cast<bool>( options()->antiAlias( ) );
2243 }
2244
2245 // Animation inter-frame delay
2246 void Magick::Image::animationDelay ( const unsigned int delay_ )
2247 {
2248   modifyImage();
2249   image()->delay = delay_;
2250 }
2251 unsigned int Magick::Image::animationDelay ( void ) const
2252 {
2253   return constImage()->delay;
2254 }
2255
2256 // Number of iterations to play animation
2257 void Magick::Image::animationIterations ( const unsigned int iterations_ )
2258 {
2259   modifyImage();
2260   image()->iterations = iterations_;
2261 }
2262 unsigned int Magick::Image::animationIterations ( void ) const
2263 {
2264   return constImage()->iterations;
2265 }
2266
2267 // Access/Update a named image attribute
2268 void Magick::Image::attribute ( const std::string name_,
2269                                 const std::string value_ )
2270 {
2271   modifyImage();
2272   SetImageProperty( image(), name_.c_str(), value_.c_str() );
2273 }
2274 std::string Magick::Image::attribute ( const std::string name_ )
2275 {
2276   const char *value = GetImageProperty( constImage(), name_.c_str() );
2277
2278   if ( value )
2279     return std::string( value );
2280
2281   return std::string(); // Intentionally no exception
2282 }
2283
2284 // Background color
2285 void Magick::Image::backgroundColor ( const Color &color_ )
2286 {
2287   modifyImage();
2288
2289   if ( color_.isValid() )
2290     {
2291       image()->background_color.red   = color_.redQuantum();
2292       image()->background_color.green = color_.greenQuantum();
2293       image()->background_color.blue  = color_.blueQuantum();
2294       image()->background_color.opacity  = color_.alphaQuantum();
2295     }
2296   else
2297     {
2298       image()->background_color.red   = 0;
2299       image()->background_color.green = 0;
2300       image()->background_color.blue  = 0;
2301       image()->background_color.opacity  = OpaqueOpacity;
2302     }
2303
2304   options()->backgroundColor( color_ );
2305 }
2306 Magick::Color Magick::Image::backgroundColor ( void ) const
2307 {
2308   return constOptions()->backgroundColor( );
2309 }
2310
2311 // Background fill texture
2312 void Magick::Image::backgroundTexture ( const std::string &backgroundTexture_ )
2313 {
2314   modifyImage();
2315   options()->backgroundTexture( backgroundTexture_ );
2316 }
2317 std::string Magick::Image::backgroundTexture ( void ) const
2318 {
2319   return constOptions()->backgroundTexture( );
2320 }
2321
2322 // Original image columns
2323 unsigned int Magick::Image::baseColumns ( void ) const
2324 {
2325   return constImage()->magick_columns;
2326 }
2327
2328 // Original image name
2329 std::string Magick::Image::baseFilename ( void ) const
2330 {
2331   return std::string(constImage()->magick_filename);
2332 }
2333
2334 // Original image rows
2335 unsigned int Magick::Image::baseRows ( void ) const
2336 {
2337   return constImage()->magick_rows;
2338 }
2339
2340 // Border color
2341 void Magick::Image::borderColor ( const Color &color_ )
2342 {
2343   modifyImage();
2344
2345   if ( color_.isValid() )
2346     {
2347       image()->border_color.red   = color_.redQuantum();
2348       image()->border_color.green = color_.greenQuantum();
2349       image()->border_color.blue  = color_.blueQuantum();
2350       image()->border_color.opacity  = color_.alphaQuantum();
2351     }
2352   else
2353     {
2354       image()->border_color.red   = 0;
2355       image()->border_color.green = 0;
2356       image()->border_color.blue  = 0;
2357       image()->border_color.opacity = OpaqueOpacity;
2358     }
2359
2360   options()->borderColor( color_ );
2361 }
2362 Magick::Color Magick::Image::borderColor ( void ) const
2363 {
2364   return constOptions()->borderColor( );
2365 }
2366
2367 // Return smallest bounding box enclosing non-border pixels. The
2368 // current fuzz value is used when discriminating between pixels.
2369 // This is the crop bounding box used by crop(Geometry(0,0));
2370 Magick::Geometry Magick::Image::boundingBox ( void ) const
2371 {
2372   ExceptionInfo exceptionInfo;
2373   GetExceptionInfo( &exceptionInfo );
2374   RectangleInfo bbox = GetImageBoundingBox( constImage(), &exceptionInfo);
2375   throwException( exceptionInfo );
2376   (void) DestroyExceptionInfo( &exceptionInfo );
2377   return Geometry( bbox );
2378 }
2379
2380 // Text bounding-box base color
2381 void Magick::Image::boxColor ( const Color &boxColor_ )
2382 {
2383   modifyImage();
2384   options()->boxColor( boxColor_ );
2385 }
2386 Magick::Color Magick::Image::boxColor ( void ) const
2387 {
2388   return constOptions()->boxColor( );
2389 }
2390
2391 // Pixel cache threshold.  Once this threshold is exceeded, all
2392 // subsequent pixels cache operations are to/from disk.
2393 // This setting is shared by all Image objects.
2394 /* static */
2395 void Magick::Image::cacheThreshold ( const unsigned int threshold_ )
2396 {
2397   SetMagickResourceLimit( MemoryResource, threshold_ );
2398 }
2399
2400 void Magick::Image::chromaBluePrimary ( const double x_, const double y_ )
2401 {
2402   modifyImage();
2403   image()->chromaticity.blue_primary.x = x_;
2404   image()->chromaticity.blue_primary.y = y_;
2405 }
2406 void Magick::Image::chromaBluePrimary ( double *x_, double *y_ ) const
2407 {
2408   *x_ = constImage()->chromaticity.blue_primary.x;
2409   *y_ = constImage()->chromaticity.blue_primary.y;
2410 }
2411
2412 void Magick::Image::chromaGreenPrimary ( const double x_, const double y_ )
2413 {
2414   modifyImage();
2415   image()->chromaticity.green_primary.x = x_;
2416   image()->chromaticity.green_primary.y = y_;
2417 }
2418 void Magick::Image::chromaGreenPrimary ( double *x_, double *y_ ) const
2419 {
2420   *x_ = constImage()->chromaticity.green_primary.x;
2421   *y_ = constImage()->chromaticity.green_primary.y;
2422 }
2423
2424 void Magick::Image::chromaRedPrimary ( const double x_, const double y_ )
2425 {
2426   modifyImage();
2427   image()->chromaticity.red_primary.x = x_;
2428   image()->chromaticity.red_primary.y = y_;
2429 }
2430 void Magick::Image::chromaRedPrimary ( double *x_, double *y_ ) const
2431 {
2432   *x_ = constImage()->chromaticity.red_primary.x;
2433   *y_ = constImage()->chromaticity.red_primary.y;
2434 }
2435
2436 void Magick::Image::chromaWhitePoint ( const double x_, const double y_ )
2437 {
2438   modifyImage();
2439   image()->chromaticity.white_point.x = x_;
2440   image()->chromaticity.white_point.y = y_;
2441 }
2442 void Magick::Image::chromaWhitePoint ( double *x_, double *y_ ) const
2443 {
2444   *x_ = constImage()->chromaticity.white_point.x;
2445   *y_ = constImage()->chromaticity.white_point.y;
2446 }
2447
2448 // Set image storage class
2449 void Magick::Image::classType ( const ClassType class_ )
2450 {
2451   if ( classType() == PseudoClass && class_ == DirectClass )
2452     {
2453       // Use SyncImage to synchronize the DirectClass pixels with the
2454       // color map and then set to DirectClass type.
2455       modifyImage();
2456       SyncImage( image() );
2457       image()->colormap = (PixelPacket *)
2458         RelinquishMagickMemory( image()->colormap );
2459       image()->storage_class = static_cast<MagickCore::ClassType>(DirectClass);
2460       return;
2461     }
2462
2463   if ( classType() == DirectClass && class_ == PseudoClass )
2464     {
2465       // Quantize to create PseudoClass color map
2466       modifyImage();
2467       quantizeColors((unsigned long) QuantumRange + 1);
2468       quantize();
2469       image()->storage_class = static_cast<MagickCore::ClassType>(PseudoClass);
2470     }
2471 }
2472
2473 // Associate a clip mask with the image. The clip mask must be the
2474 // same dimensions as the image. Pass an invalid image to unset an
2475 // existing clip mask.
2476 void Magick::Image::clipMask ( const Magick::Image & clipMask_ )
2477 {
2478   modifyImage();
2479
2480   if( clipMask_.isValid() )
2481     {
2482       // Set clip mask
2483       SetImageClipMask( image(), clipMask_.constImage() );
2484     }
2485   else
2486     {
2487       // Unset existing clip mask
2488       SetImageClipMask( image(), 0 );
2489     }
2490 }
2491 Magick::Image Magick::Image::clipMask ( void  ) const
2492 {
2493       ExceptionInfo exceptionInfo;
2494       GetExceptionInfo( &exceptionInfo );
2495       MagickCore::Image* image =
2496         GetImageClipMask( constImage(), &exceptionInfo );
2497       throwException( exceptionInfo );
2498   (void) DestroyExceptionInfo( &exceptionInfo );
2499       return Magick::Image( image );
2500 }
2501
2502 void Magick::Image::colorFuzz ( const double fuzz_ )
2503 {
2504   modifyImage();
2505   image()->fuzz = fuzz_;
2506   options()->colorFuzz( fuzz_ );
2507 }
2508 double Magick::Image::colorFuzz ( void ) const
2509 {
2510   return constOptions()->colorFuzz( );
2511 }
2512
2513 // Set color in colormap at index
2514 void Magick::Image::colorMap ( const unsigned int index_,
2515                                const Color &color_ )
2516 {
2517   MagickCore::Image* imageptr = image();
2518
2519   if (index_ > (MaxColormapSize-1) )
2520     throwExceptionExplicit( OptionError,
2521                             "Colormap index must be less than MaxColormapSize" );
2522   
2523   if ( !color_.isValid() )
2524     throwExceptionExplicit( OptionError,
2525                             "Color argument is invalid");
2526   modifyImage();
2527
2528   // Ensure that colormap size is large enough
2529   if ( colorMapSize() < (index_+1) )
2530     colorMapSize( index_ + 1 );
2531
2532   // Set color at index in colormap
2533   (imageptr->colormap)[index_] = color_;
2534 }
2535 // Return color in colormap at index
2536 Magick::Color Magick::Image::colorMap ( const unsigned int index_ ) const
2537 {
2538   const MagickCore::Image* imageptr = constImage();
2539
2540   if ( !imageptr->colormap )
2541     throwExceptionExplicit( OptionError,
2542                             "Image does not contain a colormap");
2543
2544   if ( index_ > imageptr->colors-1 )
2545     throwExceptionExplicit( OptionError,
2546                             "Index out of range");
2547
2548   return Magick::Color( (imageptr->colormap)[index_] );
2549 }
2550
2551 // Colormap size (number of colormap entries)
2552 void Magick::Image::colorMapSize ( const unsigned int entries_ )
2553 {
2554   if (entries_ >MaxColormapSize )
2555     throwExceptionExplicit( OptionError,
2556                             "Colormap entries must not exceed MaxColormapSize" );
2557
2558   modifyImage();
2559
2560   MagickCore::Image* imageptr = image();
2561
2562   if( !imageptr->colormap )
2563     {
2564       // Allocate colormap
2565       imageptr->colormap =
2566         static_cast<PixelPacket*>(AcquireMagickMemory(entries_*sizeof(PixelPacket)));
2567       imageptr->colors = 0;
2568     }
2569   else if ( entries_ > imageptr->colors )
2570     {
2571       // Re-allocate colormap
2572       imageptr->colormap=(PixelPacket *)
2573         ResizeMagickMemory(imageptr->colormap,(entries_)*sizeof(PixelPacket));
2574     }
2575
2576   // Initialize any new colormap entries as all black
2577   Color black(0,0,0);
2578   for( unsigned int i=imageptr->colors; i<(entries_-1); i++ )
2579     (imageptr->colormap)[i] = black;
2580
2581   imageptr->colors = entries_;
2582 }
2583 unsigned int Magick::Image::colorMapSize ( void )
2584 {
2585   const MagickCore::Image* imageptr = constImage();
2586
2587   if ( !imageptr->colormap )
2588     throwExceptionExplicit( OptionError,
2589                             "Image does not contain a colormap");
2590
2591   return imageptr->colors;
2592 }
2593
2594 // Image colorspace
2595 void Magick::Image::colorSpace( const ColorspaceType colorSpace_ )
2596 {
2597   // Nothing to do?
2598   if ( image()->colorspace == colorSpace_ )
2599     return;
2600
2601   modifyImage();
2602
2603   if ( colorSpace_ != RGBColorspace &&
2604        colorSpace_ != TransparentColorspace &&
2605        colorSpace_ != GRAYColorspace )
2606     {
2607       if (image()->colorspace != RGBColorspace &&
2608           image()->colorspace != TransparentColorspace &&
2609           image()->colorspace != GRAYColorspace)
2610         {
2611           /* Transform to RGB colorspace as intermediate step */
2612           TransformRGBImage( image(), image()->colorspace );
2613           throwImageException();
2614         }
2615       /* Transform to final non-RGB colorspace */
2616       RGBTransformImage( image(), colorSpace_ );
2617       throwImageException();
2618       return;
2619     }
2620
2621   if ( colorSpace_ == RGBColorspace ||
2622        colorSpace_ == TransparentColorspace ||
2623        colorSpace_ == GRAYColorspace )
2624     {
2625       /* Transform to a RGB-type colorspace */
2626       TransformRGBImage( image(), image()->colorspace );
2627       throwImageException();
2628       return;
2629     }
2630 }
2631 Magick::ColorspaceType Magick::Image::colorSpace ( void ) const
2632 {
2633   return constImage()->colorspace;
2634 }
2635
2636 // Set image colorspace type.
2637 void Magick::Image::colorspaceType( const ColorspaceType colorSpace_ )
2638 {
2639   modifyImage();
2640   options()->colorspaceType( colorSpace_ );
2641 }
2642 Magick::ColorspaceType Magick::Image::colorspaceType ( void ) const
2643 {
2644   return constOptions()->colorspaceType();
2645 }
2646
2647
2648 // Comment string
2649 void Magick::Image::comment ( const std::string &comment_ )
2650 {
2651   modifyImage();
2652   SetImageProperty( image(), "Comment", NULL );
2653   if ( comment_.length() > 0 )
2654     SetImageProperty( image(), "Comment", comment_.c_str() );
2655   throwImageException();
2656 }
2657 std::string Magick::Image::comment ( void ) const
2658 {
2659   const char *value = GetImageProperty( constImage(), "Comment" );
2660
2661   if ( value )
2662     return std::string( value );
2663
2664   return std::string(); // Intentionally no exception
2665 }
2666
2667 // Composition operator to be used when composition is implicitly used
2668 // (such as for image flattening).
2669 void Magick::Image::compose (const CompositeOperator compose_)
2670 {
2671   image()->compose=compose_;
2672 }
2673
2674 Magick::CompositeOperator Magick::Image::compose ( void ) const
2675 {
2676   return constImage()->compose;
2677 }
2678
2679 // Compression algorithm
2680 void Magick::Image::compressType ( const CompressionType compressType_ )
2681 {
2682   modifyImage();
2683   image()->compression = compressType_;
2684   options()->compressType( compressType_ );
2685 }
2686 Magick::CompressionType Magick::Image::compressType ( void ) const
2687 {
2688   return constImage()->compression;
2689 }
2690
2691 // Enable printing of debug messages from ImageMagick
2692 void Magick::Image::debug ( const bool flag_ )
2693 {
2694   modifyImage();
2695   options()->debug( flag_ );
2696 }
2697 bool Magick::Image::debug ( void ) const
2698 {
2699   return constOptions()->debug();
2700 }
2701
2702 // Tagged image format define (set/access coder-specific option) The
2703 // magick_ option specifies the coder the define applies to.  The key_
2704 // option provides the key specific to that coder.  The value_ option
2705 // provides the value to set (if any). See the defineSet() method if the
2706 // key must be removed entirely.
2707 void Magick::Image::defineValue ( const std::string &magick_,
2708                                   const std::string &key_,
2709                                   const std::string &value_ )
2710 {
2711   modifyImage();
2712   std::string format = magick_ + ":" + key_;
2713   std::string option = value_;
2714   (void) SetImageOption ( imageInfo(), format.c_str(), option.c_str() );
2715 }
2716 std::string Magick::Image::defineValue ( const std::string &magick_,
2717                                          const std::string &key_ ) const
2718 {
2719   std::string definition = magick_ + ":" + key_;
2720   const char *option =
2721     GetImageOption ( constImageInfo(), definition.c_str() );
2722   if (option)
2723     return std::string( option );
2724   return std::string( );
2725 }
2726
2727 // Tagged image format define. Similar to the defineValue() method
2728 // except that passing the flag_ value 'true' creates a value-less
2729 // define with that format and key. Passing the flag_ value 'false'
2730 // removes any existing matching definition. The method returns 'true'
2731 // if a matching key exists, and 'false' if no matching key exists.
2732 void Magick::Image::defineSet ( const std::string &magick_,
2733                                 const std::string &key_,
2734                                 bool flag_ )
2735 {
2736   modifyImage();
2737   std::string definition = magick_ + ":" + key_;
2738   if (flag_)
2739     {
2740       (void) SetImageOption ( imageInfo(), definition.c_str(),  "" );
2741     }
2742   else
2743     {
2744       DeleteImageOption( imageInfo(), definition.c_str() );
2745     }
2746 }
2747 bool Magick::Image::defineSet ( const std::string &magick_,
2748                                 const std::string &key_ ) const
2749 {
2750   std::string key = magick_ + ":" + key_;
2751   const char *option =
2752     GetImageOption ( constImageInfo(), key.c_str() );
2753   if (option)
2754     return true;
2755   return false;
2756 }
2757
2758 // Pixel resolution
2759 void Magick::Image::density ( const Geometry &density_ )
2760 {
2761   modifyImage();
2762   options()->density( density_ );
2763   if ( density_.isValid() )
2764     {
2765       image()->x_resolution = density_.width();
2766       if ( density_.height() != 0 )
2767         {
2768           image()->y_resolution = density_.height();
2769         }
2770       else
2771         {
2772           image()->y_resolution = density_.width();
2773         }
2774     }
2775   else
2776     {
2777       // Reset to default
2778       image()->x_resolution = 0;
2779       image()->y_resolution = 0;
2780     }
2781 }
2782 Magick::Geometry Magick::Image::density ( void ) const
2783 {
2784   if (isValid())
2785     {
2786       unsigned int x_resolution=72;
2787       unsigned int y_resolution=72;
2788
2789       if (constImage()->x_resolution > 0.0)
2790         x_resolution=static_cast<unsigned int>(constImage()->x_resolution + 0.5);
2791
2792       if (constImage()->y_resolution > 0.0)
2793         y_resolution=static_cast<unsigned int>(constImage()->y_resolution + 0.5);
2794
2795       return Geometry(x_resolution,y_resolution);
2796     }
2797
2798   return constOptions()->density( );
2799 }
2800
2801 // Image depth (bits allocated to red/green/blue components)
2802 void Magick::Image::depth ( const unsigned int depth_ )
2803 {
2804   unsigned int depth = depth_;
2805
2806   if (depth > MAGICKCORE_QUANTUM_DEPTH)
2807     depth=MAGICKCORE_QUANTUM_DEPTH;
2808
2809   modifyImage();
2810   image()->depth=depth;
2811   options()->depth( depth );
2812 }
2813 unsigned int Magick::Image::depth ( void ) const
2814 {
2815   return constImage()->depth;
2816 }
2817
2818 std::string Magick::Image::directory ( void ) const
2819 {
2820   if ( constImage()->directory )
2821     return std::string( constImage()->directory );
2822
2823   throwExceptionExplicit( CorruptImageWarning,
2824                           "Image does not contain a directory");
2825
2826   return std::string();
2827 }
2828
2829 // Endianness (little like Intel or big like SPARC) for image
2830 // formats which support endian-specific options.
2831 void Magick::Image::endian ( const Magick::EndianType endian_ )
2832 {
2833   modifyImage();
2834   options()->endian( endian_ );
2835   image()->endian = endian_;
2836 }
2837 Magick::EndianType Magick::Image::endian ( void ) const
2838 {
2839   return constImage()->endian;
2840 }
2841
2842 // EXIF profile (BLOB)
2843 void Magick::Image::exifProfile( const Magick::Blob &exifProfile_ )
2844 {
2845   modifyImage();
2846   if ( exifProfile_.data() != 0 )
2847     {
2848       StringInfo * exif_profile = AcquireStringInfo( exifProfile_.length() );
2849       SetStringInfoDatum(exif_profile ,(unsigned char *) exifProfile_.data());
2850       (void) SetImageProfile( image(), "exif", exif_profile);
2851       exif_profile =DestroyStringInfo( exif_profile );
2852     }
2853 }
2854 Magick::Blob Magick::Image::exifProfile( void ) const
2855 {
2856   const StringInfo * exif_profile = GetImageProfile( constImage(), "exif" );
2857   if ( exif_profile == (StringInfo *) NULL)
2858     return Blob( 0, 0 );
2859   return Blob(GetStringInfoDatum(exif_profile),GetStringInfoLength(exif_profile));
2860
2861
2862 // Image file name
2863 void Magick::Image::fileName ( const std::string &fileName_ )
2864 {
2865   modifyImage();
2866
2867   fileName_.copy( image()->filename,
2868                   sizeof(image()->filename) - 1 );
2869   image()->filename[ fileName_.length() ] = 0; // Null terminate
2870   
2871   options()->fileName( fileName_ );
2872   
2873 }
2874 std::string Magick::Image::fileName ( void ) const
2875 {
2876   return constOptions()->fileName( );
2877 }
2878
2879 // Image file size
2880 off_t Magick::Image::fileSize ( void ) const
2881 {
2882   return (off_t) GetBlobSize( constImage() );
2883 }
2884
2885 // Color to use when drawing inside an object
2886 void Magick::Image::fillColor ( const Magick::Color &fillColor_ )
2887 {
2888   modifyImage();
2889   options()->fillColor(fillColor_);
2890 }
2891 Magick::Color Magick::Image::fillColor ( void ) const
2892 {
2893   return constOptions()->fillColor();
2894 }
2895
2896 // Rule to use when filling drawn objects
2897 void Magick::Image::fillRule ( const Magick::FillRule &fillRule_ )
2898 {
2899   modifyImage();
2900   options()->fillRule(fillRule_);
2901 }
2902 Magick::FillRule Magick::Image::fillRule ( void ) const
2903 {
2904   return constOptions()->fillRule();
2905 }
2906
2907 // Pattern to use while filling drawn objects.
2908 void Magick::Image::fillPattern ( const Image &fillPattern_ )
2909 {
2910   modifyImage();
2911   if(fillPattern_.isValid())
2912     options()->fillPattern( fillPattern_.constImage() );
2913   else
2914     options()->fillPattern( static_cast<MagickCore::Image*>(NULL) );
2915 }
2916 Magick::Image  Magick::Image::fillPattern ( void  ) const
2917 {
2918   // FIXME: This is inordinately innefficient
2919   Image texture;
2920   
2921   const MagickCore::Image* tmpTexture = constOptions()->fillPattern( );
2922
2923   if ( tmpTexture )
2924     {
2925       ExceptionInfo exceptionInfo;
2926       GetExceptionInfo( &exceptionInfo );
2927       MagickCore::Image* image =
2928         CloneImage( tmpTexture,
2929                     0, // columns
2930                     0, // rows
2931                     MagickTrue, // orphan
2932                     &exceptionInfo);
2933       texture.replaceImage( image );
2934       throwException( exceptionInfo );
2935   (void) DestroyExceptionInfo( &exceptionInfo );
2936     }
2937   return texture;
2938 }
2939
2940 // Filter used by zoom
2941 void Magick::Image::filterType ( const Magick::FilterTypes filterType_ )
2942 {
2943   modifyImage();
2944   image()->filter = filterType_;
2945 }
2946 Magick::FilterTypes Magick::Image::filterType ( void ) const
2947 {
2948   return constImage()->filter;
2949 }
2950
2951 // Font name
2952 void Magick::Image::font ( const std::string &font_ )
2953 {
2954   modifyImage();
2955   options()->font( font_ );
2956 }
2957 std::string Magick::Image::font ( void ) const
2958 {
2959   return constOptions()->font( );
2960 }
2961
2962 // Font point size
2963 void Magick::Image::fontPointsize ( const double pointSize_ )
2964 {
2965   modifyImage();
2966   options()->fontPointsize( pointSize_ );
2967 }
2968 double Magick::Image::fontPointsize ( void ) const
2969 {
2970   return constOptions()->fontPointsize( );
2971 }
2972
2973 // Font type metrics
2974 void Magick::Image::fontTypeMetrics( const std::string &text_,
2975                                      TypeMetric *metrics )
2976 {
2977   DrawInfo *drawInfo = options()->drawInfo();
2978   drawInfo->text = const_cast<char *>(text_.c_str());
2979   GetTypeMetrics( image(), drawInfo, &(metrics->_typeMetric) );
2980   drawInfo->text = 0;
2981 }
2982
2983 // Image format string
2984 std::string Magick::Image::format ( void ) const
2985 {
2986   ExceptionInfo exceptionInfo;
2987   GetExceptionInfo( &exceptionInfo );
2988   const MagickInfo * magick_info
2989     = GetMagickInfo( constImage()->magick, &exceptionInfo);
2990   throwException( exceptionInfo );
2991   (void) DestroyExceptionInfo( &exceptionInfo );
2992
2993   if (( magick_info != 0 ) && 
2994       ( *magick_info->description != '\0' ))
2995     return std::string(magick_info->description);
2996
2997   throwExceptionExplicit( CorruptImageWarning,
2998                           "Unrecognized image magick type" );
2999   return std::string();
3000 }
3001
3002 // Gamma adjustment
3003 double Magick::Image::gamma ( void ) const
3004 {
3005   return constImage()->gamma;
3006 }
3007
3008 Magick::Geometry Magick::Image::geometry ( void ) const
3009 {
3010   if ( constImage()->geometry )
3011   {
3012     return Geometry(constImage()->geometry);
3013   }
3014
3015   throwExceptionExplicit( OptionWarning,
3016                           "Image does not contain a geometry");
3017
3018   return Geometry();
3019 }
3020
3021 void Magick::Image::gifDisposeMethod ( const unsigned int disposeMethod_ )
3022 {
3023   modifyImage();
3024   image()->dispose = (DisposeType) disposeMethod_;
3025 }
3026 unsigned int Magick::Image::gifDisposeMethod ( void ) const
3027 {
3028   // FIXME: It would be better to return an enumeration
3029   return constImage()->dispose;
3030 }
3031
3032 // ICC ICM color profile (BLOB)
3033 void Magick::Image::iccColorProfile( const Magick::Blob &colorProfile_ )
3034 {
3035   profile("icm",colorProfile_);
3036 }
3037 Magick::Blob Magick::Image::iccColorProfile( void ) const
3038 {
3039   const StringInfo * color_profile = GetImageProfile( constImage(), "icc" );
3040   if ( color_profile == (StringInfo *) NULL)
3041     return Blob( 0, 0 );
3042   return Blob( GetStringInfoDatum(color_profile), GetStringInfoLength(color_profile) );
3043 }
3044
3045 void Magick::Image::interlaceType ( const Magick::InterlaceType interlace_ )
3046 {
3047   modifyImage();
3048   image()->interlace = interlace_;
3049   options()->interlaceType ( interlace_ );
3050 }
3051 Magick::InterlaceType Magick::Image::interlaceType ( void ) const
3052 {
3053   return constImage()->interlace;
3054 }
3055
3056 // IPTC profile (BLOB)
3057 void Magick::Image::iptcProfile( const Magick::Blob &iptcProfile_ )
3058 {
3059   modifyImage();
3060   if (  iptcProfile_.data() != 0 )
3061     {
3062       StringInfo * iptc_profile = AcquireStringInfo( iptcProfile_.length() );
3063       SetStringInfoDatum(iptc_profile ,(unsigned char *) iptcProfile_.data());
3064       (void) SetImageProfile( image(), "iptc", iptc_profile);
3065        iptc_profile =DestroyStringInfo( iptc_profile );
3066     }
3067 }
3068 Magick::Blob Magick::Image::iptcProfile( void ) const
3069 {
3070   const StringInfo * iptc_profile = GetImageProfile( constImage(), "iptc" );
3071   if ( iptc_profile == (StringInfo *) NULL)
3072     return Blob( 0, 0 );
3073   return Blob( GetStringInfoDatum(iptc_profile), GetStringInfoLength(iptc_profile));
3074 }
3075
3076 // Does object contain valid image?
3077 void Magick::Image::isValid ( const bool isValid_ )
3078 {
3079   if ( !isValid_ )
3080     {
3081       delete _imgRef;
3082       _imgRef = new ImageRef;
3083     }
3084   else if ( !isValid() )
3085     {
3086       // Construct with single-pixel black image to make
3087       // image valid.  This is an obvious hack.
3088       size( Geometry(1,1) );
3089       read( "xc:#000000" );
3090     }
3091 }
3092
3093 bool Magick::Image::isValid ( void ) const
3094 {
3095   if ( rows() && columns() )
3096     return true;
3097
3098   return false;
3099 }
3100
3101 // Label image
3102 void Magick::Image::label ( const std::string &label_ )
3103 {
3104   modifyImage();
3105   SetImageProperty ( image(), "Label", NULL );
3106   if ( label_.length() > 0 )
3107     SetImageProperty ( image(), "Label", label_.c_str() );
3108   throwImageException();
3109 }
3110 std::string Magick::Image::label ( void ) const
3111 {
3112   const char *value = GetImageProperty( constImage(), "Label" );
3113
3114   if ( value )
3115     return std::string( value );
3116
3117   return std::string();
3118 }
3119
3120 void Magick::Image::magick ( const std::string &magick_ )
3121 {
3122   modifyImage();
3123
3124   magick_.copy( image()->magick,
3125                 sizeof(image()->magick) - 1 );
3126   image()->magick[ magick_.length() ] = 0;
3127   
3128   options()->magick( magick_ );
3129 }
3130 std::string Magick::Image::magick ( void ) const
3131 {
3132   if ( *(constImage()->magick) != '\0' )
3133     return std::string(constImage()->magick);
3134
3135   return constOptions()->magick( );
3136 }
3137
3138 void Magick::Image::matte ( const bool matteFlag_ )
3139 {
3140   modifyImage();
3141
3142   // If matte channel is requested, but image doesn't already have a
3143   // matte channel, then create an opaque matte channel.  Likewise, if
3144   // the image already has a matte channel but a matte channel is not
3145   // desired, then set the matte channel to opaque.
3146   if ((matteFlag_ && !constImage()->matte) ||
3147       (constImage()->matte && !matteFlag_))
3148     SetImageOpacity(image(),OpaqueOpacity);
3149
3150   image()->matte = (MagickBooleanType) matteFlag_;
3151 }
3152 bool Magick::Image::matte ( void ) const
3153 {
3154   if ( constImage()->matte )
3155     return true;
3156   else
3157     return false;
3158 }
3159
3160 void Magick::Image::matteColor ( const Color &matteColor_ )
3161 {
3162   modifyImage();
3163   
3164   if ( matteColor_.isValid() )
3165     {
3166       image()->matte_color.red   = matteColor_.redQuantum();
3167       image()->matte_color.green = matteColor_.greenQuantum();
3168       image()->matte_color.blue  = matteColor_.blueQuantum();
3169       image()->matte_color.opacity  = matteColor_.alphaQuantum();
3170
3171       options()->matteColor( matteColor_ ); 
3172     }
3173   else
3174     {
3175       // Set to default matte color
3176       Color tmpColor( "#BDBDBD" );
3177       image()->matte_color.red   = tmpColor.redQuantum();
3178       image()->matte_color.green = tmpColor.greenQuantum();
3179       image()->matte_color.blue  = tmpColor.blueQuantum();
3180       image()->matte_color.opacity  = tmpColor.alphaQuantum();
3181
3182       options()->matteColor( tmpColor );
3183     }
3184 }
3185 Magick::Color Magick::Image::matteColor ( void ) const
3186 {
3187   return Color( constImage()->matte_color.red,
3188                 constImage()->matte_color.green,
3189                 constImage()->matte_color.blue,
3190                 constImage()->matte_color.opacity );
3191 }
3192
3193 double Magick::Image::meanErrorPerPixel ( void ) const
3194 {
3195   return(constImage()->error.mean_error_per_pixel);
3196 }
3197
3198 // Image modulus depth (minimum number of bits required to support
3199 // red/green/blue components without loss of accuracy)
3200 void Magick::Image::modulusDepth ( const unsigned int depth_ )
3201 {
3202   modifyImage();
3203   SetImageDepth( image(), depth_ );
3204   options()->depth( depth_ );
3205 }
3206 unsigned int Magick::Image::modulusDepth ( void ) const
3207 {
3208   ExceptionInfo exceptionInfo;
3209   GetExceptionInfo( &exceptionInfo );
3210   unsigned int depth=GetImageDepth( constImage(), &exceptionInfo );
3211   throwException( exceptionInfo );
3212   (void) DestroyExceptionInfo( &exceptionInfo );
3213   return depth;
3214 }
3215
3216 void Magick::Image::monochrome ( const bool monochromeFlag_ )
3217 {
3218   modifyImage();
3219   options()->monochrome( monochromeFlag_ );
3220 }
3221 bool Magick::Image::monochrome ( void ) const
3222 {
3223   return constOptions()->monochrome( );
3224 }
3225
3226 Magick::Geometry Magick::Image::montageGeometry ( void ) const
3227 {
3228   if ( constImage()->montage )
3229     return Magick::Geometry(constImage()->montage);
3230
3231   throwExceptionExplicit( CorruptImageWarning,
3232                           "Image does not contain a montage" );
3233
3234   return Magick::Geometry();
3235 }
3236
3237 double Magick::Image::normalizedMaxError ( void ) const
3238 {
3239   return(constImage()->error.normalized_maximum_error);
3240 }
3241
3242 double Magick::Image::normalizedMeanError ( void ) const
3243 {
3244   return constImage()->error.normalized_mean_error;
3245 }
3246
3247 // Image orientation
3248 void Magick::Image::orientation ( const Magick::OrientationType orientation_ )
3249 {
3250   modifyImage();
3251   image()->orientation = orientation_;
3252 }
3253 Magick::OrientationType Magick::Image::orientation ( void ) const
3254 {
3255   return constImage()->orientation;
3256 }
3257
3258 void Magick::Image::penColor ( const Color &penColor_ )
3259 {
3260   modifyImage();
3261   options()->fillColor(penColor_);
3262   options()->strokeColor(penColor_);
3263 }
3264 Magick::Color Magick::Image::penColor ( void  ) const
3265 {
3266   return constOptions()->fillColor();
3267 }
3268
3269 void Magick::Image::penTexture ( const Image &penTexture_ )
3270 {
3271   modifyImage();
3272   if(penTexture_.isValid())
3273     options()->fillPattern( penTexture_.constImage() );
3274   else
3275     options()->fillPattern( static_cast<MagickCore::Image*>(NULL) );
3276 }
3277
3278 Magick::Image  Magick::Image::penTexture ( void  ) const
3279 {
3280   // FIXME: This is inordinately innefficient
3281   Image texture;
3282   
3283   const MagickCore::Image* tmpTexture = constOptions()->fillPattern( );
3284
3285   if ( tmpTexture )
3286     {
3287       ExceptionInfo exceptionInfo;
3288       GetExceptionInfo( &exceptionInfo );
3289       MagickCore::Image* image =
3290         CloneImage( tmpTexture,
3291                     0, // columns
3292                     0, // rows
3293                     MagickTrue, // orphan
3294                     &exceptionInfo);
3295       texture.replaceImage( image );
3296       throwException( exceptionInfo );
3297   (void) DestroyExceptionInfo( &exceptionInfo );
3298     }
3299   return texture;
3300 }
3301
3302 // Set the color of a pixel.
3303 void Magick::Image::pixelColor ( const unsigned int x_, const unsigned int y_,
3304                                  const Color &color_ )
3305 {
3306   // Test arguments to ensure they are within the image.
3307   if ( y_ > rows() || x_ > columns() )
3308     throwExceptionExplicit( OptionError,
3309             "Access outside of image boundary" );
3310       
3311   modifyImage();
3312
3313   // Set image to DirectClass
3314   classType( DirectClass );
3315
3316   // Get pixel view
3317   Pixels pixels(*this);
3318     // Set pixel value
3319   *(pixels.get(x_, y_, 1, 1 )) = color_;
3320   // Tell ImageMagick that pixels have been updated
3321   pixels.sync();
3322
3323   return;
3324 }
3325
3326 // Get the color of a pixel
3327 Magick::Color Magick::Image::pixelColor ( const unsigned int x_,
3328                                           const unsigned int y_ ) const
3329 {
3330   ClassType storage_class;
3331   storage_class = classType();
3332   // DirectClass
3333   const PixelPacket* pixel = getConstPixels( x_, y_, 1, 1 );
3334   if ( storage_class == DirectClass )
3335     {
3336       if ( pixel )
3337         return Color( *pixel );
3338     }
3339
3340   // PseudoClass
3341   if ( storage_class == PseudoClass )
3342     {
3343       const IndexPacket* indexes = getConstIndexes();
3344       if ( indexes )
3345         return colorMap( (unsigned long) *indexes );
3346     }
3347
3348   return Color(); // invalid
3349 }
3350
3351 // Preferred size and location of an image canvas.
3352 void Magick::Image::page ( const Magick::Geometry &pageSize_ )
3353 {
3354   modifyImage();
3355   options()->page( pageSize_ );
3356   image()->page = pageSize_;
3357 }
3358 Magick::Geometry Magick::Image::page ( void ) const
3359 {
3360   return Geometry( constImage()->page.width,
3361                    constImage()->page.height,
3362                    AbsoluteValue(constImage()->page.x),
3363                    AbsoluteValue(constImage()->page.y),
3364                    constImage()->page.x < 0 ? true : false,
3365                    constImage()->page.y < 0 ? true : false);
3366 }
3367
3368 // Add a named profile to an image or remove a named profile by
3369 // passing an empty Blob (use default Blob constructor).
3370 // Valid names are:
3371 // "*", "8BIM", "ICM", "IPTC", or a generic profile name.
3372 void Magick::Image::profile( const std::string name_,
3373                              const Magick::Blob &profile_ )
3374 {
3375   modifyImage();
3376   int result = ProfileImage( image(), name_.c_str(),
3377                              (unsigned char *)profile_.data(),
3378                              profile_.length(), MagickTrue);
3379
3380   if( !result )
3381     throwImageException();
3382 }
3383
3384 // Retrieve a named profile from the image.
3385 // Valid names are:
3386 // "8BIM", "8BIMTEXT", "APP1", "APP1JPEG", "ICC", "ICM", & "IPTC" or
3387 // an existing generic profile name.
3388 Magick::Blob Magick::Image::profile( const std::string name_ ) const
3389 {
3390   const MagickCore::Image* image = constImage();
3391                                                                                 
3392   const StringInfo * profile = GetImageProfile( image, name_.c_str() );
3393                                                                                 
3394   if ( profile != (StringInfo *) NULL)
3395       return Blob( (void*) GetStringInfoDatum(profile), GetStringInfoLength(profile));
3396                                                                                 
3397   Blob blob;
3398   Image temp_image = *this;
3399   temp_image.write( &blob, name_ );
3400   return blob;
3401 }
3402
3403 void Magick::Image::quality ( const unsigned int quality_ )
3404 {
3405   modifyImage();
3406   image()->quality = quality_;
3407   options()->quality( quality_ );
3408 }
3409 unsigned int Magick::Image::quality ( void ) const
3410 {
3411   return constImage()->quality;
3412 }
3413
3414 void Magick::Image::quantizeColors ( const unsigned int colors_ )
3415 {
3416   modifyImage();
3417   options()->quantizeColors( colors_ );
3418 }
3419 unsigned int Magick::Image::quantizeColors ( void ) const
3420 {
3421   return constOptions()->quantizeColors( );
3422 }
3423
3424 void Magick::Image::quantizeColorSpace
3425   ( const Magick::ColorspaceType colorSpace_ )
3426 {
3427   modifyImage();
3428   options()->quantizeColorSpace( colorSpace_ );
3429 }
3430 Magick::ColorspaceType Magick::Image::quantizeColorSpace ( void ) const
3431 {
3432   return constOptions()->quantizeColorSpace( );
3433 }
3434
3435 void Magick::Image::quantizeDither ( const bool ditherFlag_ )
3436 {
3437   modifyImage();
3438   options()->quantizeDither( ditherFlag_ );
3439 }
3440 bool Magick::Image::quantizeDither ( void ) const
3441 {
3442   return constOptions()->quantizeDither( );
3443 }
3444
3445 void Magick::Image::quantizeTreeDepth ( const unsigned int treeDepth_ )
3446 {
3447   modifyImage();
3448   options()->quantizeTreeDepth( treeDepth_ );
3449 }
3450 unsigned int Magick::Image::quantizeTreeDepth ( void ) const
3451 {
3452   return constOptions()->quantizeTreeDepth( );
3453 }
3454
3455 void Magick::Image::renderingIntent
3456   ( const Magick::RenderingIntent renderingIntent_ )
3457 {
3458   modifyImage();
3459   image()->rendering_intent = renderingIntent_;
3460 }
3461 Magick::RenderingIntent Magick::Image::renderingIntent ( void ) const
3462 {
3463   return static_cast<Magick::RenderingIntent>(constImage()->rendering_intent);
3464 }
3465
3466 void Magick::Image::resolutionUnits
3467   ( const Magick::ResolutionType resolutionUnits_ )
3468 {
3469   modifyImage();
3470   image()->units = resolutionUnits_;
3471   options()->resolutionUnits( resolutionUnits_ );
3472 }
3473 Magick::ResolutionType Magick::Image::resolutionUnits ( void ) const
3474 {
3475   return constOptions()->resolutionUnits( );
3476 }
3477
3478 void Magick::Image::scene ( const unsigned int scene_ )
3479 {
3480   modifyImage();
3481   image()->scene = scene_;
3482 }
3483 unsigned int Magick::Image::scene ( void ) const
3484 {
3485   return constImage()->scene;
3486 }
3487
3488 std::string Magick::Image::signature ( const bool force_ ) const
3489 {
3490   Lock( &_imgRef->_mutexLock );
3491
3492   // Re-calculate image signature if necessary
3493   if ( force_ ||
3494        !GetImageProperty(constImage(), "Signature") ||
3495        constImage()->taint )
3496     {
3497       SignatureImage( const_cast<MagickCore::Image *>(constImage()) );
3498     }
3499
3500   const char *property = GetImageProperty(constImage(), "Signature");
3501
3502   return std::string( property );
3503 }
3504
3505 void Magick::Image::size ( const Geometry &geometry_ )
3506 {
3507   modifyImage();
3508   options()->size( geometry_ );
3509   image()->rows = geometry_.height();
3510   image()->columns = geometry_.width();
3511 }
3512 Magick::Geometry Magick::Image::size ( void ) const
3513 {
3514   return Magick::Geometry( constImage()->columns, constImage()->rows );
3515 }
3516
3517 // Obtain image statistics. Statistics are normalized to the range of
3518 // 0.0 to 1.0 and are output to the specified ImageStatistics
3519 // structure.
3520 void Magick::Image::statistics ( ImageStatistics *statistics ) const
3521 {
3522   double
3523     maximum,
3524     minimum;
3525
3526   ExceptionInfo exceptionInfo;
3527   GetExceptionInfo( &exceptionInfo );
3528   (void) GetImageChannelRange(constImage(),RedChannel,&minimum,&maximum,
3529     &exceptionInfo);
3530   statistics->red.minimum=minimum;
3531         statistics->red.maximum=maximum;
3532   (void) GetImageChannelMean(constImage(),RedChannel,
3533     &statistics->red.mean,&statistics->red.standard_deviation,&exceptionInfo);
3534   (void) GetImageChannelKurtosis(constImage(),RedChannel,
3535     &statistics->red.kurtosis,&statistics->red.skewness,&exceptionInfo);
3536   (void) GetImageChannelRange(constImage(),GreenChannel,&minimum,&maximum,
3537     &exceptionInfo);
3538   statistics->green.minimum=minimum;
3539         statistics->green.maximum=maximum;
3540   (void) GetImageChannelMean(constImage(),GreenChannel,
3541     &statistics->green.mean,&statistics->green.standard_deviation,
3542     &exceptionInfo);
3543   (void) GetImageChannelKurtosis(constImage(),GreenChannel,
3544     &statistics->green.kurtosis,&statistics->green.skewness,&exceptionInfo);
3545   (void) GetImageChannelRange(constImage(),BlueChannel,&minimum,&maximum,
3546     &exceptionInfo);
3547   statistics->blue.minimum=minimum;
3548         statistics->blue.maximum=maximum;
3549   (void) GetImageChannelMean(constImage(),BlueChannel,
3550     &statistics->blue.mean,&statistics->blue.standard_deviation,&exceptionInfo);
3551   (void) GetImageChannelKurtosis(constImage(),BlueChannel,
3552     &statistics->blue.kurtosis,&statistics->blue.skewness,&exceptionInfo);
3553   (void) GetImageChannelRange(constImage(),OpacityChannel,&minimum,&maximum,
3554     &exceptionInfo);
3555   statistics->opacity.minimum=minimum;
3556         statistics->opacity.maximum=maximum;
3557   (void) GetImageChannelMean(constImage(),OpacityChannel,
3558     &statistics->opacity.mean,&statistics->opacity.standard_deviation,
3559     &exceptionInfo);
3560   (void) GetImageChannelKurtosis(constImage(),OpacityChannel,
3561     &statistics->opacity.kurtosis,&statistics->opacity.skewness,&exceptionInfo);
3562   throwException( exceptionInfo );
3563   (void) DestroyExceptionInfo( &exceptionInfo );
3564 }
3565
3566 // enabled/disable stroke anti-aliasing
3567 void Magick::Image::strokeAntiAlias ( const bool flag_ )
3568 {
3569   modifyImage();
3570   options()->strokeAntiAlias(flag_);
3571 }
3572 bool Magick::Image::strokeAntiAlias ( void ) const
3573 {
3574   return constOptions()->strokeAntiAlias();
3575 }
3576
3577 // Color to use when drawing object outlines
3578 void Magick::Image::strokeColor ( const Magick::Color &strokeColor_ )
3579 {
3580   modifyImage();
3581   options()->strokeColor(strokeColor_);
3582 }
3583 Magick::Color Magick::Image::strokeColor ( void ) const
3584 {
3585   return constOptions()->strokeColor();
3586 }
3587
3588 // dash pattern for drawing vector objects (default one)
3589 void Magick::Image::strokeDashArray ( const double* strokeDashArray_ )
3590 {
3591   modifyImage();
3592   options()->strokeDashArray( strokeDashArray_ );
3593 }
3594
3595 const double* Magick::Image::strokeDashArray ( void ) const
3596 {
3597   return constOptions()->strokeDashArray( );
3598 }
3599
3600 // dash offset for drawing vector objects (default one)
3601 void Magick::Image::strokeDashOffset ( const double strokeDashOffset_ )
3602 {
3603   modifyImage();
3604   options()->strokeDashOffset( strokeDashOffset_ );
3605 }
3606
3607 double Magick::Image::strokeDashOffset ( void ) const
3608 {
3609   return constOptions()->strokeDashOffset( );
3610 }
3611
3612 // Specify the shape to be used at the end of open subpaths when they
3613 // are stroked. Values of LineCap are UndefinedCap, ButtCap, RoundCap,
3614 // and SquareCap.
3615 void Magick::Image::strokeLineCap ( const Magick::LineCap lineCap_ )
3616 {
3617   modifyImage();
3618   options()->strokeLineCap( lineCap_ );
3619 }
3620 Magick::LineCap Magick::Image::strokeLineCap ( void ) const
3621 {
3622   return constOptions()->strokeLineCap( );
3623 }
3624
3625 // Specify the shape to be used at the corners of paths (or other
3626 // vector shapes) when they are stroked. Values of LineJoin are
3627 // UndefinedJoin, MiterJoin, RoundJoin, and BevelJoin.
3628 void Magick::Image::strokeLineJoin ( const Magick::LineJoin lineJoin_ )
3629 {
3630   modifyImage();
3631   options()->strokeLineJoin( lineJoin_ );
3632 }
3633 Magick::LineJoin Magick::Image::strokeLineJoin ( void ) const
3634 {
3635   return constOptions()->strokeLineJoin( );
3636 }
3637
3638 // Specify miter limit. When two line segments meet at a sharp angle
3639 // and miter joins have been specified for 'lineJoin', it is possible
3640 // for the miter to extend far beyond the thickness of the line
3641 // stroking the path. The miterLimit' imposes a limit on the ratio of
3642 // the miter length to the 'lineWidth'. The default value of this
3643 // parameter is 4.
3644 void Magick::Image::strokeMiterLimit ( const unsigned int strokeMiterLimit_ )
3645 {
3646   modifyImage();
3647   options()->strokeMiterLimit( strokeMiterLimit_ );
3648 }
3649 unsigned int Magick::Image::strokeMiterLimit ( void ) const
3650 {
3651   return constOptions()->strokeMiterLimit( );
3652 }
3653
3654 // Pattern to use while stroking drawn objects.
3655 void Magick::Image::strokePattern ( const Image &strokePattern_ )
3656 {
3657   modifyImage();
3658   if(strokePattern_.isValid())
3659     options()->strokePattern( strokePattern_.constImage() );
3660   else
3661     options()->strokePattern( static_cast<MagickCore::Image*>(NULL) );
3662 }
3663 Magick::Image  Magick::Image::strokePattern ( void  ) const
3664 {
3665   // FIXME: This is inordinately innefficient
3666   Image texture;
3667   
3668   const MagickCore::Image* tmpTexture = constOptions()->strokePattern( );
3669
3670   if ( tmpTexture )
3671     {
3672       ExceptionInfo exceptionInfo;
3673       GetExceptionInfo( &exceptionInfo );
3674       MagickCore::Image* image =
3675         CloneImage( tmpTexture,
3676                     0, // columns
3677                     0, // rows
3678                     MagickTrue, // orphan
3679                     &exceptionInfo);
3680       throwException( exceptionInfo );
3681   (void) DestroyExceptionInfo( &exceptionInfo );
3682       texture.replaceImage( image );
3683     }
3684   return texture;
3685 }
3686
3687 // Stroke width for drawing lines, circles, ellipses, etc.
3688 void Magick::Image::strokeWidth ( const double strokeWidth_ )
3689 {
3690   modifyImage();
3691   options()->strokeWidth( strokeWidth_ );
3692 }
3693 double Magick::Image::strokeWidth ( void ) const
3694 {
3695   return constOptions()->strokeWidth( );
3696 }
3697
3698 void Magick::Image::subImage ( const unsigned int subImage_ )
3699 {
3700   modifyImage();
3701   options()->subImage( subImage_ );
3702 }
3703 unsigned int Magick::Image::subImage ( void ) const
3704 {
3705   return constOptions()->subImage( );
3706 }
3707
3708 void Magick::Image::subRange ( const unsigned int subRange_ )
3709 {
3710   modifyImage();
3711   options()->subRange( subRange_ );
3712 }
3713 unsigned int Magick::Image::subRange ( void ) const
3714 {
3715   return constOptions()->subRange( );
3716 }
3717
3718 // Annotation text encoding (e.g. "UTF-16")
3719 void Magick::Image::textEncoding ( const std::string &encoding_ )
3720 {
3721   modifyImage();
3722   options()->textEncoding( encoding_ );
3723 }
3724 std::string Magick::Image::textEncoding ( void ) const
3725 {
3726   return constOptions()->textEncoding( );
3727 }
3728
3729 void Magick::Image::tileName ( const std::string &tileName_ )
3730 {
3731   modifyImage();
3732   options()->tileName( tileName_ );
3733 }
3734 std::string Magick::Image::tileName ( void ) const
3735 {
3736   return constOptions()->tileName( );
3737 }
3738
3739 unsigned long Magick::Image::totalColors ( void )
3740 {
3741   ExceptionInfo exceptionInfo;
3742   GetExceptionInfo( &exceptionInfo );
3743   unsigned long colors = GetNumberColors( image(), 0, &exceptionInfo);
3744   throwException( exceptionInfo );
3745   (void) DestroyExceptionInfo( &exceptionInfo );
3746   return colors;
3747 }
3748
3749 // Origin of coordinate system to use when annotating with text or drawing
3750 void Magick::Image::transformOrigin ( const double x_, const double y_ )
3751 {
3752   modifyImage();
3753   options()->transformOrigin( x_, y_ );
3754 }
3755
3756 // Rotation to use when annotating with text or drawing
3757 void Magick::Image::transformRotation ( const double angle_ )
3758 {
3759   modifyImage();
3760   options()->transformRotation( angle_ );
3761 }
3762
3763 // Reset transformation parameters to default
3764 void Magick::Image::transformReset ( void )
3765 {
3766   modifyImage();
3767   options()->transformReset();
3768 }
3769
3770 // Scale to use when annotating with text or drawing
3771 void Magick::Image::transformScale ( const double sx_, const double sy_ )
3772 {
3773   modifyImage();
3774   options()->transformScale( sx_, sy_ );
3775 }
3776
3777 // Skew to use in X axis when annotating with text or drawing
3778 void Magick::Image::transformSkewX ( const double skewx_ )
3779 {
3780   modifyImage();
3781   options()->transformSkewX( skewx_ );
3782 }
3783
3784 // Skew to use in Y axis when annotating with text or drawing
3785 void Magick::Image::transformSkewY ( const double skewy_ )
3786 {
3787   modifyImage();
3788   options()->transformSkewY( skewy_ );
3789 }
3790
3791 // Image representation type
3792 Magick::ImageType Magick::Image::type ( void ) const
3793 {
3794
3795   ExceptionInfo exceptionInfo;
3796   GetExceptionInfo( &exceptionInfo );
3797   ImageType image_type = constOptions()->type();
3798   if ( image_type == UndefinedType )
3799     image_type= GetImageType( constImage(), &exceptionInfo);
3800   throwException( exceptionInfo );
3801   (void) DestroyExceptionInfo( &exceptionInfo );
3802   return image_type;
3803 }
3804 void Magick::Image::type ( const Magick::ImageType type_)
3805 {
3806   modifyImage();
3807   options()->type( type_ );
3808   SetImageType( image(), type_ );
3809 }
3810
3811 void Magick::Image::verbose ( const bool verboseFlag_ )
3812 {
3813   modifyImage();
3814   options()->verbose( verboseFlag_ );
3815 }
3816 bool Magick::Image::verbose ( void ) const
3817 {
3818   return constOptions()->verbose( );
3819 }
3820
3821 void Magick::Image::view ( const std::string &view_ )
3822 {
3823   modifyImage();
3824   options()->view( view_ );
3825 }
3826 std::string Magick::Image::view ( void ) const
3827 {
3828   return constOptions()->view( );
3829 }
3830
3831 // Virtual pixel method
3832 void Magick::Image::virtualPixelMethod ( const VirtualPixelMethod virtual_pixel_method_ )
3833 {
3834   modifyImage();
3835   SetImageVirtualPixelMethod( image(), virtual_pixel_method_ );
3836   options()->virtualPixelMethod( virtual_pixel_method_ );
3837 }
3838 Magick::VirtualPixelMethod Magick::Image::virtualPixelMethod ( void ) const
3839 {
3840   return GetImageVirtualPixelMethod( constImage() );
3841 }
3842
3843 void Magick::Image::x11Display ( const std::string &display_ )
3844 {
3845   modifyImage();
3846   options()->x11Display( display_ );
3847 }
3848 std::string Magick::Image::x11Display ( void ) const
3849 {
3850   return constOptions()->x11Display( );
3851 }
3852
3853 double Magick::Image::xResolution ( void ) const
3854 {
3855   return constImage()->x_resolution;
3856 }
3857 double Magick::Image::yResolution ( void ) const
3858 {
3859   return constImage()->y_resolution;
3860 }
3861
3862 // Copy Constructor
3863 Magick::Image::Image( const Image & image_ )
3864   : _imgRef(image_._imgRef)
3865 {
3866   Lock( &_imgRef->_mutexLock );
3867
3868   // Increase reference count
3869   ++_imgRef->_refCount;
3870 }
3871
3872 // Assignment operator
3873 Magick::Image& Magick::Image::operator=( const Magick::Image &image_ )
3874 {
3875   if( this != &image_ )
3876     {
3877       {
3878         Lock( &image_._imgRef->_mutexLock );
3879         ++image_._imgRef->_refCount;
3880       }
3881
3882       bool doDelete = false;
3883       {
3884         Lock( &_imgRef->_mutexLock );
3885         if ( --_imgRef->_refCount == 0 )
3886           doDelete = true;
3887       }
3888
3889       if ( doDelete )
3890         {
3891           // Delete old image reference with associated image and options.
3892           delete _imgRef;
3893           _imgRef = 0;
3894         }
3895       // Use new image reference
3896       _imgRef = image_._imgRef;
3897     }
3898
3899   return *this;
3900 }
3901
3902 //////////////////////////////////////////////////////////////////////    
3903 //
3904 // Low-level Pixel Access Routines
3905 //
3906 // Also see the Pixels class, which provides support for multiple
3907 // cache views. The low-level pixel access routines in the Image
3908 // class are provided in order to support backward compatability.
3909 //
3910 //////////////////////////////////////////////////////////////////////
3911
3912 // Transfers read-only pixels from the image to the pixel cache as
3913 // defined by the specified region
3914 const Magick::PixelPacket* Magick::Image::getConstPixels
3915   ( const int x_, const int y_,
3916     const unsigned int columns_,
3917     const unsigned int rows_ ) const
3918 {
3919   ExceptionInfo exceptionInfo;
3920   GetExceptionInfo( &exceptionInfo );
3921   const PixelPacket* p = (*GetVirtualPixels)( constImage(),
3922                                                 x_, y_,
3923                                                 columns_, rows_,
3924                                                 &exceptionInfo );
3925   throwException( exceptionInfo );
3926   (void) DestroyExceptionInfo( &exceptionInfo );
3927   return p;
3928 }
3929
3930 // Obtain read-only pixel indexes (valid for PseudoClass images)
3931 const Magick::IndexPacket* Magick::Image::getConstIndexes ( void ) const
3932 {
3933   const Magick::IndexPacket* result = GetVirtualIndexQueue( constImage() );
3934
3935   if( !result )
3936     throwImageException();
3937
3938   return result;
3939 }
3940
3941 // Obtain image pixel indexes (valid for PseudoClass images)
3942 Magick::IndexPacket* Magick::Image::getIndexes ( void )
3943 {
3944   Magick::IndexPacket* result = GetAuthenticIndexQueue( image() );
3945
3946   if( !result )
3947     throwImageException();
3948
3949   return ( result );
3950 }
3951
3952 // Transfers pixels from the image to the pixel cache as defined
3953 // by the specified region. Modified pixels may be subsequently
3954 // transferred back to the image via syncPixels.
3955 Magick::PixelPacket* Magick::Image::getPixels ( const int x_, const int y_,
3956                                                 const unsigned int columns_,
3957                                                 const unsigned int rows_ )
3958 {
3959   modifyImage();
3960   ExceptionInfo exceptionInfo;
3961   GetExceptionInfo( &exceptionInfo );
3962   PixelPacket* result = (*GetAuthenticPixels)( image(),
3963                                            x_, y_,
3964                                            columns_, rows_, &exceptionInfo );
3965   throwException( exceptionInfo );
3966   (void) DestroyExceptionInfo( &exceptionInfo );
3967
3968   return result;
3969 }
3970
3971 // Allocates a pixel cache region to store image pixels as defined
3972 // by the region rectangle.  This area is subsequently transferred
3973 // from the pixel cache to the image via syncPixels.
3974 Magick::PixelPacket* Magick::Image::setPixels ( const int x_, const int y_,
3975                                                 const unsigned int columns_,
3976                                                 const unsigned int rows_ )
3977 {
3978   modifyImage();
3979   ExceptionInfo exceptionInfo;
3980   GetExceptionInfo( &exceptionInfo );
3981   PixelPacket* result = (*QueueAuthenticPixels)( image(),
3982                                            x_, y_,
3983                                            columns_, rows_, &exceptionInfo );
3984   throwException( exceptionInfo );
3985   (void) DestroyExceptionInfo( &exceptionInfo );
3986
3987   return result;
3988 }
3989
3990 // Transfers the image cache pixels to the image.
3991 void Magick::Image::syncPixels ( void )
3992 {
3993   ExceptionInfo exceptionInfo;
3994   GetExceptionInfo( &exceptionInfo );
3995   (*SyncAuthenticPixels)( image(), &exceptionInfo );
3996   throwException( exceptionInfo );
3997   (void) DestroyExceptionInfo( &exceptionInfo );
3998 }
3999
4000 // Transfers one or more pixel components from a buffer or file
4001 // into the image pixel cache of an image.
4002 // Used to support image decoders.
4003 void Magick::Image::readPixels ( const Magick::QuantumType quantum_,
4004                                  const unsigned char *source_ )
4005 {
4006   QuantumInfo
4007     *quantum_info;
4008
4009   quantum_info=AcquireQuantumInfo(imageInfo(),image());
4010   ExceptionInfo exceptionInfo;
4011   GetExceptionInfo( &exceptionInfo );
4012   ImportQuantumPixels(image(),(MagickCore::CacheView *) NULL,quantum_info,
4013     quantum_,source_, &exceptionInfo);
4014   throwException( exceptionInfo );
4015   (void) DestroyExceptionInfo( &exceptionInfo );
4016   quantum_info=DestroyQuantumInfo(quantum_info);
4017 }
4018
4019 // Transfers one or more pixel components from the image pixel
4020 // cache to a buffer or file.
4021 // Used to support image encoders.
4022 void Magick::Image::writePixels ( const Magick::QuantumType quantum_,
4023                                   unsigned char *destination_ )
4024 {
4025   QuantumInfo
4026     *quantum_info;
4027
4028   quantum_info=AcquireQuantumInfo(imageInfo(),image());
4029   ExceptionInfo exceptionInfo;
4030   GetExceptionInfo( &exceptionInfo );
4031   ExportQuantumPixels(image(),(MagickCore::CacheView *) NULL,quantum_info,
4032     quantum_,destination_, &exceptionInfo);
4033   quantum_info=DestroyQuantumInfo(quantum_info);
4034   throwException( exceptionInfo );
4035   (void) DestroyExceptionInfo( &exceptionInfo );
4036 }
4037
4038 /////////////////////////////////////////////////////////////////////
4039 //
4040 // No end-user methods beyond this point
4041 //
4042 /////////////////////////////////////////////////////////////////////
4043
4044
4045 //
4046 // Construct using existing image and default options
4047 //
4048 Magick::Image::Image ( MagickCore::Image* image_ )
4049   : _imgRef(new ImageRef( image_))
4050 {
4051 }
4052
4053 // Get Magick::Options*
4054 Magick::Options* Magick::Image::options( void )
4055 {
4056   return _imgRef->options();
4057 }
4058 const Magick::Options* Magick::Image::constOptions( void ) const
4059 {
4060   return _imgRef->options();
4061 }
4062
4063 // Get MagickCore::Image*
4064 MagickCore::Image*& Magick::Image::image( void )
4065 {
4066   return _imgRef->image();
4067 }
4068 const MagickCore::Image* Magick::Image::constImage( void ) const
4069 {
4070   return _imgRef->image();
4071 }
4072
4073 // Get ImageInfo *
4074 MagickCore::ImageInfo* Magick::Image::imageInfo( void )
4075 {
4076   return _imgRef->options()->imageInfo();
4077 }
4078 const MagickCore::ImageInfo * Magick::Image::constImageInfo( void ) const
4079 {
4080   return _imgRef->options()->imageInfo();
4081 }
4082
4083 // Get QuantizeInfo *
4084 MagickCore::QuantizeInfo* Magick::Image::quantizeInfo( void )
4085 {
4086   return _imgRef->options()->quantizeInfo();
4087 }
4088 const MagickCore::QuantizeInfo * Magick::Image::constQuantizeInfo( void ) const
4089 {
4090   return _imgRef->options()->quantizeInfo();
4091 }
4092
4093 //
4094 // Replace current image
4095 //
4096 MagickCore::Image * Magick::Image::replaceImage
4097   ( MagickCore::Image* replacement_ )
4098 {
4099   MagickCore::Image* image;
4100   
4101   if( replacement_ )
4102     image = replacement_;
4103   else
4104     image = AcquireImage(constImageInfo());
4105
4106   {
4107     Lock( &_imgRef->_mutexLock );
4108
4109     if ( _imgRef->_refCount == 1 )
4110       {
4111         // We own the image, just replace it, and de-register
4112         _imgRef->id( -1 );
4113         _imgRef->image(image);
4114       }
4115     else
4116       {
4117         // We don't own the image, dereference and replace with copy
4118         --_imgRef->_refCount;
4119         _imgRef = new ImageRef( image, constOptions() );
4120       }
4121   }
4122
4123   return _imgRef->_image;
4124 }
4125
4126 //
4127 // Prepare to modify image or image options
4128 // Replace current image and options with copy if reference count > 1
4129 //
4130 void Magick::Image::modifyImage( void )
4131 {
4132   {
4133     Lock( &_imgRef->_mutexLock );
4134     if ( _imgRef->_refCount == 1 )
4135       {
4136         // De-register image and return
4137         _imgRef->id( -1 );
4138         return;
4139       }
4140   }
4141
4142   ExceptionInfo exceptionInfo;
4143   GetExceptionInfo( &exceptionInfo );
4144   replaceImage( CloneImage( image(),
4145                             0, // columns
4146                             0, // rows
4147                             MagickTrue, // orphan
4148                             &exceptionInfo) );
4149   throwException( exceptionInfo );
4150   (void) DestroyExceptionInfo( &exceptionInfo );
4151   return;
4152 }
4153
4154 //
4155 // Test for an ImageMagick reported error and throw exception if one
4156 // has been reported.  Secretly resets image->exception back to default
4157 // state even though this method is const.
4158 //
4159 void Magick::Image::throwImageException( void ) const
4160 {
4161   // Throw C++ exception while resetting Image exception to default state
4162   throwException( const_cast<MagickCore::Image*>(constImage())->exception );
4163 }
4164
4165 // Register image with image registry or obtain registration id
4166 long Magick::Image::registerId( void )
4167 {
4168   Lock( &_imgRef->_mutexLock );
4169   if( _imgRef->id() < 0 )
4170     {
4171       char id[MaxTextExtent];
4172       ExceptionInfo exceptionInfo;
4173       GetExceptionInfo( &exceptionInfo );
4174       _imgRef->id(_imgRef->id()+1);
4175       sprintf(id,"%ld\n",_imgRef->id());
4176       SetImageRegistry(ImageRegistryType, id, image(), &exceptionInfo);
4177       throwException( exceptionInfo );
4178   (void) DestroyExceptionInfo( &exceptionInfo );
4179     }
4180   return _imgRef->id();
4181 }
4182
4183 // Unregister image from image registry
4184 void Magick::Image::unregisterId( void )
4185 {
4186   modifyImage();
4187   _imgRef->id( -1 );
4188 }
4189
4190 //
4191 // Create a local wrapper around MagickCoreTerminus
4192 //
4193 namespace Magick
4194 {
4195   extern "C" {
4196     void MagickPlusPlusDestroyMagick(void);
4197   }
4198 }
4199
4200 void Magick::MagickPlusPlusDestroyMagick(void)
4201 {
4202   if (magick_initialized)
4203     {
4204       magick_initialized=false;
4205       MagickCore::MagickCoreTerminus();
4206     }
4207 }
4208
4209 // C library initialization routine
4210 void MagickDLLDecl Magick::InitializeMagick(const char *path_)
4211 {
4212   MagickCore::MagickCoreGenesis(path_,MagickFalse);
4213   if (!magick_initialized)
4214     magick_initialized=true;
4215 }
4216
4217 //
4218 // Cleanup class to ensure that ImageMagick singletons are destroyed
4219 // so as to avoid any resemblence to a memory leak (which seems to
4220 // confuse users)
4221 //
4222 namespace Magick
4223 {
4224
4225   class MagickCleanUp
4226   {
4227   public:
4228     MagickCleanUp( void );
4229     ~MagickCleanUp( void );
4230   };
4231
4232   // The destructor for this object is invoked when the destructors for
4233   // static objects in this translation unit are invoked.
4234   static MagickCleanUp magickCleanUpGuard;
4235 }
4236
4237 Magick::MagickCleanUp::MagickCleanUp ( void )
4238 {
4239   // Don't even think about invoking InitializeMagick here!
4240 }
4241
4242 Magick::MagickCleanUp::~MagickCleanUp ( void )
4243 {
4244   MagickPlusPlusDestroyMagick();
4245 }