]> granicus.if.org Git - imagemagick/blob - MagickWand/operation.c
Removed 3 redundant lines of code from coders/png.c
[imagemagick] / MagickWand / operation.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %             OOO  PPPP  EEEE RRRR   AA  TTTTTT III  OOO  N   N               %
7 %            O   O P   P E    R   R A  A   TT    I  O   O NN  N               %
8 %            O   O PPPP  EEE  RRRR  AAAA   TT    I  O   O N N N               %
9 %            O   O P     E    R R   A  A   TT    I  O   O N  NN               %
10 %             OOO  P     EEEE R  RR A  A   TT   III  OOO  N   N               %
11 %                                                                             %
12 %                                                                             %
13 %                         MagickWand Module Methods                           %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                               September 2011                                %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 % Apply the given options (settings, and simple, or sequence operations) to
37 % the given image(s) according to the current "image_info" and "draw_info"
38 % settings.
39 %
40 % The final goal is to allow the execution in a strict one option at a time
41 % manner that is needed for 'pipelining and file scripting' of options in
42 % IMv7.
43 %
44 % Anthony Thyssen, Sept 2011
45 */
46 #if 0
47 \f
48 /*
49   Include declarations.
50 */
51 #include "MagickWand/studio.h"
52 #include "MagickWand/MagickWand.h"
53 #include "MagickWand/mogrify-private.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/thread-private.h"
56 #include "MagickCore/string-private.h"
57 \f
58 /*
59   Define declarations.
60 */
61 #define UndefinedCompressionQuality  0UL
62 /*
63   Constant declaration. (temporary exports)
64 */
65 static const char
66   BackgroundColor[] = "#fff",  /* white */
67   BorderColor[] = "#dfdfdf",  /* gray */
68   MatteColor[] = "#bdbdbd";  /* gray */
69 \f
70 /*
71 ** Function to report on the progress of image operations
72 */
73 static MagickBooleanType MonitorProgress(const char *text,
74   const MagickOffsetType offset,const MagickSizeType extent,
75   void *wand_unused(client_data))
76 {
77   char
78     message[MaxTextExtent],
79     tag[MaxTextExtent];
80
81   const char
82     *locale_message;
83
84   register char
85     *p;
86
87   if (extent < 2)
88     return(MagickTrue);
89   (void) CopyMagickMemory(tag,text,MaxTextExtent);
90   p=strrchr(tag,'/');
91   if (p != (char *) NULL)
92     *p='\0';
93   (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
94   locale_message=GetLocaleMessage(message);
95   if (locale_message == message)
96     locale_message=tag;
97   if (p == (char *) NULL)
98     (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
99       locale_message,(long) offset,(unsigned long) extent,(long)
100       (100L*offset/(extent-1)));
101   else
102     (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
103       locale_message,p+1,(long) offset,(unsigned long) extent,(long)
104       (100L*offset/(extent-1)));
105   if (offset == (MagickOffsetType) (extent-1))
106     (void) FormatLocaleFile(stderr,"\n");
107   (void) fflush(stderr);
108   return(MagickTrue);
109 }
110
111 /*
112 ** GetImageCache() will read an image into a image cache if not already
113 ** present then return the image that is in the cache under that filename.
114 */
115 static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
116   ExceptionInfo *exception)
117 {
118   char
119     key[MaxTextExtent];
120
121   ExceptionInfo
122     *sans_exception;
123
124   Image
125     *image;
126
127   ImageInfo
128     *read_info;
129
130   (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
131   sans_exception=AcquireExceptionInfo();
132   image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
133   sans_exception=DestroyExceptionInfo(sans_exception);
134   if (image != (Image *) NULL)
135     return(image);
136   read_info=CloneImageInfo(image_info);
137   (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
138   image=ReadImage(read_info,exception);
139   read_info=DestroyImageInfo(read_info);
140   if (image != (Image *) NULL)
141     (void) SetImageRegistry(ImageRegistryType,key,image,exception);
142   return(image);
143 }
144
145 /*
146   SparseColorOption() parse the complex -sparse-color argument into an
147   an array of floating point values than call SparseColorImage().
148   Argument is a complex mix of floating-point pixel coodinates, and color
149   specifications (or direct floating point numbers).  The number of floats
150   needed to represent a color varies depending on teh current channel
151   setting.
152 */
153 static Image *SparseColorOption(const Image *image,
154   const SparseColorMethod method,const char *arguments,
155   const MagickBooleanType color_from_image,ExceptionInfo *exception)
156 {
157   char
158     token[MaxTextExtent];
159
160   const char
161     *p;
162
163   double
164     *sparse_arguments;
165
166   Image
167     *sparse_image;
168
169   PixelInfo
170     color;
171
172   MagickBooleanType
173     error;
174
175   register size_t
176     x;
177
178   size_t
179     number_arguments,
180     number_colors;
181
182   assert(image != (Image *) NULL);
183   assert(image->signature == MagickSignature);
184   if (image->debug != MagickFalse)
185     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
186   assert(exception != (ExceptionInfo *) NULL);
187   assert(exception->signature == MagickSignature);
188   /*
189     Limit channels according to image - and add up number of color channel.
190   */
191   number_colors=0;
192   if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
193     number_colors++;
194   if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
195     number_colors++;
196   if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
197     number_colors++;
198   if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
199       (image->colorspace == CMYKColorspace))
200     number_colors++;
201   if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
202       (image->matte != MagickFalse))
203     number_colors++;
204
205   /*
206     Read string, to determine number of arguments needed,
207   */
208   p=arguments;
209   x=0;
210   while( *p != '\0' )
211   {
212     GetMagickToken(p,&p,token);
213     if ( token[0] == ',' ) continue;
214     if ( isalpha((int) token[0]) || token[0] == '#' ) {
215       if ( color_from_image ) {
216         (void) ThrowMagickException(exception,GetMagickModule(),
217             OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
218             "Color arg given, when colors are coming from image");
219         return( (Image *)NULL);
220       }
221       x += number_colors;  /* color argument */
222     }
223     else {
224       x++;   /* floating point argument */
225     }
226   }
227   error=MagickTrue;
228   if ( color_from_image ) {
229     /* just the control points are being given */
230     error = ( x % 2 != 0 ) ? MagickTrue : MagickFalse;
231     number_arguments=(x/2)*(2+number_colors);
232   }
233   else {
234     /* control points and color values */
235     error = ( x % (2+number_colors) != 0 ) ? MagickTrue : MagickFalse;
236     number_arguments=x;
237   }
238   if ( error ) {
239     (void) ThrowMagickException(exception,GetMagickModule(),
240                OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
241                "Invalid number of Arguments");
242     return( (Image *)NULL);
243   }
244
245   /* Allocate and fill in the floating point arguments */
246   sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
247     sizeof(*sparse_arguments));
248   if (sparse_arguments == (double *) NULL) {
249     (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
250       "MemoryAllocationFailed","%s","SparseColorOption");
251     return( (Image *)NULL);
252   }
253   (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
254     sizeof(*sparse_arguments));
255   p=arguments;
256   x=0;
257   while( *p != '\0' && x < number_arguments ) {
258     /* X coordinate */
259     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
260     if ( token[0] == '\0' ) break;
261     if ( isalpha((int) token[0]) || token[0] == '#' ) {
262       (void) ThrowMagickException(exception,GetMagickModule(),
263             OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
264             "Color found, instead of X-coord");
265       error = MagickTrue;
266       break;
267     }
268     sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
269     /* Y coordinate */
270     token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
271     if ( token[0] == '\0' ) break;
272     if ( isalpha((int) token[0]) || token[0] == '#' ) {
273       (void) ThrowMagickException(exception,GetMagickModule(),
274             OptionError, "InvalidArgument", "`%s': %s", "sparse-color",
275             "Color found, instead of Y-coord");
276       error = MagickTrue;
277       break;
278     }
279     sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
280     /* color values for this control point */
281 #if 0
282     if ( (color_from_image ) {
283       /* get color from image */
284       /* HOW??? */
285     }
286     else
287 #endif
288     {
289       /* color name or function given in string argument */
290       token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
291       if ( token[0] == '\0' ) break;
292       if ( isalpha((int) token[0]) || token[0] == '#' ) {
293         /* Color string given */
294         (void) QueryColorCompliance(token,AllCompliance,&color,
295                   exception);
296         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
297           sparse_arguments[x++] = QuantumScale*color.red;
298         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
299           sparse_arguments[x++] = QuantumScale*color.green;
300         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
301           sparse_arguments[x++] = QuantumScale*color.blue;
302         if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
303             (image->colorspace == CMYKColorspace))
304           sparse_arguments[x++] = QuantumScale*color.black;
305         if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
306             (image->matte != MagickFalse))
307           sparse_arguments[x++] = QuantumScale*color.alpha;
308       }
309       else {
310         /* Colors given as a set of floating point values - experimental */
311         /* NB: token contains the first floating point value to use! */
312         if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
313           {
314           while ( token[0] == ',' ) GetMagickToken(p,&p,token);
315           if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
316             break;
317           sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
318           token[0] = ','; /* used this token - get another */
319         }
320         if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
321           {
322           while ( token[0] == ',' ) GetMagickToken(p,&p,token);
323           if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
324             break;
325           sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
326           token[0] = ','; /* used this token - get another */
327         }
328         if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
329           {
330           while ( token[0] == ',' ) GetMagickToken(p,&p,token);
331           if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
332             break;
333           sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
334           token[0] = ','; /* used this token - get another */
335         }
336         if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
337             (image->colorspace == CMYKColorspace))
338           {
339           while ( token[0] == ',' ) GetMagickToken(p,&p,token);
340           if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
341             break;
342           sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
343           token[0] = ','; /* used this token - get another */
344         }
345         if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
346             (image->matte != MagickFalse))
347           {
348           while ( token[0] == ',' ) GetMagickToken(p,&p,token);
349           if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
350             break;
351           sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
352           token[0] = ','; /* used this token - get another */
353         }
354       }
355     }
356   }
357   if ( number_arguments != x && !error ) {
358     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
359       "InvalidArgument","`%s': %s","sparse-color","Argument Parsing Error");
360     sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
361     return( (Image *)NULL);
362   }
363   if ( error )
364     return( (Image *)NULL);
365
366   /* Call the Interpolation function with the parsed arguments */
367   sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
368     exception);
369   sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
370   return( sparse_image );
371 }
372 \f
373 /*
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 %                                                                             %
376 %                                                                             %
377 %                                                                             %
378 +   A p p l y S e t t i n g O p t i o n                                       %
379 %                                                                             %
380 %                                                                             %
381 %                                                                             %
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 %
384 %  ApplySettingOption() applies a single settings option into a CLI wand
385 %  holding the image_info, draw_info, quantize_info structures that will be
386 %  later used when processing images.
387 %
388 %  These options require no images to be present in the wand for them to be
389 %  able to be set.  That is they may be used before the first image is read.
390 %
391 %  The format of the ApplySettingOption method is:
392 %
393 %    MagickBooleanType ApplySettingOption(MagickWand *wand,
394 %        const char *option, const MagickBooleanType set_option, const char
395 %        **args, ExceptionInfo *exception)
396 %
397 %  A description of each parameter follows:
398 %
399 %    o wand: structure holding settings to be applied
400 %
401 %    o option: The option string to be set
402 %
403 %    o set_option: is the option being set, or reset to some default
404 %
405 %    o arg: the single argument (if needed) to set this option.
406 %
407 %    o exception: return any errors or warnings in this structure.
408 %
409 %
410 % Example usage (FUTURE)
411 %
412 %    argc,argv
413 %    i=index in argv
414 %
415 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
416 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
417 %    if ( flags == MagickCommandOptions )
418 %      ApplySettingsOption(wand, argv[i]+1,
419 %          (*argv[i])=='-' ? MagickTrue : MagickFalse,
420 %          (count>0)? argv[i+1]:(char *)NULL,
421 %          exception);
422 %    i += count+1;
423 %
424 */
425 WandExport MagickBooleanType ApplySettingsOption(MagickWand *wand,
426   const char *option, const MagickBooleanType set_option, const char *arg,
427   ExceptionInfo *exception)
428 {
429   assert(wand != (MagickWand *) NULL);
430   assert(wand->signature == WandSignature);
431   assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
432   if (wand->debug != MagickFalse)
433     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
434
435 #define image_info    (wand->image_info)
436 #define draw_info     (wand->draw_info)
437 #define quantize_info (wand->quantize_info)
438 #define IfSetOption   (set_option != MagickFalse)
439 #define IfArgOption   (IfSetOption?arg:(char *)NULL)
440
441   switch (*option)
442   {
443     case 'a':
444     {
445       if (LocaleCompare("adjoin",option) == 0)
446         {
447           image_info->adjoin = set_option;
448           break;
449         }
450       if (LocaleCompare("affine",option) == 0)
451         {
452           /* draw_info setting only */
453           if (IfSetOption)
454             (void) ParseAffineGeometry(arg,draw_info->affine,exception);
455           else
456             GetAffineMatrix(draw_info->affine);
457           break;
458         }
459       if (LocaleCompare("antialias",option) == 0)
460         {
461           image_info->antialias =
462           draw_info->stroke_antialias =
463           draw_info->text_antialias = set_option;
464           break;
465         }
466       if (LocaleCompare("authenticate",option) == 0)
467         {
468           (void) SetImageOption(image_info,option,IfArgOption);
469           break;
470         }
471       break;
472     }
473     case 'b':
474     {
475       if (LocaleCompare("background",option) == 0)
476         {
477           /* FUTURE: both image_info attribute & ImageOption in use!
478              image_info only used for generating new images.
479              Note that +background, means fall-back to image
480              attribute so ImageOption is deleted, not set to a default.
481           */
482           if (IfSetOption)
483             {
484               (void) SetImageOption(image_info,option,arg);
485               (void) QueryColorCompliance(arg,AllCompliance,
486                    image_info->background_color,exception);
487               break;
488             }
489           (void) DeleteImageOption(image_info,option);
490           (void) QueryColorCompliance("none",AllCompliance,
491                image_info->background_color,exception);
492           break;
493         }
494       if (LocaleCompare("bias",option) == 0)
495         {
496           /* FUTURE: bias OBSOLETED, replaced by "convolve:bias"
497              as it is actually rarely used except in direct convolve
498              Usage outside direct convolve is actally non-sensible!
499           */
500           (void) SetImageOption(image_info,option,
501                IfSetOption ? arg : "0");
502           break;
503         }
504       if (LocaleCompare("black-point-compensation",option) == 0)
505         {
506           /* Used as a image chromaticity setting */
507           (void) SetImageOption(image_info,option,
508                IfSetOption ? "true" : "false" );
509           break;
510         }
511       if (LocaleCompare("blue-primary",option) == 0)
512         {
513           /* Image chromaticity X,Y  NB: Y=X if Y not defined
514              Used by many coders including PNG
515           */
516           (void) SetImageOption(image_info,option,
517                IfSetOption ? arg : "0" );
518           break;
519         }
520       if (LocaleCompare("bordercolor",option) == 0)
521         {
522           /* FUTURE: both image_info attribute & ImageOption in use! */
523           if (IfSetOption)
524             {
525               (void) SetImageOption(image_info,option,arg);
526               (void) QueryColorCompliance(arg,AllCompliece,
527                   &image_info->border_color,exception);
528               (void) QueryColorCompliance(arg,AllCompliance,
529                   &draw_info->border_color,exception);
530               break;
531             }
532           (void) DeleteImageOption(image_info,option);
533           (void) QueryColorCompliance(BorderColor,AllCompliance,
534             &image_info->border_color,exception);
535           (void) QueryColorCompliance(BorderColor,AllCompliance,
536             &draw_info->border_color,exception);
537           break;
538         }
539       if (LocaleCompare("box",option) == 0)
540         {
541           /* Only used to set draw_info for text drawing */
542           const char
543             *value = IfSetOption ? arg : "none";
544           (void) SetImageOption(image_info,option,value);
545           (void) QueryColorCompliance(value,AllCompliance,
546                &draw_info->undercolor,exception);
547           break;
548         }
549       break;
550     }
551     case 'c':
552     {
553       if (LocaleCompare("cache",option) == 0)
554         {
555           MagickSizeType
556             limit;
557
558           limit=MagickResourceInfinity;
559           if (LocaleCompare("unlimited",arg) != 0)
560             limit=(MagickSizeType) SiPrefixToDoubleInterval(arg,100.0);
561           (void) SetMagickResourceLimit(MemoryResource,limit);
562           (void) SetMagickResourceLimit(MapResource,2*limit);
563           break;
564         }
565       if (LocaleCompare("caption",option) == 0)
566         {
567           (void) SetImageOption(image_info,option,IfSetOption ? arg :
568             (const char*)NULL);
569           break;
570         }
571       if (LocaleCompare("channel",option) == 0)
572         {
573           /* FUTURE: This is also a SimpleImageOperator!!! */
574           image_info->channel=(ChannelType) (
575                IfSetOption ? ParseChannelOption(arg) : DefaultChannels );
576           /* This is also a SimpleImageOperator */
577           break;
578         }
579       if (LocaleCompare("colorspace",option) == 0)
580         {
581           /* Setting used for new images via AquireImage()
582              But also used as a SimpleImageOperator
583              Undefined colorspace means don't modify images on
584              read or as a operation */
585           image_info->colorspace=UndefinedColorspace;
586           if (IfSetOption)
587             image_info->colorspace=(ColorspaceType) ParseCommandOption(
588                  MagickColorspaceOptions,MagickFalse,arg)
589           break;
590         }
591       if (LocaleCompare("comment",option) == 0)
592         {
593           (void) SetImageOption(image_info,option,
594                IfSetOption ? arg : (const char*)NULL);
595           break;
596         }
597       if (LocaleCompare("compose",option) == 0)
598         {
599           /* FUTURE: image_info should be used, but Option kept escapes
600              This setting should NOT be used to set image 'compose'
601              which is used by "-layer" operators is image_info is undefined
602           */
603           (void) SetImageOption(image_info,option,
604                IfSetOption ? arg : (const char*)NULL);
605           image_info->compose=(CompositeOperator) ParseCommandOption(
606                MagickComposeOptions,MagickFalse,
607                IfSetOption ? arg : "undefined");
608           break;
609         }
610       if (LocaleCompare("compress",option) == 0)
611         {
612           /* FUTURE: What should be used?  image_info  or ImageOption ???
613              The former is more efficent, but Crisy prefers the latter!
614
615              The coders appears to use image_info, not Image_Option
616              however the image attribute (for save) is set from the
617              ImageOption!
618           */
619           if (IfSetOption)
620             {
621               image_info->compression=(CompressionType) ParseCommandOption(
622                 MagickCompressOptions,MagickFalse,arg);
623               (void) SetImageOption(image_info,option,arg);
624               break;
625             }
626           image_info->compression=UndefinedCompression;
627           (void) SetImageOption(image_info,option,"undefined");
628           break;
629         }
630       break;
631     }
632     case 'd':
633     {
634       if (LocaleCompare("debug",option) == 0)
635         {
636           if (IfSetOption)
637           (void) SetLogEventMask(IfSetOption?arg:"none");
638           image_info->debug=IsEventLogging(); /* extract logging*/
639           wand->debug=IsEventLogging();
640           break;
641         }
642       if (LocaleCompare("define",option) == 0)
643         {
644           /* FUTURE both -set and -define sets ImageOption
645              But differs in that -set tries to set image properity (attributes)
646           */
647           if (LocaleNCompare(arg,"registry:",9) == 0)
648             {
649               if (IfSetOption)
650                 (void) DefineImageRegistry(StringRegistryType,arg+9,
651                     exception);
652               else
653                 (void) DefineImageOption(image_info,arg,exception);
654               break;
655             }
656           if (IfSetOption)
657             (void) DefineImageOption(image_info,arg,exception);
658           else
659             (void) DeleteImageOption(image_info,arg,exception);
660           break;
661         }
662       if (LocaleCompare("delay",option) == 0)
663         {
664           /* Only used for new images via AcquireImage()
665              FUTURE: Option should also be used for "-morph" (color morphing)
666           */
667           (void) SetImageOption(image_info,option,
668                IfSetOption ? arg : "0");
669           break;
670         }
671       if (LocaleCompare("density",option) == 0)
672         {
673           /* FUTURE: string in image_info - moved into Option ??? */
674           /* Used by both draw_info and in images via SyncImageSettings() */
675           if (IfSetOption)
676             {
677               (void) CloneString(&image_info->density,arg);
678               (void) CloneString(&draw_info->density,arg);
679               (void) SetImageOption(image_info,option,arg);
680               break;
681             }
682           if (image_info->density != (char *) NULL)
683             image_info->density=DestroyString(image_info->density);
684           if (draw_info->density != (char *) NULL)
685             draw_info->density=DestroyString(draw_info->density);
686           (void) SetImageOption(image_info,option,"72");
687           break;
688         }
689       if (LocaleCompare("depth",option) == 0)
690         {
691           /* This is also a SimpleImageOperator! to set depth across images */
692           image_info->depth=IfSetOption?StringToUnsignedLong(arg)
693                                        :MAGICKCORE_QUANTUM_DEPTH;
694           break;
695         }
696       if (LocaleCompare("direction",option) == 0)
697         {
698           /* Image Option is only used to set draw_info */
699           (void) SetImageOption(image_info,option,
700                IfSetOption ? arg : "undefined");
701           draw_info->direction=(DirectionType) ParseCommandOption(
702                          MagickDirectionOptions,MagickFalse,
703                          IfSetOption ? arg : "undefined");
704           break;
705         }
706       if (LocaleCompare("display",option) == 0)
707         {
708           /* FUTURE: string in image_info - moved into Option ??? */
709           (void) CloneString(&image_info->server_name,
710                IfSetOption ? arg :(char *) NULL);
711           break;
712         }
713       if (LocaleCompare("dispose",option) == 0)
714         {
715           (void) SetImageOption(image_info,option,
716                IfSetOption ? arg : "undefined");
717           break;
718         }
719       if (LocaleCompare("dither",option) == 0)
720         {
721           /* FUTURE: merge all options to just Option and quantize_info! */
722           (void) SetImageOption(image_info,option,
723                        IfSetOption ? arg : "none");
724           image_info->dither = quantize_info->dither =
725                     IfSetOption ? MagickTrue : MagickFalse;
726           quantize_info->dither_method=(DitherMethod) ParseCommandOption(
727                     MagickDitherOptions,MagickFalse,
728                     IfSetOption ? arg : "none");
729           if (quantize_info->dither_method == NoDitherMethod)
730                 image_info->dither = quantize_info->dither = MagickFalse;
731           break;
732         }
733       break;
734     }
735     case 'e':
736     {
737       if (LocaleCompare("encoding",option) == 0)
738         {
739           (void) CloneString(&draw_info->encoding,
740                        IfSetOption ? arg : "undefined");
741           (void) SetImageOption(image_info,option,&draw_info->encoding);
742           break;
743         }
744       if (LocaleCompare("endian",option) == 0)
745         {
746           const char
747             value;
748
749           value=IfSetOption?arg:"undefined";
750           (void) SetImageOption(image_info,option,value);
751           image_info->endian=(EndianType) ParseCommandOption(
752               MagickEndianOptions,MagickFalse,value);
753           break;
754         }
755       if (LocaleCompare("extract",option) == 0)
756         {
757           (void) CloneString(&image_info->extract,
758                IfSetOption?arg:(const char *) NULL);
759           break;
760         }
761       break;
762     }
763     case 'f':
764     {
765       if (LocaleCompare("family",argv[0]+1) == 0)
766         {
767           (void) CloneString(&draw_info->family,
768                IfSetOption ? arg : (const char *) NULL);
769           break;
770         }
771       if (LocaleCompare("fill",option) == 0)
772         {
773           /* set fill OR a fill-pattern
774              color is only used by draw_info
775              but draw_info is only initialsed using the color not the pattern
776           */
777           const char
778             value;
779
780           ExceptionInfo
781             *sans;
782
783           value = IfSetOption ? arg : "none";
784           (void) SetImageOption(image_info,option,value);
785
786           sans=AcquireExceptionInfo();
787           status=QueryColorCompliance(value,AllCompliance,&draw_info->fill,sans);
788           sans=DestroyExceptionInfo(sans);
789
790           if (draw_info->fill_pattern != (Image *) NULL)
791             draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
792           if (status == MagickFalse)
793             draw_info->fill_pattern=GetImageCache(image_info,value,
794               exception);
795           break;
796         }
797       if (LocaleCompare("filter",option) == 0)
798         {
799           (void) SetImageOption(image_info,option,
800                 IfSetOption ? arg : "undefined");
801           break;
802         }
803       if (LocaleCompare("font",option) == 0)
804         {
805           (void) CloneString(&draw_info->font,
806                IfSetOption ? arg : (const char *) NULL);
807           (void) CloneString(&image_info->font,draw_info->font);
808           break;
809         }
810       if (LocaleCompare("format",option) == 0)
811         {
812           /* FUTURE: why the ping test, you could set ping after this! */
813           /*
814           register const char
815             *q;
816
817           for (q=strchr(arg,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
818             if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
819               image_info->ping=MagickFalse;
820           */
821           (void) SetImageOption(image_info,option,
822                IfSetOption ? arg : (const char *) NULL);
823           break;
824         }
825       if (LocaleCompare("fuzz",option) == 0)
826         {
827           /* FUTURE: image_info and ImageOption!
828              Option used to set image fuzz! unless blank canvas (from color)
829              Image attribute used for color compare operations
830              image->fuzz is being set by SyncImageSettings()
831              Can't find anything using image_info->fuzz (except cloning)!
832           */
833           if (IfSetOption)
834             {
835               image_info->fuzz=StringToDoubleInterval(arg,(double) QuantumRange+
836                 1.0);
837               (void) SetImageOption(image_info,option,arg);
838               break;
839             }
840           image_info->fuzz=0.0;
841           (void) SetImageOption(image_info,option,"0");
842           break;
843         }
844       break;
845     }
846     case 'g':
847     {
848       if (LocaleCompare("gravity",option) == 0)
849         {
850           /* FUTURE gravity also set in image via SyncImageSettings() */
851           const char
852             value;
853
854           value = IfSetOption ? arg : "none";
855           (void) SetImageOption(image_info,option,value);
856           draw_info->gravity=(GravityType) ParseCommandOption(
857                            MagickGravityOptions,MagickFalse,value);
858           break;
859         }
860       if (LocaleCompare("green-primary",option) == 0)
861         {
862           /* Image chromaticity X,Y  NB: Y=X if Y not defined
863              Used by many coders
864           */
865           (void) SetImageOption(image_info,option,
866                IfSetOption ? arg : "0.0");
867           break;
868         }
869       break;
870     }
871     case 'i':
872     {
873       if (LocaleCompare("intent",option) == 0)
874         {
875           /* FUTURE: sets image->rendering_intent in SyncImagesSettings
876              Which is only used by coders: MIFF, MPC, BMP, PNG
877              and for image profile call to AcquireTransformThreadSet()
878           */
879           (void) SetImageOption(image_info,option,
880                IfSetOption ? arg : "undefined");
881           break;
882         }
883       if (LocaleCompare("interlace",option) == 0)
884         {
885           /* sets image attibute interlace via SyncImageSettings()
886              Also image_info is directly used by coders
887           */
888           const char
889             value;
890
891           value = IfSetOption ? arg : "undefined";
892           (void) SetImageOption(image_info,option, value);
893           image_info->interlace=(InterlaceType) ParseCommandOption(
894             MagickInterlaceOptions,MagickFalse,arg);
895           (void) SetImageOption(image_info,option,arg);
896           break;
897         }
898       if (LocaleCompare("interline-spacing",option) == 0)
899         {
900           const char
901             value;
902
903           value = IfSetOption ? arg : "0"; /* undefined? */
904           (void) SetImageOption(image_info,option, value);
905           draw_info->interline_spacing=StringToDouble(value,(char **) NULL);
906           break;
907         }
908       if (LocaleCompare("interpolate",option) == 0)
909         {
910           /* FUTURE: sets image interpolate value via SyncImageSettings()
911              It is NOT used by coders, only in image processing,
912              so shoud really be a image_info attribute.
913           */
914           (void) SetImageOption(image_info,option,
915                IfSetOption ? arg : "undefined");
916           break;
917         }
918       if (LocaleCompare("interword-spacing",option) == 0)
919         {
920           const char
921             value;
922
923           value = IfSetOption ? arg : "0"; /* undefined? */
924           (void) SetImageOption(image_info,option, value);
925           draw_info->interword_spacing=StringToDouble(value,(char **) NULL);
926           break;
927         }
928       break;
929     }
930     case 'k':
931     {
932       if (LocaleCompare("kerning",option) == 0)
933         {
934           const char
935             value;
936
937           value = IfSetOption ? arg : "0"; /* undefined? */
938           (void) SetImageOption(image_info,option, value);
939           draw_info->kerning=StringToDouble(value,(char **) NULL);
940           break;
941         }
942       break;
943     }
944     case 'l':
945     {
946       if (LocaleCompare("label",option) == 0)
947         {
948           /* only used for new images */
949           (void) SetImageOption(image_info,option,
950                IfSetOption ? arg : (char *)NULL);
951           break;
952         }
953       if (LocaleCompare("limit",option) == 0)
954         {
955           MagickSizeType
956             limit;
957
958           ResourceType
959             type;
960
961           if (!IfSetOption)
962             break;
963           type=(ResourceType) ParseCommandOption(MagickResourceOptions,
964             MagickFalse,arg);
965           limit=MagickResourceInfinity;
966           if (LocaleCompare("unlimited",argv[2]) != 0)
967             limit=(MagickSizeType) SiPrefixToDoubleInterval(argv[2],
968               100.0);
969           (void) SetMagickResourceLimit(type,limit);
970           break;
971         }
972       if (LocaleCompare("list",option) == 0)
973         {
974           ssize_t
975             list;
976
977           list=ParseCommandOption(MagickListOptions,MagickFalse,arg);
978           switch (list)
979           {
980             case MagickCoderOptions:
981             {
982               (void) ListCoderInfo((FILE *) NULL,exception);
983               break;
984             }
985             case MagickColorOptions:
986             {
987               (void) ListColorInfo((FILE *) NULL,exception);
988               break;
989             }
990             case MagickConfigureOptions:
991             {
992               (void) ListConfigureInfo((FILE *) NULL,exception);
993               break;
994             }
995             case MagickDelegateOptions:
996             {
997               (void) ListDelegateInfo((FILE *) NULL,exception);
998               break;
999             }
1000             case MagickFontOptions:
1001             {
1002               (void) ListTypeInfo((FILE *) NULL,exception);
1003               break;
1004             }
1005             case MagickFormatOptions:
1006             {
1007               (void) ListMagickInfo((FILE *) NULL,exception);
1008               break;
1009             }
1010             case MagickLocaleOptions:
1011             {
1012               (void) ListLocaleInfo((FILE *) NULL,exception);
1013               break;
1014             }
1015             case MagickLogOptions:
1016             {
1017               (void) ListLogInfo((FILE *) NULL,exception);
1018               break;
1019             }
1020             case MagickMagicOptions:
1021             {
1022               (void) ListMagicInfo((FILE *) NULL,exception);
1023               break;
1024             }
1025             case MagickMimeOptions:
1026             {
1027               (void) ListMimeInfo((FILE *) NULL,exception);
1028               break;
1029             }
1030             case MagickModuleOptions:
1031             {
1032               (void) ListModuleInfo((FILE *) NULL,exception);
1033               break;
1034             }
1035             case MagickPolicyOptions:
1036             {
1037               (void) ListPolicyInfo((FILE *) NULL,exception);
1038               break;
1039             }
1040             case MagickResourceOptions:
1041             {
1042               (void) ListMagickResourceInfo((FILE *) NULL,exception);
1043               break;
1044             }
1045             case MagickThresholdOptions:
1046             {
1047               (void) ListThresholdMaps((FILE *) NULL,exception);
1048               break;
1049             }
1050             default:
1051             {
1052               (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
1053                 exception);
1054               break;
1055             }
1056           }
1057           break;
1058         }
1059       if (LocaleCompare("log",option) == 0)
1060         {
1061           if (IfSetOption)
1062             (void) SetLogFormat(arg);
1063           break;
1064         }
1065       if (LocaleCompare("loop",option) == 0)
1066         {
1067           /* Sets image attibutes iterations via SyncImageSettings() */
1068           (void) SetImageOption(image_info,option,
1069                IfSetOption ? arg : "0");
1070           break;
1071         }
1072       break;
1073     }
1074     case 'm':
1075     {
1076       if (LocaleCompare("matte",option) == 0)
1077         {
1078           if (*argv[0] == '+')
1079             {
1080               (void) SetImageOption(image_info,option,"false");
1081               break;
1082             }
1083           (void) SetImageOption(image_info,option,"true");
1084           break;
1085         }
1086       if (LocaleCompare("mattecolor",option) == 0)
1087         {
1088           if (*argv[0] == '+')
1089             {
1090               (void) SetImageOption(image_info,option,arg);
1091               (void) QueryColorCompliance(MatteColor,AllCompliance,
1092                 &image_info->matte_color,exception);
1093               break;
1094             }
1095           (void) SetImageOption(image_info,option,arg);
1096           (void) QueryColorCompliance(arg,AllCompliance,&image_info->matte_color,
1097             exception);
1098           break;
1099         }
1100       if (LocaleCompare("monitor",option) == 0)
1101         {
1102           (void) SetImageInfoProgressMonitor(image_info,MonitorProgress,
1103             (void *) NULL);
1104           break;
1105         }
1106       if (LocaleCompare("monochrome",option) == 0)
1107         {
1108           /* Setting (for input coders) and a 'type' operation */
1109           image_info->monochrome=IfSetOption ? MagickTrue : MagickFalse;
1110           break;
1111         }
1112       break;
1113     }
1114     case 'o':
1115     {
1116       if (LocaleCompare("orient",option) == 0)
1117         {
1118           /* Sets image attribute orientation via SyncImageSettings()
1119              Is not used when defining for new images.
1120              This makes it more of a 'operation' than a setting
1121           */
1122           const char
1123             value;
1124
1125           value = IfSetOption ? arg : "undefined";
1126           (void) SetImageOption(image_info,option, value);
1127           image_info->orientation=(InterlaceType) ParseCommandOption(
1128             MagickOrientationOptions,MagickFalse,value);
1129           break;
1130         }
1131     }
1132     case 'p':
1133     {
1134       if (LocaleCompare("page",option) == 0)
1135         {
1136           /* Only used for new images and image generators */
1137           char
1138             *canonical_page,
1139             page[MaxTextExtent];
1140
1141           const char
1142             *image_option;
1143
1144           MagickStatusType
1145             flags;
1146
1147           RectangleInfo
1148             geometry;
1149
1150           if (!IfSetOption)
1151             {
1152               (void) DeleteImageOption(image_info,option);
1153               (void) CloneString(&image_info->page,(char *) NULL);
1154               break;
1155             }
1156           (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1157           image_option=GetImageOption(image_info,"page");
1158           if (image_option != (const char *) NULL)
1159             flags=ParseAbsoluteGeometry(image_option,&geometry);
1160           canonical_page=GetPageGeometry(arg);
1161           flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1162           canonical_page=DestroyString(canonical_page);
1163           (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1164             (unsigned long) geometry.width,(unsigned long) geometry.height);
1165           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1166             (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1167               (unsigned long) geometry.width,(unsigned long) geometry.height,
1168               (long) geometry.x,(long) geometry.y);
1169           (void) SetImageOption(image_info,option,page);
1170           (void) CloneString(&image_info->page,page);
1171           break;
1172         }
1173       if (LocaleCompare("ping",option) == 0)
1174         {
1175           image_info->ping= IfSetOption ? MagickTrue : MagickFalse;
1176           break;
1177         }
1178       if (LocaleCompare("pointsize",option) == 0)
1179         {
1180           double
1181             value=12.0;
1182
1183           if (IfSetOption)
1184             StringToDouble(arg,(char **) NULL);
1185           image_info->pointsize=draw_info->pointsize=value;
1186           break;
1187         }
1188       if (LocaleCompare("precision",option) == 0)
1189         {
1190           (void) SetMagickPrecision(StringToInteger(arg));
1191           break;
1192         }
1193       /* FUTURE: Only the 'preview' coder appears to use this
1194        * Depreciate the coder?  Leaving only the 'preview' operator.
1195       if (LocaleCompare("preview",option) == 0)
1196         {
1197           image_info->preview_type=UndefinedPreview;
1198           if (IfSetOption)
1199             image_info->preview_type=(PreviewType) ParseCommandOption(
1200                 MagickPreviewOptions,MagickFalse,arg);
1201           break;
1202         }
1203       */
1204       break;
1205     }
1206     case 'q':
1207     {
1208       if (LocaleCompare("quality",option) == 0)
1209         {
1210           if (IfSetOption)
1211             {
1212               image_info->quality=StringToUnsignedLong(arg);
1213               (void) SetImageOption(image_info,option,arg);
1214               break;
1215             }
1216           image_info->quality=UndefinedCompressionQuality;
1217           (void) SetImageOption(image_info,option,"0");
1218           break;
1219         }
1220       if (LocaleCompare("quantize",option) == 0)
1221         {
1222           /* no image_info setting!  Only set direct in quantize_info */
1223           quantize_info->colorspace=UndefinedColorspace;
1224           if (IfSetOption)
1225             quantize_info->colorspace=(ColorspaceType) ParseCommandOption(
1226                  MagickColorspaceOptions,MagickFalse,arg);
1227           break;
1228         }
1229       if (LocaleCompare("quiet",option) == 0)
1230         {
1231           /* FUTURE: if two -quiet is performed you can not do +quiet! */
1232           static WarningHandler
1233             warning_handler = (WarningHandler) NULL;
1234           WarningHandler
1235             tmp = SetWarningHandler((WarningHandler) NULL);
1236
1237           if ( tmp != (WarningHandler) NULL)
1238             warning_handler = tmp; /* remember the old handler */
1239           if (!IfSetOption)        /* set the old handler */
1240             warning_handler=SetWarningHandler(warning_handler);
1241           break;
1242         }
1243       break;
1244     }
1245     case 'r':
1246     {
1247       if (LocaleCompare("red-primary",option) == 0)
1248         {
1249           /* Image chromaticity X,Y  NB: Y=X if Y not defined
1250              Used by many coders
1251           */
1252           (void) SetImageOption(image_info,option,
1253                IfSetOption ? arg : "0" );
1254           break;
1255         }
1256       if (LocaleCompare("render",option) == 0)
1257         {
1258           /* draw_info only setting */
1259           draw_info->render= IfSetOption ? MagickFalse : MagickTrue;
1260           break;
1261         }
1262       break;
1263     }
1264     case 's':
1265     {
1266       if (LocaleCompare("sampling-factor",option) == 0)
1267         {
1268           /* FUTURE: should be converted to jpeg:sampling_factor */
1269           (void) CloneString(&image_info->sampling_factor,
1270                IfSetOption ? arg : (char *) NULL);
1271           break;
1272         }
1273       if (LocaleCompare("scene",option) == 0)
1274         {
1275           char
1276             *value = IfSetOption ? arg : "0";
1277
1278           (void) SetImageOption(image_info,option,value);
1279           image_info->scene=StringToUnsignedLong(value);
1280           break;
1281         }
1282       if (LocaleCompare("seed",option) == 0)
1283         {
1284           SeedPseudoRandomGenerator(
1285                IfSetOption ? (size_t) StringToUnsignedLong(arg)
1286                            : (size_t) time((time_t *) NULL) );
1287           break;
1288         }
1289       if (LocaleCompare("size",option) == 0)
1290         {
1291           /* FUTURE: string in image_info -- convert to Option ???
1292              Look at the special handling for "size" in SetImageOption()
1293            */
1294           (void) CloneString(&image_info->size,
1295                IfSetOption ? arg : (char *) NULL);
1296           break;
1297         }
1298       if (LocaleCompare("stretch",option) == 0)
1299         {
1300           draw_info->stretch=UndefinedStretch;
1301           if (IfSetOption)
1302             draw_info->stretch=(StretchType) ParseCommandOption(
1303               MagickStretchOptions,MagickFalse,arg);
1304           break;
1305         }
1306       if (LocaleCompare("stroke",option) == 0)
1307         {
1308           /* set stroke color OR stroke-pattern
1309              color is only used by draw_info
1310              but draw_info is only initialsed using the color not the pattern
1311            */
1312           const char
1313             *value = IfSetOption ? arg : "none";
1314
1315           ExceptionInfo
1316             *sans;
1317
1318           (void) SetImageOption(image_info,option,value);
1319
1320           sans=AcquireExceptionInfo();
1321           status=QueryColorCompliance(value,AllCompliance,&draw_info->stroke,
1322                sans);
1323           sans=DestroyExceptionInfo(sans);
1324
1325           if (draw_info->stroke_pattern != (Image *) NULL)
1326             draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
1327           if (status == MagickFalse)
1328             draw_info->stroke_pattern=GetImageCache(image_info,value,
1329               exception);
1330           break;
1331         }
1332       if (LocaleCompare("strokewidth",option) == 0)
1333         {
1334           const char
1335             *value = IfSetOption ? arg : "1.0";
1336           (void) SetImageOption(image_info,option,value);
1337           draw_info->stroke_width=StringToDouble(value,(char **) NULL);
1338           break;
1339         }
1340       if (LocaleCompare("style",option) == 0)
1341         {
1342           draw_info->style=UndefinedStyle;
1343           if (IfSetOption)
1344             draw_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1345                  MagickFalse,arg);
1346           break;
1347         }
1348       if (LocaleCompare("synchronize",option) == 0)
1349         {
1350           image_info->synchronize=IfSetOption ? MagickTrue : MagickFalse;
1351           break;
1352         }
1353       break;
1354     }
1355     case 't':
1356     {
1357       if (LocaleCompare("taint",option) == 0)
1358         {
1359           (void) SetImageOption(image_info,option,
1360                IfSetOption ? "true" : "false");
1361           break;
1362         }
1363       if (LocaleCompare("texture",option) == 0)
1364         {
1365           /* FUTURE: move image_info string to option splay-tree */
1366           (void) CloneString(&image_info->texture,
1367                IfSetOption ? arg : (char *) NULL);
1368           break;
1369         }
1370       if (LocaleCompare("tile",option) == 0)
1371         {
1372           draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
1373           if (IfSetOption)
1374             draw_info->fill_pattern=GetImageCache(image_info,arg,exception);
1375           break;
1376         }
1377       if (LocaleCompare("tile-offset",option) == 0)
1378         {
1379           (void) SetImageOption(image_info,option,
1380                IfSetOption ? arg : "0");
1381           break;
1382         }
1383       if (LocaleCompare("transparent-color",option) == 0)
1384         {
1385           /* FUTURE: both image_info attribute & ImageOption in use!
1386              image_info only used for generating new images.
1387              Note that +transparent-color, means fall-back to image
1388              attribute so ImageOption is deleted, not set to a default.
1389           */
1390           if (IfSetOption)
1391             {
1392               (void) SetImageOption(image_info,option,arg);
1393               (void) QueryColorCompliance(arg,AllCompliance,
1394                    image_info->transparent_color,exception);
1395               break;
1396             }
1397           (void) DeleteImageOption(image_info,option);
1398           (void) QueryColorCompliance("none",AllCompliance,
1399                image_info->transparent_color,exception);
1400           break;
1401         }
1402       if (LocaleCompare("type",option) == 0)
1403         {
1404           (void) SetImageOption(image_info,option,
1405                IfSetOption ? arg : (char) NULL);
1406           image_info->type=UndefinedType;
1407           if (IfSetOption)
1408             image_info->type=(ImageType) ParseCommandOption(MagickTypeOptions,
1409                  MagickFalse,arg);
1410           break;
1411         }
1412       break;
1413     }
1414     case 'u':
1415     {
1416       if (LocaleCompare("undercolor",option) == 0)
1417         {
1418           (void) SetImageOption(image_info,option,
1419                IfSetOption ? arg : (char) NULL);
1420           (void) QueryColorCompliance(arg,AllCompliance,
1421                draw_info->undercolor,exception);
1422           break;
1423         }
1424       if (LocaleCompare("units",option) == 0)
1425         {
1426           /* Set in images via SyncImageSettings() */
1427           /* Should this effect draw_info X and Y resolution? */
1428           /* FUTURE: this probably should be part of the density setting */
1429           (void) SetImageOption(image_info,option,
1430                IfSetOption ? arg : (char) NULL);
1431           image_info->units=UndefinedResolution;
1432           if (IfSetOption)
1433              image_info->units=(ResolutionType) ParseCommandOption(
1434                   MagickResolutionOptions,MagickFalse,arg);
1435           break;
1436         }
1437       break;
1438     }
1439     case 'v':
1440     {
1441       if (LocaleCompare("verbose",option) == 0)
1442         {
1443           /* FUTURE: Also an image artifact, set in Simple Operators.
1444              But artifact is only used in verbose output.
1445           */
1446           image_info->verbose= IfSetOption ? MagickTrue : MagickFalse;
1447           image_info->ping=MagickFalse; /* verbose can't be a ping */
1448           break;
1449         }
1450       if (LocaleCompare("view",option) == 0)
1451         {
1452           /* FUTURE: Convert from image_info to Option
1453              Only used by coder FPX
1454           */
1455           (void) CloneString(&image_info->view,
1456                IfSetOption ? arg : (char) NULL);
1457           break;
1458         }
1459       if (LocaleCompare("virtual-pixel",option) == 0)
1460         {
1461           /* Also used as a 'image' option deep in image structure */
1462           const char
1463             *value = IfSetOption ? arg : "undefined";
1464
1465           (void) SetImageOption(image_info,option,value);
1466           image_info->virtual_pixel_method=(VirtualPixelMethod)
1467             ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,value);
1468           break;
1469         }
1470       break;
1471     }
1472     case 'w':
1473     {
1474       if (LocaleCompare("weight",option) == 0)
1475         {
1476           /* FUTURE: relative weights not sensical due to first assignment!
1477              Also just what is actually using font 'weight' ???
1478              There is no "-list weight" output (reference manual says there is)
1479           */
1480           draw_info->weight=StringToUnsignedLong(arg);
1481           if (LocaleCompare(arg,"all") == 0)
1482             draw_info->weight=0;
1483           if (LocaleCompare(arg,"bold") == 0)
1484             draw_info->weight=700;
1485           if (LocaleCompare(arg,"bolder") == 0)
1486             if (draw_info->weight <= 800)
1487               draw_info->weight+=100;
1488           if (LocaleCompare(arg,"lighter") == 0)
1489             if (draw_info->weight >= 100)
1490               draw_info->weight-=100;
1491           if (LocaleCompare(arg,"normal") == 0)
1492             draw_info->weight=400;
1493           break;
1494         }
1495       if (LocaleCompare("white-point",option) == 0)
1496         {
1497           /* Used as a image chromaticity setting */
1498           (void) SetImageOption(image_info,option,
1499                IfSetOption ? arg : "0.0" );
1500           break;
1501         }
1502       break;
1503     }
1504     default:
1505       break;
1506   }
1507   return(MagickTrue);
1508 }
1509 \f
1510 /*
1511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 %                                                                             %
1513 %                                                                             %
1514 %                                                                             %
1515 +     A p p l y I m a g e O p e r a t o r                                     %
1516 %                                                                             %
1517 %                                                                             %
1518 %                                                                             %
1519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1520 %
1521 %  ApplyImageOperator() apply one simple image operation to the current
1522 %  image pointed to by the CLI wand, with the settings that are saved in the
1523 %  CLI wand.
1524 %
1525 %  The image in the list may be modified in three different ways...
1526 %
1527 %    * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1528 %    * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1529 %    * replace by a list of images (-separate and -crop only!)
1530 %
1531 %  In each case the result replaces the original image in the list, as well as
1532 %  the pointer to the modified image (last image added if replaced by a list
1533 %  of images) is returned.  As the image pointed to may be replaced, the first
1534 %  image in the list may also change.  GetFirstImageInList() should be used by
1535 %  caller if they wish return the Image pointer to the first image in list.
1536 %
1537 %  It is assumed that any per-image settings are up-to-date with respect to
1538 %  extra settings that have been saved in the wand.
1539 %
1540 %  The format of the ApplyImageOperator method is:
1541 %
1542 %    MagickBooleanType ApplyImageOperator(MagickWand *wand,
1543 %        const char *option, const MagickBooleanType set_option, const char
1544 %        **args, ExceptionInfo *exception)
1545 %
1546 %  A description of each parameter follows:
1547 %
1548 %    o wand: structure holding settings to be applied
1549 %
1550 %    o option: The option string to be set
1551 %
1552 %    o set_option: is the option being set, or reset to some default
1553 %
1554 %    o arg: the single argument (if needed) to set this option.
1555 %
1556 %    o exception: return any errors or warnings in this structure.
1557 %
1558 %
1559 % Example usage (FUTURE)
1560 %
1561 %    argc,argv
1562 %    i=index in argv
1563 %
1564 %    count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
1565 %    flags=GetCommandOptionFlags(MagickCommandOptions,MagickFalse,argv[i]);
1566 %    if ( flags == MagickCommandOptions )
1567 %      ApplySettingsOption(wand, argv[i]+1,
1568 %          (*argv[i])=='-' ? MagickTrue : MagickFalse,
1569 %          argv+i+1, exception);
1570 %    i += count+1;
1571 %
1572 */
1573 WandExport MagickBooleanType ApplySettingsOption(MagickWand *wand,
1574   const char *option, const MagickBooleanType set_option, const char **args,
1575   ExceptionInfo *exception)
1576 {
1577   Image *
1578     new_image;
1579
1580   GeometryInfo
1581     geometry_info;
1582
1583   RectangleInfo
1584     geometry;
1585
1586   MagickStatusType
1587     status;
1588
1589   MagickStatusType
1590     flags;
1591
1592   assert(image_info != (const ImageInfo *) NULL);
1593   assert(image_info->signature == MagickSignature);
1594   assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
1595   assert(image != (Image **) NULL);             /* there is an image */
1596   assert((*image)->signature == MagickSignature);
1597
1598   if (wand->debug != MagickFalse)
1599     (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
1600
1601   SetGeometryInfo(&geometry_info);
1602
1603   new_image = (Image *)NULL; /* the replacement image, if not null at end */
1604
1605   /* We need somthing more optimized than this! */
1606   (void) SyncImageSettings(image_info,*image,exception);
1607
1608   switch (*option)
1609   {
1610     case 'a':
1611     {
1612       if (LocaleCompare("adaptive-blur",option) == 0)
1613         {
1614           flags=ParseGeometry(args[0],&geometry_info);
1615           if ((flags & SigmaValue) == 0)
1616             geometry_info.sigma=1.0;
1617           if ((flags & XiValue) == 0)
1618             geometry_info.xi=0.0;
1619           new_image=AdaptiveBlurImage(*image,geometry_info.rho,
1620             geometry_info.sigma,geometry_info.xi,exception);
1621           break;
1622         }
1623       if (LocaleCompare("adaptive-resize",option) == 0)
1624         {
1625           /* FUTURE: this is really a "interpolate-resize" operator
1626              "adaptive-resize" uses a fixed "Mesh" interpolation
1627           */
1628           (void) ParseRegionGeometry(*image,args[0],&geometry,exception);
1629           new_image=AdaptiveResizeImage(*image,geometry.width,
1630             geometry.height,interpolate_method,exception);
1631           break;
1632         }
1633       if (LocaleCompare("adaptive-sharpen",option) == 0)
1634         {
1635           /*
1636             Adaptive sharpen image.
1637           */
1638           (void) SyncImageSettings(image_info,*image,exception);
1639           flags=ParseGeometry(args[0],&geometry_info);
1640           if ((flags & SigmaValue) == 0)
1641             geometry_info.sigma=1.0;
1642           if ((flags & XiValue) == 0)
1643             geometry_info.xi=0.0;
1644           new_image=AdaptiveSharpenImage(*image,geometry_info.rho,
1645             geometry_info.sigma,geometry_info.xi,exception);
1646           break;
1647         }
1648       if (LocaleCompare("alpha",option) == 0)
1649         {
1650           AlphaChannelType
1651             alpha_type;
1652
1653           (void) SyncImageSettings(image_info,*image,exception);
1654           alpha_type=(AlphaChannelType) ParseCommandOption(MagickAlphaOptions,
1655             MagickFalse,args[0]);
1656           (void) SetImageAlphaChannel(*image,alpha_type,exception);
1657           break;
1658         }
1659       if (LocaleCompare("annotate",option) == 0)
1660         {
1661           char
1662             *text,
1663             geometry[MaxTextExtent];
1664
1665           (void) SyncImageSettings(image_info,*image,exception);
1666           SetGeometryInfo(&geometry_info);
1667           flags=ParseGeometry(args[0],&geometry_info);
1668           if ((flags & SigmaValue) == 0)
1669             geometry_info.sigma=geometry_info.rho;
1670           text=InterpretImageProperties(image_info,*image,argv[2],
1671             exception);
1672           if (text == (char *) NULL)
1673             break;
1674           (void) CloneString(&draw_info->text,text);
1675           text=DestroyString(text);
1676           (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1677             geometry_info.xi,geometry_info.psi);
1678           (void) CloneString(&draw_info->geometry,geometry);
1679           draw_info->affine.sx=cos(DegreesToRadians(
1680             fmod(geometry_info.rho,360.0)));
1681           draw_info->affine.rx=sin(DegreesToRadians(
1682             fmod(geometry_info.rho,360.0)));
1683           draw_info->affine.ry=(-sin(DegreesToRadians(
1684             fmod(geometry_info.sigma,360.0))));
1685           draw_info->affine.sy=cos(DegreesToRadians(
1686             fmod(geometry_info.sigma,360.0)));
1687           (void) AnnotateImage(*image,draw_info,exception);
1688           break;
1689         }
1690       if (LocaleCompare("auto-gamma",option) == 0)
1691         {
1692           /*
1693             Auto Adjust Gamma of image based on its mean
1694           */
1695           (void) SyncImageSettings(image_info,*image,exception);
1696           (void) AutoGammaImage(*image,exception);
1697           break;
1698         }
1699       if (LocaleCompare("auto-level",option) == 0)
1700         {
1701           /*
1702             Perfectly Normalize (max/min stretch) the image
1703           */
1704           (void) SyncImageSettings(image_info,*image,exception);
1705           (void) AutoLevelImage(*image,exception);
1706           break;
1707         }
1708       if (LocaleCompare("auto-orient",option) == 0)
1709         {
1710           (void) SyncImageSettings(image_info,*image,exception);
1711           switch ((*image)->orientation)
1712           {
1713             case TopRightOrientation:
1714             {
1715               new_image=FlopImage(*image,exception);
1716               break;
1717             }
1718             case BottomRightOrientation:
1719             {
1720               new_image=RotateImage(*image,180.0,exception);
1721               break;
1722             }
1723             case BottomLeftOrientation:
1724             {
1725               new_image=FlipImage(*image,exception);
1726               break;
1727             }
1728             case LeftTopOrientation:
1729             {
1730               new_image=TransposeImage(*image,exception);
1731               break;
1732             }
1733             case RightTopOrientation:
1734             {
1735               new_image=RotateImage(*image,90.0,exception);
1736               break;
1737             }
1738             case RightBottomOrientation:
1739             {
1740               new_image=TransverseImage(*image,exception);
1741               break;
1742             }
1743             case LeftBottomOrientation:
1744             {
1745               new_image=RotateImage(*image,270.0,exception);
1746               break;
1747             }
1748             default:
1749               break;
1750           }
1751           if (new_image != (Image *) NULL)
1752             new_image->orientation=TopLeftOrientation;
1753           break;
1754         }
1755       break;
1756     }
1757     case 'b':
1758     {
1759       if (LocaleCompare("black-threshold",option) == 0)
1760         {
1761           (void) SyncImageSettings(image_info,*image,exception);
1762           (void) BlackThresholdImage(*image,args[0],exception);
1763           break;
1764         }
1765       if (LocaleCompare("blue-shift",option) == 0)
1766         {
1767           (void) SyncImageSettings(image_info,*image,exception);
1768           geometry_info.rho=1.5;
1769           if (*argv[0] == '-')
1770             flags=ParseGeometry(args[0],&geometry_info);
1771           new_image=BlueShiftImage(*image,geometry_info.rho,exception);
1772           break;
1773         }
1774       if (LocaleCompare("blur",option) == 0)
1775         {
1776           /* FUTURE: use of "bias" in a blur is non-sensible */
1777           (void) SyncImageSettings(image_info,*image,exception);
1778           flags=ParseGeometry(args[0],&geometry_info);
1779           if ((flags & SigmaValue) == 0)
1780             geometry_info.sigma=1.0;
1781           if ((flags & XiValue) == 0)
1782             geometry_info.xi=0.0;
1783           new_image=BlurImage(*image,geometry_info.rho,
1784             geometry_info.sigma,geometry_info.xi,exception);
1785           break;
1786         }
1787       if (LocaleCompare("border",option) == 0)
1788         {
1789           ComposeOperator
1790             compose;
1791
1792           const char*
1793           const char*
1794             value;
1795
1796           value=GetImageOption(image_info,"compose");
1797           if (value != (const char *) NULL)
1798             compose=(CompositeOperator) ParseCommandOption(
1799                  MagickComposeOptions,MagickFalse,value);
1800           else
1801             compose=OverCompositeOp;  /* use Over not image->compose */
1802
1803           (void) SyncImageSettings(image_info,*image,exception);
1804           flags=ParsePageGeometry(*image,args[0],&geometry,exception);
1805           if ((flags & SigmaValue) == 0)
1806             geometry.height=geometry.width;
1807           new_image=BorderImage(*image,&geometry,compose,exception);
1808           break;
1809         }
1810       if (LocaleCompare("brightness-contrast",option) == 0)
1811         {
1812           double
1813             brightness,
1814             contrast;
1815
1816           GeometryInfo
1817             geometry_info;
1818
1819           MagickStatusType
1820             flags;
1821
1822           (void) SyncImageSettings(image_info,*image,exception);
1823           flags=ParseGeometry(args[0],&geometry_info);
1824           brightness=geometry_info.rho;
1825           contrast=0.0;
1826           if ((flags & SigmaValue) != 0)
1827             contrast=geometry_info.sigma;
1828           (void) BrightnessContrastImage(*image,brightness,contrast,
1829             exception);
1830           break;
1831         }
1832       break;
1833     }
1834     case 'c':
1835     {
1836       if (LocaleCompare("cdl",option) == 0)
1837         {
1838           char
1839             *color_correction_collection;
1840
1841           /*
1842             Color correct with a color decision list.
1843           */
1844           (void) SyncImageSettings(image_info,*image,exception);
1845           color_correction_collection=FileToString(args[0],~0,exception);
1846           if (color_correction_collection == (char *) NULL)
1847             break;
1848           (void) ColorDecisionListImage(*image,color_correction_collection,
1849             exception);
1850           break;
1851         }
1852       if (LocaleCompare("channel",option) == 0)
1853         {
1854           /* The "channel" setting has already been set */
1855           SetPixelChannelMap(*image,image_info->channel);
1856           break;
1857         }
1858       if (LocaleCompare("charcoal",option) == 0)
1859         {
1860           (void) SyncImageSettings(image_info,*image,exception);
1861           flags=ParseGeometry(args[0],&geometry_info);
1862           if ((flags & SigmaValue) == 0)
1863             geometry_info.sigma=1.0;
1864           if ((flags & XiValue) == 0)
1865             geometry_info.xi=1.0;
1866           new_image=CharcoalImage(*image,geometry_info.rho,
1867             geometry_info.sigma,geometry_info.xi,exception);
1868           break;
1869         }
1870       if (LocaleCompare("chop",option) == 0)
1871         {
1872           (void) SyncImageSettings(image_info,*image,exception);
1873           (void) ParseGravityGeometry(*image,args[0],&geometry,exception);
1874           new_image=ChopImage(*image,&geometry,exception);
1875           break;
1876         }
1877       if (LocaleCompare("clamp",option) == 0)
1878         {
1879           (void) SyncImageSettings(image_info,*image,exception);
1880           (void) ClampImage(*image,exception);
1881           break;
1882         }
1883       if (LocaleCompare("clip",option) == 0)
1884         {
1885           (void) SyncImageSettings(image_info,*image,exception);
1886           if (*argv[0] == '+')
1887             {
1888               (void) SetImageClipMask(*image,(Image *) NULL,exception);
1889               break;
1890             }
1891           (void) ClipImage(*image,exception);
1892           break;
1893         }
1894       if (LocaleCompare("clip-mask",option) == 0)
1895         {
1896           CacheView
1897             *mask_view;
1898
1899           Image
1900             *mask_image;
1901
1902           register Quantum
1903             *restrict q;
1904
1905           register ssize_t
1906             x;
1907
1908           ssize_t
1909             y;
1910
1911           (void) SyncImageSettings(image_info,*image,exception);
1912           if (*argv[0] == '+')
1913             {
1914               /* Remove the write mask */
1915               (void) SetImageMask(*image,(Image *) NULL,exception);
1916               break;
1917             }
1918           mask_image=GetImageCache(image_info,args[0],exception);
1919           if (mask_image == (Image *) NULL)
1920             break;
1921           if (SetImageStorageClass(mask_image,DirectClass,exception) == MagickFalse)
1922             return(MagickFalse);
1923           /* create a write mask from clip-mask image */
1924           /* FUTURE: use Alpha operations instead */
1925           mask_view=AcquireCacheView(mask_image);
1926           for (y=0; y < (ssize_t) mask_image->rows; y++)
1927           {
1928             q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1929               exception);
1930             if (q == (Quantum *) NULL)
1931               break;
1932             for (x=0; x < (ssize_t) mask_image->columns; x++)
1933             {
1934               if (mask_image->matte == MagickFalse)
1935                 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
1936               SetPixelRed(mask_image,GetPixelAlpha(mask_image,q),q);
1937               SetPixelGreen(mask_image,GetPixelAlpha(mask_image,q),q);
1938               SetPixelBlue(mask_image,GetPixelAlpha(mask_image,q),q);
1939               q+=GetPixelChannels(mask_image);
1940             }
1941             if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1942               break;
1943           }
1944           /* set the write mask */
1945           mask_view=DestroyCacheView(mask_view);
1946           mask_image->matte=MagickTrue;
1947           (void) SetImageClipMask(*image,mask_image,exception);
1948           mask_image=DestroyImage(mask_image);
1949           break;
1950         }
1951       if (LocaleCompare("clip-path",option) == 0)
1952         {
1953           (void) SyncImageSettings(image_info,*image,exception);
1954           (void) ClipImagePath(*image,args[0],*argv[0] == '-' ? MagickTrue :
1955             MagickFalse,exception);
1956           break;
1957         }
1958       if (LocaleCompare("colorize",option) == 0)
1959         {
1960           (void) SyncImageSettings(image_info,*image,exception);
1961           new_image=ColorizeImage(*image,args[0],draw_info->fill,
1962             exception);
1963           break;
1964         }
1965       if (LocaleCompare("color-matrix",option) == 0)
1966         {
1967           KernelInfo
1968             *kernel;
1969
1970           (void) SyncImageSettings(image_info,*image,exception);
1971           kernel=AcquireKernelInfo(args[0]);
1972           if (kernel == (KernelInfo *) NULL)
1973             break;
1974           new_image=ColorMatrixImage(*image,kernel,exception);
1975           kernel=DestroyKernelInfo(kernel);
1976           break;
1977         }
1978       if (LocaleCompare("colors",option) == 0)
1979         {
1980           /* Reduce the number of colors in the image.  */
1981           (void) SyncImageSettings(image_info,*image,exception);
1982           quantize_info->number_colors=StringToUnsignedLong(args[0]);
1983           if (quantize_info->number_colors == 0)
1984             break;
1985           if (((*image)->storage_class == DirectClass) ||
1986               (*image)->colors > quantize_info->number_colors)
1987             (void) QuantizeImage(quantize_info,*image,exception);
1988           else
1989             (void) CompressImageColormap(*image,exception);
1990           break;
1991         }
1992       if (LocaleCompare("colorspace",option) == 0)
1993         {
1994           /* This is a Image Setting, which should already been set */
1995           /* FUTURE: default colorspace should be sRGB!
1996              Unless some type of 'linear colorspace' mode is set.
1997              Note that +colorspace sets "undefined" or no effect on
1998              new images, but forces images already in memory back to RGB!
1999           */
2000           (void) SyncImageSettings(image_info,*image,exception);
2001           (void) TransformImageColorspace(*image,
2002                     IfSetOption ? image_info->colorspace : RGBColorspace,
2003                     exception);
2004           break;
2005         }
2006       if (LocaleCompare("contrast",option) == 0)
2007         {
2008           (void) SyncImageSettings(image_info,*image,exception);
2009           (void) ContrastImage(*image,(*argv[0] == '-') ? MagickTrue :
2010             MagickFalse,exception);
2011           break;
2012         }
2013       if (LocaleCompare("contrast-stretch",option) == 0)
2014         {
2015           double
2016             black_point,
2017             white_point;
2018
2019           MagickStatusType
2020             flags;
2021
2022           /*
2023             Contrast stretch image.
2024           */
2025           (void) SyncImageSettings(image_info,*image,exception);
2026           flags=ParseGeometry(args[0],&geometry_info);
2027           black_point=geometry_info.rho;
2028           white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2029             black_point;
2030           if ((flags & PercentValue) != 0)
2031             {
2032               black_point*=(double) (*image)->columns*(*image)->rows/100.0;
2033               white_point*=(double) (*image)->columns*(*image)->rows/100.0;
2034             }
2035           white_point=(MagickRealType) (*image)->columns*(*image)->rows-
2036             white_point;
2037           (void) ContrastStretchImage(*image,black_point,white_point,
2038             exception);
2039           break;
2040         }
2041       if (LocaleCompare("convolve",option) == 0)
2042         {
2043           KernelInfo
2044             *kernel_info;
2045
2046           (void) SyncImageSettings(image_info,*image,exception);
2047           kernel_info=AcquireKernelInfo(args[0]);
2048           if (kernel_info == (KernelInfo *) NULL)
2049             break;
2050           kernel_info->bias=(*image)->bias;
2051           new_image=ConvolveImage(*image,kernel_info,exception);
2052           kernel_info=DestroyKernelInfo(kernel_info);
2053           break;
2054         }
2055       if (LocaleCompare("crop",option) == 0)
2056         {
2057           /*
2058             Crop a image to a smaller size
2059           */
2060           (void) SyncImageSettings(image_info,*image,exception);
2061           new_image=CropImageToTiles(*image,args[0],exception);
2062           break;
2063         }
2064       if (LocaleCompare("cycle",option) == 0)
2065         {
2066           /*
2067             Cycle an image colormap.
2068           */
2069           (void) SyncImageSettings(image_info,*image,exception);
2070           (void) CycleColormapImage(*image,(ssize_t) StringToLong(args[0]),
2071             exception);
2072           break;
2073         }
2074       break;
2075     }
2076     case 'd':
2077     {
2078       if (LocaleCompare("decipher",option) == 0)
2079         {
2080           StringInfo
2081             *passkey;
2082
2083           /*
2084             Decipher pixels.
2085           */
2086           (void) SyncImageSettings(image_info,*image,exception);
2087           passkey=FileToStringInfo(args[0],~0,exception);
2088           if (passkey != (StringInfo *) NULL)
2089             {
2090               (void) PasskeyDecipherImage(*image,passkey,exception);
2091               passkey=DestroyStringInfo(passkey);
2092             }
2093           break;
2094         }
2095       if (LocaleCompare("depth",option) == 0)
2096         {
2097           /* The image_info->depth setting has already been set
2098              We just need to apply it to all images in current sequence
2099              WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2100              That is it really is an operation, not a setting! Arrgghhh
2101           */
2102           (void) SyncImageSettings(image_info,*image,exception);
2103           (void) SetImageDepth(*image,image_info->depth);
2104           break;
2105         }
2106       if (LocaleCompare("deskew",option) == 0)
2107         {
2108           double
2109             threshold;
2110
2111           /*
2112             Straighten the image.
2113           */
2114           (void) SyncImageSettings(image_info,*image,exception);
2115           if (*argv[0] == '+')
2116             threshold=40.0*QuantumRange/100.0;
2117           else
2118             threshold=StringToDoubleInterval(args[0],(double) QuantumRange+1.0);
2119           new_image=DeskewImage(*image,threshold,exception);
2120           break;
2121         }
2122       if (LocaleCompare("despeckle",option) == 0)
2123         {
2124           /*
2125             Reduce the speckles within an image.
2126           */
2127           (void) SyncImageSettings(image_info,*image,exception);
2128           new_image=DespeckleImage(*image,exception);
2129           break;
2130         }
2131       if (LocaleCompare("display",option) == 0)
2132         {
2133           (void) CloneString(&draw_info->server_name,args[0]);
2134           break;
2135         }
2136       if (LocaleCompare("distort",option) == 0)
2137         {
2138           char
2139             *args,
2140             token[MaxTextExtent];
2141
2142           const char
2143             *p;
2144
2145           DistortImageMethod
2146             method;
2147
2148           double
2149             *arguments;
2150
2151           register ssize_t
2152             x;
2153
2154           size_t
2155             number_arguments;
2156
2157           /*
2158             Distort image.
2159           */
2160           (void) SyncImageSettings(image_info,*image,exception);
2161           method=(DistortImageMethod) ParseCommandOption(MagickDistortOptions,
2162             MagickFalse,args[0]);
2163           if ( method == ResizeDistortion )
2164             {
2165                /* Special Case - Argument is actually a resize geometry!
2166                ** Convert that to an appropriate distortion argument array.
2167                */
2168                double
2169                  resize_args[2];
2170                (void) ParseRegionGeometry(*image,argv[2],&geometry,
2171                     exception);
2172                resize_args[0]=(double)geometry.width;
2173                resize_args[1]=(double)geometry.height;
2174                new_image=DistortImage(*image,method,(size_t)2,
2175                     resize_args,MagickTrue,exception);
2176                break;
2177             }
2178           args=InterpretImageProperties(image_info,*image,argv[2],
2179             exception);
2180           if (args == (char *) NULL)
2181             break;
2182           p=(char *) args;
2183           for (x=0; *p != '\0'; x++)
2184           {
2185             GetMagickToken(p,&p,token);
2186             if (*token == ',')
2187               GetMagickToken(p,&p,token);
2188           }
2189           number_arguments=(size_t) x;
2190           arguments=(double *) AcquireQuantumMemory(number_arguments,
2191             sizeof(*arguments));
2192           if (arguments == (double *) NULL)
2193             ThrowWandFatalException(ResourceLimitFatalError,
2194               "MemoryAllocationFailed",(*image)->filename);
2195           (void) ResetMagickMemory(arguments,0,number_arguments*
2196             sizeof(*arguments));
2197           p=(char *) args;
2198           for (x=0; (x < (ssize_t) number_arguments) && (*p != '\0'); x++)
2199           {
2200             GetMagickToken(p,&p,token);
2201             if (*token == ',')
2202               GetMagickToken(p,&p,token);
2203             arguments[x]=StringToDouble(token,(char **) NULL);
2204           }
2205           args=DestroyString(args);
2206           new_image=DistortImage(*image,method,number_arguments,arguments,
2207             (*argv[0] == '+') ? MagickTrue : MagickFalse,exception);
2208           arguments=(double *) RelinquishMagickMemory(arguments);
2209           break;
2210         }
2211       if (LocaleCompare("draw",option) == 0)
2212         {
2213           (void) SyncImageSettings(image_info,*image,exception);
2214           (void) CloneString(&draw_info->primitive,args[0]);
2215           (void) DrawImage(*image,draw_info,exception);
2216           break;
2217         }
2218       break;
2219     }
2220     case 'e':
2221     {
2222       if (LocaleCompare("edge",option) == 0)
2223         {
2224           (void) SyncImageSettings(image_info,*image,exception);
2225           flags=ParseGeometry(args[0],&geometry_info);
2226           if ((flags & SigmaValue) == 0)
2227             geometry_info.sigma=1.0;
2228           new_image=EdgeImage(*image,geometry_info.rho,
2229             geometry_info.sigma,exception);
2230           break;
2231         }
2232       if (LocaleCompare("emboss",option) == 0)
2233         {
2234           (void) SyncImageSettings(image_info,*image,exception);
2235           flags=ParseGeometry(args[0],&geometry_info);
2236           if ((flags & SigmaValue) == 0)
2237             geometry_info.sigma=1.0;
2238           new_image=EmbossImage(*image,geometry_info.rho,
2239             geometry_info.sigma,exception);
2240           break;
2241         }
2242       if (LocaleCompare("encipher",option) == 0)
2243         {
2244           StringInfo
2245             *passkey;
2246
2247           (void) SyncImageSettings(image_info,*image,exception);
2248           passkey=FileToStringInfo(args[0],~0,exception);
2249           if (passkey != (StringInfo *) NULL)
2250             {
2251               (void) PasskeyEncipherImage(*image,passkey,exception);
2252               passkey=DestroyStringInfo(passkey);
2253             }
2254           break;
2255         }
2256       if (LocaleCompare("enhance",option) == 0)
2257         {
2258           (void) SyncImageSettings(image_info,*image,exception);
2259           new_image=EnhanceImage(*image,exception);
2260           break;
2261         }
2262       if (LocaleCompare("equalize",option) == 0)
2263         {
2264           (void) SyncImageSettings(image_info,*image,exception);
2265           (void) EqualizeImage(*image,exception);
2266           break;
2267         }
2268       if (LocaleCompare("evaluate",option) == 0)
2269         {
2270           double
2271             constant;
2272
2273           MagickEvaluateOperator
2274             op;
2275
2276           (void) SyncImageSettings(image_info,*image,exception);
2277           op=(MagickEvaluateOperator) ParseCommandOption(
2278             MagickEvaluateOptions,MagickFalse,args[0]);
2279           constant=StringToDoubleInterval(argv[2],(double) QuantumRange+1.0);
2280           (void) EvaluateImage(*image,op,constant,exception);
2281           break;
2282         }
2283       if (LocaleCompare("extent",option) == 0)
2284         {
2285           (void) SyncImageSettings(image_info,*image,exception);
2286           flags=ParseGravityGeometry(*image,args[0],&geometry,exception);
2287           if (geometry.width == 0)
2288             geometry.width=(*image)->columns;
2289           if (geometry.height == 0)
2290             geometry.height=(*image)->rows;
2291           new_image=ExtentImage(*image,&geometry,exception);
2292           break;
2293         }
2294       break;
2295     }
2296     case 'f':
2297     {
2298       if (LocaleCompare("features",option) == 0)
2299         {
2300           /* FUTURE: Assign Artifact to all images -- per image setting */
2301           (void) SetImageArtifact(*image,"identify:features",
2302               IfSetOption ? args[0] : (const char *) NULL);
2303           break;
2304         }
2305       if (LocaleCompare("flip",option) == 0)
2306         {
2307           /*
2308             Flip image scanlines.
2309           */
2310           (void) SyncImageSettings(image_info,*image,exception);
2311           new_image=FlipImage(*image,exception);
2312           break;
2313         }
2314       if (LocaleCompare("flop",option) == 0)
2315         {
2316           /*
2317             Flop image scanlines.
2318           */
2319           (void) SyncImageSettings(image_info,*image,exception);
2320           new_image=FlopImage(*image,exception);
2321           break;
2322         }
2323       if (LocaleCompare("floodfill",option) == 0)
2324         {
2325           PixelInfo
2326             target;
2327
2328           /*
2329             Floodfill image.
2330           */
2331           (void) SyncImageSettings(image_info,*image,exception);
2332           (void) ParsePageGeometry(*image,args[0],&geometry,exception);
2333           (void) QueryColorCompliance(argv[2],AllCompliance,&target,
2334                         exception);
2335           (void) FloodfillPaintImage(*image,draw_info,&target,geometry.x,
2336             geometry.y,*argv[0] == '-' ? MagickFalse : MagickTrue,exception);
2337           break;
2338         }
2339       /* FUTURE: should be from  ImageOption "format"
2340       if (LocaleCompare("format",option) == 0)
2341         {
2342           format=args[0];
2343           break;
2344         }
2345       */
2346       if (LocaleCompare("frame",option) == 0)
2347         {
2348           FrameInfo
2349             frame_info;
2350
2351           /*
2352             Surround image with an ornamental border.
2353           */
2354           (void) SyncImageSettings(image_info,*image,exception);
2355           flags=ParsePageGeometry(*image,args[0],&geometry,exception);
2356           frame_info.width=geometry.width;
2357           frame_info.height=geometry.height;
2358           if ((flags & HeightValue) == 0)
2359             frame_info.height=geometry.width;
2360           frame_info.outer_bevel=geometry.x;
2361           frame_info.inner_bevel=geometry.y;
2362           frame_info.x=(ssize_t) frame_info.width;
2363           frame_info.y=(ssize_t) frame_info.height;
2364           frame_info.width=(*image)->columns+2*frame_info.width;
2365           frame_info.height=(*image)->rows+2*frame_info.height;
2366           new_image=FrameImage(*image,&frame_info,COMPOSE,exception);
2367           break;
2368         }
2369       if (LocaleCompare("function",option) == 0)
2370         {
2371           char
2372             *arguments,
2373             token[MaxTextExtent];
2374
2375           const char
2376             *p;
2377
2378           double
2379             *parameters;
2380
2381           MagickFunction
2382             function;
2383
2384           register ssize_t
2385             x;
2386
2387           size_t
2388             number_parameters;
2389
2390           /*
2391             Function Modify Image Values
2392           */
2393           (void) SyncImageSettings(image_info,*image,exception);
2394           function=(MagickFunction) ParseCommandOption(MagickFunctionOptions,
2395             MagickFalse,args[0]);
2396           arguments=InterpretImageProperties(image_info,*image,argv[2],
2397             exception);
2398           if (arguments == (char *) NULL)
2399             break;
2400           p=(char *) arguments;
2401           for (x=0; *p != '\0'; x++)
2402           {
2403             GetMagickToken(p,&p,token);
2404             if (*token == ',')
2405               GetMagickToken(p,&p,token);
2406           }
2407           number_parameters=(size_t) x;
2408           parameters=(double *) AcquireQuantumMemory(number_parameters,
2409             sizeof(*parameters));
2410           if (parameters == (double *) NULL)
2411             ThrowWandFatalException(ResourceLimitFatalError,
2412               "MemoryAllocationFailed",(*image)->filename);
2413           (void) ResetMagickMemory(parameters,0,number_parameters*
2414             sizeof(*parameters));
2415           p=(char *) arguments;
2416           for (x=0; (x < (ssize_t) number_parameters) && (*p != '\0'); x++)
2417           {
2418             GetMagickToken(p,&p,token);
2419             if (*token == ',')
2420               GetMagickToken(p,&p,token);
2421             parameters[x]=StringToDouble(token,(char **) NULL);
2422           }
2423           arguments=DestroyString(arguments);
2424           (void) FunctionImage(*image,function,number_parameters,parameters,
2425             exception);
2426           parameters=(double *) RelinquishMagickMemory(parameters);
2427           break;
2428         }
2429       break;
2430     }
2431     case 'g':
2432     {
2433       if (LocaleCompare("gamma",option) == 0)
2434         {
2435           (void) SyncImageSettings(image_info,*image,exception);
2436           if (*argv[0] == '+')
2437             (*image)->gamma=StringToDouble(args[0],(char **) NULL);
2438           else
2439             (void) GammaImage(*image,StringToDouble(args[0],
2440               (char **) NULL),exception);
2441           break;
2442         }
2443       if ((LocaleCompare("gaussian-blur",option) == 0) ||
2444           (LocaleCompare("gaussian",option) == 0))
2445         {
2446           (void) SyncImageSettings(image_info,*image,exception);
2447           flags=ParseGeometry(args[0],&geometry_info);
2448           if ((flags & SigmaValue) == 0)
2449             geometry_info.sigma=1.0;
2450           if ((flags & XiValue) == 0)
2451             geometry_info.xi=0.0;
2452           new_image=GaussianBlurImage(*image,geometry_info.rho,
2453             geometry_info.sigma,geometry_info.xi,exception);
2454           break;
2455         }
2456       if (LocaleCompare("geometry",option) == 0)
2457         {
2458             /*
2459               Record Image offset for composition,
2460               Resize last image. -- FUTURE depreciate this aspect
2461             */
2462           (void) SyncImageSettings(image_info,*image,exception);
2463           if (*argv[0] == '+')
2464             {
2465               if ((*image)->geometry != (char *) NULL)
2466                 (*image)->geometry=DestroyString((*image)->geometry);
2467               break;
2468             }
2469           flags=ParseRegionGeometry(*image,args[0],&geometry,exception);
2470           if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2471             (void) CloneString(&(*image)->geometry,args[0]);
2472           else
2473             new_image=ResizeImage(*image,geometry.width,geometry.height,
2474               (*image)->filter,(*image)->blur,exception);
2475           break;
2476         }
2477       break;
2478     }
2479     case 'h':
2480     {
2481       if (LocaleCompare("highlight-color",option) == 0)
2482         {
2483           (void) SetImageArtifact(*image,option,args[0]);
2484           break;
2485         }
2486       break;
2487     }
2488     case 'i':
2489     {
2490       if (LocaleCompare("identify",option) == 0)
2491         {
2492           char
2493             *text;
2494
2495           (void) SyncImageSettings(image_info,*image,exception);
2496           if (format == (char *) NULL)
2497             {
2498               (void) IdentifyImage(*image,stdout,image_info->verbose,
2499                 exception);
2500               break;
2501             }
2502           text=InterpretImageProperties(image_info,*image,format,
2503             exception);
2504           if (text == (char *) NULL)
2505             break;
2506           (void) fputs(text,stdout);
2507           (void) fputc('\n',stdout);
2508           text=DestroyString(text);
2509           break;
2510         }
2511       if (LocaleCompare("implode",option) == 0)
2512         {
2513           /*
2514             Implode image.
2515           */
2516           (void) SyncImageSettings(image_info,*image,exception);
2517           (void) ParseGeometry(args[0],&geometry_info);
2518           new_image=ImplodeImage(*image,geometry_info.rho,
2519             interpolate_method,exception);
2520           break;
2521         }
2522       if (LocaleCompare("interline-spacing",option) == 0)
2523         {
2524           if (*argv[0] == '+')
2525             (void) ParseGeometry("0",&geometry_info);
2526           else
2527             (void) ParseGeometry(args[0],&geometry_info);
2528           draw_info->interline_spacing=geometry_info.rho;
2529           break;
2530         }
2531       if (LocaleCompare("interpolate",option) == 0)
2532         {
2533           interpolate_method=(PixelInterpolateMethod) ParseCommandOption(
2534             MagickInterpolateOptions,MagickFalse,args[0]);
2535           break;
2536         }
2537       if (LocaleCompare("interword-spacing",option) == 0)
2538         {
2539           if (*argv[0] == '+')
2540             (void) ParseGeometry("0",&geometry_info);
2541           else
2542             (void) ParseGeometry(args[0],&geometry_info);
2543           draw_info->interword_spacing=geometry_info.rho;
2544           break;
2545         }
2546       break;
2547     }
2548     case 'k':
2549     {
2550       if (LocaleCompare("kerning",option) == 0)
2551         {
2552           if (*argv[0] == '+')
2553             (void) ParseGeometry("0",&geometry_info);
2554           else
2555             (void) ParseGeometry(args[0],&geometry_info);
2556           draw_info->kerning=geometry_info.rho;
2557           break;
2558         }
2559       break;
2560     }
2561     case 'l':
2562     {
2563       if (LocaleCompare("lat",option) == 0)
2564         {
2565           /*
2566             Local adaptive threshold image.
2567           */
2568           (void) SyncImageSettings(image_info,*image,exception);
2569           flags=ParseGeometry(args[0],&geometry_info);
2570           if ((flags & PercentValue) != 0)
2571             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2572           new_image=AdaptiveThresholdImage(*image,(size_t)
2573             geometry_info.rho,(size_t) geometry_info.sigma,(double)
2574             geometry_info.xi,exception);
2575           break;
2576         }
2577       if (LocaleCompare("level",option) == 0)
2578         {
2579           MagickRealType
2580             black_point,
2581             gamma,
2582             white_point;
2583
2584           MagickStatusType
2585             flags;
2586
2587           /*
2588             Parse levels.
2589           */
2590           (void) SyncImageSettings(image_info,*image,exception);
2591           flags=ParseGeometry(args[0],&geometry_info);
2592           black_point=geometry_info.rho;
2593           white_point=(MagickRealType) QuantumRange;
2594           if ((flags & SigmaValue) != 0)
2595             white_point=geometry_info.sigma;
2596           gamma=1.0;
2597           if ((flags & XiValue) != 0)
2598             gamma=geometry_info.xi;
2599           if ((flags & PercentValue) != 0)
2600             {
2601               black_point*=(MagickRealType) (QuantumRange/100.0);
2602               white_point*=(MagickRealType) (QuantumRange/100.0);
2603             }
2604           if ((flags & SigmaValue) == 0)
2605             white_point=(MagickRealType) QuantumRange-black_point;
2606           if ((*argv[0] == '+') || ((flags & AspectValue) != 0))
2607             (void) LevelizeImage(*image,black_point,white_point,gamma,
2608               exception);
2609           else
2610             (void) LevelImage(*image,black_point,white_point,gamma,
2611               exception);
2612           break;
2613         }
2614       if (LocaleCompare("level-colors",option) == 0)
2615         {
2616           char
2617             token[MaxTextExtent];
2618
2619           const char
2620             *p;
2621
2622           PixelInfo
2623             black_point,
2624             white_point;
2625
2626           p=(const char *) args[0];
2627           GetMagickToken(p,&p,token);  /* get black point color */
2628           if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2629             (void) QueryColorCompliance(token,AllCompliance,
2630                       &black_point,exception);
2631           else
2632             (void) QueryColorCompliance("#000000",AllCompliance,
2633                       &black_point,exception);
2634           if (isalpha((int) token[0]) || (token[0] == '#'))
2635             GetMagickToken(p,&p,token);
2636           if (*token == '\0')
2637             white_point=black_point; /* set everything to that color */
2638           else
2639             {
2640               if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2641                 GetMagickToken(p,&p,token); /* Get white point color. */
2642               if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
2643                 (void) QueryColorCompliance(token,AllCompliance,
2644                            &white_point,exception);
2645               else
2646                 (void) QueryColorCompliance("#ffffff",AllCompliance,
2647                            &white_point,exception);
2648             }
2649           (void) LevelImageColors(*image,&black_point,&white_point,
2650             *argv[0] == '+' ? MagickTrue : MagickFalse,exception);
2651           break;
2652         }
2653       if (LocaleCompare("linear-stretch",option) == 0)
2654         {
2655           double
2656             black_point,
2657             white_point;
2658
2659           MagickStatusType
2660             flags;
2661
2662           (void) SyncImageSettings(image_info,*image,exception);
2663           flags=ParseGeometry(args[0],&geometry_info);
2664           black_point=geometry_info.rho;
2665           white_point=(MagickRealType) (*image)->columns*(*image)->rows;
2666           if ((flags & SigmaValue) != 0)
2667             white_point=geometry_info.sigma;
2668           if ((flags & PercentValue) != 0)
2669             {
2670               black_point*=(double) (*image)->columns*(*image)->rows/100.0;
2671               white_point*=(double) (*image)->columns*(*image)->rows/100.0;
2672             }
2673           if ((flags & SigmaValue) == 0)
2674             white_point=(MagickRealType) (*image)->columns*(*image)->rows-
2675               black_point;
2676           (void) LinearStretchImage(*image,black_point,white_point,exception);
2677           break;
2678         }
2679       if (LocaleCompare("linewidth",option) == 0)
2680         {
2681           draw_info->stroke_width=StringToDouble(args[0],
2682             (char **) NULL);
2683           break;
2684         }
2685       if (LocaleCompare("liquid-rescale",option) == 0)
2686         {
2687           /*
2688             Liquid rescale image.
2689           */
2690           (void) SyncImageSettings(image_info,*image,exception);
2691           flags=ParseRegionGeometry(*image,args[0],&geometry,exception);
2692           if ((flags & XValue) == 0)
2693             geometry.x=1;
2694           if ((flags & YValue) == 0)
2695             geometry.y=0;
2696           new_image=LiquidRescaleImage(*image,geometry.width,
2697             geometry.height,1.0*geometry.x,1.0*geometry.y,exception);
2698           break;
2699         }
2700       if (LocaleCompare("lowlight-color",option) == 0)
2701         {
2702           (void) SetImageArtifact(*image,option,args[0]);
2703           break;
2704         }
2705       break;
2706     }
2707     case 'm':
2708     {
2709       if (LocaleCompare("map",option) == 0)
2710         {
2711           Image
2712             *remap_image;
2713
2714           /*
2715             Transform image colors to match this set of colors.
2716           */
2717           (void) SyncImageSettings(image_info,*image,exception);
2718           if (*argv[0] == '+')
2719             break;
2720           remap_image=GetImageCache(image_info,args[0],exception);
2721           if (remap_image == (Image *) NULL)
2722             break;
2723           (void) RemapImage(quantize_info,*image,remap_image,exception);
2724           remap_image=DestroyImage(remap_image);
2725           break;
2726         }
2727       if (LocaleCompare("mask",option) == 0)
2728         {
2729           Image
2730             *mask;
2731
2732           (void) SyncImageSettings(image_info,*image,exception);
2733           if (*argv[0] == '+')
2734             {
2735               /*
2736                 Remove a mask.
2737               */
2738               (void) SetImageMask(*image,(Image *) NULL,exception);
2739               break;
2740             }
2741           /*
2742             Set the image mask.
2743           */
2744           mask=GetImageCache(image_info,args[0],exception);
2745           if (mask == (Image *) NULL)
2746             break;
2747           (void) SetImageMask(*image,mask,exception);
2748           mask=DestroyImage(mask);
2749           break;
2750         }
2751       if (LocaleCompare("matte",option) == 0)
2752         {
2753           (void) SetImageAlphaChannel(*image,(*argv[0] == '-') ?
2754             SetAlphaChannel : DeactivateAlphaChannel,exception);
2755           break;
2756         }
2757       if (LocaleCompare("median",option) == 0)
2758         {
2759           /*
2760             Median filter image.
2761           */
2762           (void) SyncImageSettings(image_info,*image,exception);
2763           flags=ParseGeometry(args[0],&geometry_info);
2764           if ((flags & SigmaValue) == 0)
2765             geometry_info.sigma=geometry_info.rho;
2766           new_image=StatisticImage(*image,MedianStatistic,(size_t)
2767             geometry_info.rho,(size_t) geometry_info.sigma,exception);
2768           break;
2769         }
2770       if (LocaleCompare("mode",option) == 0)
2771         {
2772           /*
2773             Mode image.
2774           */
2775           (void) SyncImageSettings(image_info,*image,exception);
2776           flags=ParseGeometry(args[0],&geometry_info);
2777           if ((flags & SigmaValue) == 0)
2778             geometry_info.sigma=geometry_info.rho;
2779           new_image=StatisticImage(*image,ModeStatistic,(size_t)
2780             geometry_info.rho,(size_t) geometry_info.sigma,exception);
2781           break;
2782         }
2783       if (LocaleCompare("modulate",option) == 0)
2784         {
2785           (void) SyncImageSettings(image_info,*image,exception);
2786           (void) ModulateImage(*image,args[0],exception);
2787           break;
2788         }
2789       if (LocaleCompare("monitor",option) == 0)
2790         {
2791           /* FUTURE: Why is this a per-image setting? */
2792           if (*argv[0] == '+')
2793             {
2794               (void) SetImageProgressMonitor(*image,
2795                 (MagickProgressMonitor) NULL,(void *) NULL);
2796               break;
2797             }
2798           (void) SetImageProgressMonitor(*image,MonitorProgress,
2799             (void *) NULL);
2800           break;
2801         }
2802       if (LocaleCompare("monochrome",option) == 0)
2803         {
2804           (void) SyncImageSettings(image_info,*image,exception);
2805           (void) SetImageType(*image,BilevelType,exception);
2806           break;
2807         }
2808       if (LocaleCompare("morphology",option) == 0)
2809         {
2810           char
2811             token[MaxTextExtent];
2812
2813           const char
2814             *p;
2815
2816           KernelInfo
2817             *kernel;
2818
2819           MorphologyMethod
2820             method;
2821
2822           ssize_t
2823             iterations;
2824
2825           (void) SyncImageSettings(image_info,*image,exception);
2826           p=args[0];
2827           GetMagickToken(p,&p,token);
2828           method=(MorphologyMethod) ParseCommandOption(
2829             MagickMorphologyOptions,MagickFalse,token);
2830           iterations=1L;
2831           GetMagickToken(p,&p,token);
2832           if ((*p == ':') || (*p == ','))
2833             GetMagickToken(p,&p,token);
2834           if ((*p != '\0'))
2835             iterations=(ssize_t) StringToLong(p);
2836           kernel=AcquireKernelInfo(argv[2]);
2837           if (kernel == (KernelInfo *) NULL)
2838             {
2839               (void) ThrowMagickException(exception,GetMagickModule(),
2840                 OptionError,"UnabletoParseKernel","morphology");
2841               status=MagickFalse;
2842               break;
2843             }
2844           new_image=MorphologyImage(*image,method,iterations,kernel,
2845             exception);
2846           kernel=DestroyKernelInfo(kernel);
2847           break;
2848         }
2849       if (LocaleCompare("motion-blur",option) == 0)
2850         {
2851           /*
2852             Motion blur image.
2853           */
2854           (void) SyncImageSettings(image_info,*image,exception);
2855           flags=ParseGeometry(args[0],&geometry_info);
2856           if ((flags & SigmaValue) == 0)
2857             geometry_info.sigma=1.0;
2858           new_image=MotionBlurImage(*image,geometry_info.rho,
2859             geometry_info.sigma,geometry_info.xi,geometry_info.psi,
2860             exception);
2861           break;
2862         }
2863       break;
2864     }
2865     case 'n':
2866     {
2867       if (LocaleCompare("negate",option) == 0)
2868         {
2869           (void) SyncImageSettings(image_info,*image,exception);
2870           (void) NegateImage(*image,*argv[0] == '+' ? MagickTrue :
2871             MagickFalse,exception);
2872           break;
2873         }
2874       if (LocaleCompare("noise",option) == 0)
2875         {
2876           (void) SyncImageSettings(image_info,*image,exception);
2877           if (*argv[0] == '-')
2878             {
2879               flags=ParseGeometry(args[0],&geometry_info);
2880               if ((flags & SigmaValue) == 0)
2881                 geometry_info.sigma=geometry_info.rho;
2882               new_image=StatisticImage(*image,NonpeakStatistic,(size_t)
2883                 geometry_info.rho,(size_t) geometry_info.sigma,exception);
2884             }
2885           else
2886             {
2887               NoiseType
2888                 noise;
2889
2890               noise=(NoiseType) ParseCommandOption(MagickNoiseOptions,
2891                 MagickFalse,args[0]);
2892               new_image=AddNoiseImage(*image,noise,exception);
2893             }
2894           break;
2895         }
2896       if (LocaleCompare("normalize",option) == 0)
2897         {
2898           (void) SyncImageSettings(image_info,*image,exception);
2899           (void) NormalizeImage(*image,exception);
2900           break;
2901         }
2902       break;
2903     }
2904     case 'o':
2905     {
2906       if (LocaleCompare("opaque",option) == 0)
2907         {
2908           PixelInfo
2909             target;
2910
2911           (void) SyncImageSettings(image_info,*image,exception);
2912           (void) QueryColorCompliance(args[0],AllCompliance,&target,
2913                        exception);
2914           (void) OpaquePaintImage(*image,&target,&fill,*argv[0] == '-' ?
2915             MagickFalse : MagickTrue,exception);
2916           break;
2917         }
2918       if (LocaleCompare("ordered-dither",option) == 0)
2919         {
2920           (void) SyncImageSettings(image_info,*image,exception);
2921           (void) OrderedPosterizeImage(*image,args[0],exception);
2922           break;
2923         }
2924       break;
2925     }
2926     case 'p':
2927     {
2928       if (LocaleCompare("paint",option) == 0)
2929         {
2930           (void) SyncImageSettings(image_info,*image,exception);
2931           (void) ParseGeometry(args[0],&geometry_info);
2932           new_image=OilPaintImage(*image,geometry_info.rho,
2933             geometry_info.sigma,exception);
2934           break;
2935         }
2936       if (LocaleCompare("polaroid",option) == 0)
2937         {
2938           const char
2939             *caption;
2940
2941           double
2942             angle;
2943
2944           RandomInfo
2945             *random_info;
2946
2947           /*
2948             Simulate a Polaroid picture.
2949           */
2950           (void) SyncImageSettings(image_info,*image,exception);
2951           random_info=AcquireRandomInfo();
2952           angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2953           random_info=DestroyRandomInfo(random_info);
2954           if (*argv[0] == '-')
2955             {
2956               SetGeometryInfo(&geometry_info);
2957               flags=ParseGeometry(args[0],&geometry_info);
2958               angle=geometry_info.rho;
2959             }
2960           caption=GetImageProperty(*image,"caption",exception);
2961           new_image=PolaroidImage(*image,draw_info,caption,angle,
2962             interpolate_method,exception);
2963           break;
2964         }
2965       if (LocaleCompare("posterize",option) == 0)
2966         {
2967           /*
2968             Posterize image.
2969           */
2970           (void) SyncImageSettings(image_info,*image,exception);
2971           (void) PosterizeImage(*image,StringToUnsignedLong(args[0]),
2972             quantize_info->dither,exception);
2973           break;
2974         }
2975       if (LocaleCompare("preview",option) == 0)
2976         {
2977           PreviewType
2978             preview_type;
2979
2980           /*
2981             Preview image.
2982           */
2983           (void) SyncImageSettings(image_info,*image,exception);
2984           if (*argv[0] == '+')
2985             preview_type=UndefinedPreview;
2986           else
2987             preview_type=(PreviewType) ParseCommandOption(
2988               MagickPreviewOptions,MagickFalse,args[0]);
2989           new_image=PreviewImage(*image,preview_type,exception);
2990           break;
2991         }
2992       if (LocaleCompare("profile",option) == 0)
2993         {
2994           const char
2995             *name;
2996
2997           const StringInfo
2998             *profile;
2999
3000           Image
3001             *profile_image;
3002
3003           ImageInfo
3004             *profile_info;
3005
3006           (void) SyncImageSettings(image_info,*image,exception);
3007           if (*argv[0] == '+')
3008             {
3009               /*
3010                 Remove a profile from the image.
3011               */
3012               (void) ProfileImage(*image,args[0],(const unsigned char *)
3013                 NULL,0,exception);
3014               break;
3015             }
3016           /*
3017             Associate a profile with the image.
3018           */
3019           profile_info=CloneImageInfo(image_info);
3020           profile=GetImageProfile(*image,"iptc");
3021           if (profile != (StringInfo *) NULL)
3022             profile_info->profile=(void *) CloneStringInfo(profile);
3023           profile_image=GetImageCache(profile_info,args[0],exception);
3024           profile_info=DestroyImageInfo(profile_info);
3025           if (profile_image == (Image *) NULL)
3026             {
3027               StringInfo
3028                 *profile;
3029
3030               profile_info=CloneImageInfo(image_info);
3031               (void) CopyMagickString(profile_info->filename,args[0],
3032                 MaxTextExtent);
3033               profile=FileToStringInfo(profile_info->filename,~0UL,exception);
3034               if (profile != (StringInfo *) NULL)
3035                 {
3036                   (void) ProfileImage(*image,profile_info->magick,
3037                     GetStringInfoDatum(profile),(size_t)
3038                     GetStringInfoLength(profile),exception);
3039                   profile=DestroyStringInfo(profile);
3040                 }
3041               profile_info=DestroyImageInfo(profile_info);
3042               break;
3043             }
3044           ResetImageProfileIterator(profile_image);
3045           name=GetNextImageProfile(profile_image);
3046           while (name != (const char *) NULL)
3047           {
3048             profile=GetImageProfile(profile_image,name);
3049             if (profile != (StringInfo *) NULL)
3050               (void) ProfileImage(*image,name,GetStringInfoDatum(profile),
3051                 (size_t) GetStringInfoLength(profile),exception);
3052             name=GetNextImageProfile(profile_image);
3053           }
3054           profile_image=DestroyImage(profile_image);
3055           break;
3056         }
3057       break;
3058     }
3059     case 'q':
3060     {
3061       if (LocaleCompare("quantize",option) == 0)
3062         {
3063           if (*argv[0] == '+')
3064             {
3065               quantize_info->colorspace=UndefinedColorspace;
3066               break;
3067             }
3068           quantize_info->colorspace=(ColorspaceType) ParseCommandOption(
3069             MagickColorspaceOptions,MagickFalse,args[0]);
3070           break;
3071         }
3072       break;
3073     }
3074     case 'r':
3075     {
3076       if (LocaleCompare("radial-blur",option) == 0)
3077         {
3078           (void) SyncImageSettings(image_info,*image,exception);
3079           flags=ParseGeometry(args[0],&geometry_info);
3080           new_image=RadialBlurImage(*image,geometry_info.rho,
3081             geometry_info.sigma,exception);
3082           break;
3083         }
3084       if (LocaleCompare("raise",option) == 0)
3085         {
3086           flags=ParsePageGeometry(*image,args[0],&geometry,exception);
3087           if ((flags & SigmaValue) == 0)
3088             geometry.height=geometry.width;
3089           (void) RaiseImage(*image,&geometry,*argv[0] == '-' ? MagickTrue :
3090             MagickFalse,exception);
3091           break;
3092         }
3093       if (LocaleCompare("random-threshold",option) == 0)
3094         {
3095           (void) SyncImageSettings(image_info,*image,exception);
3096           (void) RandomThresholdImage(*image,args[0],exception);
3097           break;
3098         }
3099       if (LocaleCompare("recolor",option) == 0)
3100         {
3101           KernelInfo
3102             *kernel;
3103
3104           (void) SyncImageSettings(image_info,*image,exception);
3105           kernel=AcquireKernelInfo(args[0]);
3106           if (kernel == (KernelInfo *) NULL)
3107             break;
3108           new_image=ColorMatrixImage(*image,kernel,exception);
3109           kernel=DestroyKernelInfo(kernel);
3110           break;
3111         }
3112       if (LocaleCompare("remap",option) == 0)
3113         {
3114           Image
3115             *remap_image;
3116
3117           (void) SyncImageSettings(image_info,*image,exception);
3118           if (*argv[0] == '+')
3119             break;
3120           remap_image=GetImageCache(image_info,args[0],exception);
3121           if (remap_image == (Image *) NULL)
3122             break;
3123           (void) RemapImage(quantize_info,*image,remap_image,exception);
3124           remap_image=DestroyImage(remap_image);
3125           break;
3126         }
3127       if (LocaleCompare("repage",option) == 0)
3128         {
3129           if (*argv[0] == '+')
3130             {
3131               (void) ParseAbsoluteGeometry("0x0+0+0",&(*image)->page);
3132               break;
3133             }
3134           (void) ResetImagePage(*image,args[0]);
3135           break;
3136         }
3137       if (LocaleCompare("resample",option) == 0)
3138         {
3139           /* FUTURE: remove blur - no longer used */
3140           (void) SyncImageSettings(image_info,*image,exception);
3141           flags=ParseGeometry(args[0],&geometry_info);
3142           if ((flags & SigmaValue) == 0)
3143             geometry_info.sigma=geometry_info.rho;
3144           new_image=ResampleImage(*image,geometry_info.rho,
3145             geometry_info.sigma,(*image)->filter,(*image)->blur,exception);
3146           break;
3147         }
3148       if (LocaleCompare("resize",option) == 0)
3149         {
3150           /* FUTURE: remove blur argument - no longer used */
3151           (void) SyncImageSettings(image_info,*image,exception);
3152           (void) ParseRegionGeometry(*image,args[0],&geometry,exception);
3153           new_image=ResizeImage(*image,geometry.width,geometry.height,
3154             (*image)->filter,(*image)->blur,exception);
3155           break;
3156         }
3157       if (LocaleCompare("roll",option) == 0)
3158         {
3159           (void) SyncImageSettings(image_info,*image,exception);
3160           (void) ParsePageGeometry(*image,args[0],&geometry,exception);
3161           new_image=RollImage(*image,geometry.x,geometry.y,exception);
3162           break;
3163         }
3164       if (LocaleCompare("rotate",option) == 0)
3165         {
3166           /* special case rotation flags */
3167           (void) SyncImageSettings(image_info,*image,exception);
3168           if (strchr(args[0],'>') != (char *) NULL)
3169             if ((*image)->columns <= (*image)->rows)
3170               break;
3171           if (strchr(args[0],'<') != (char *) NULL)
3172             if ((*image)->columns >= (*image)->rows)
3173               break;
3174
3175           (void) ParseGeometry(args[0],&geometry_info);
3176           new_image=RotateImage(*image,geometry_info.rho,exception);
3177           break;
3178         }
3179       break;
3180     }
3181     case 's':
3182     {
3183       if (LocaleCompare("sample",option) == 0)
3184         {
3185           (void) SyncImageSettings(image_info,*image,exception);
3186           (void) ParseRegionGeometry(*image,args[0],&geometry,exception);
3187           new_image=SampleImage(*image,geometry.width,geometry.height,
3188             exception);
3189           break;
3190         }
3191       if (LocaleCompare("scale",option) == 0)
3192         {
3193           (void) SyncImageSettings(image_info,*image,exception);
3194           (void) ParseRegionGeometry(*image,args[0],&geometry,exception);
3195           new_image=ScaleImage(*image,geometry.width,geometry.height,
3196             exception);
3197           break;
3198         }
3199       if (LocaleCompare("selective-blur",option) == 0)
3200         {
3201           (void) SyncImageSettings(image_info,*image,exception);
3202           flags=ParseGeometry(args[0],&geometry_info);
3203           if ((flags & PercentValue) != 0)
3204             geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3205           new_image=SelectiveBlurImage(*image,geometry_info.rho,
3206             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3207           break;
3208         }
3209       if (LocaleCompare("separate",option) == 0)
3210         {
3211           /*
3212             Break channels into separate images.
3213             WARNING: This can generate multiple images!
3214           */
3215           (void) SyncImageSettings(image_info,*image,exception);
3216           new_image=SeparateImages(*image,exception);
3217           break;
3218         }
3219       if (LocaleCompare("sepia-tone",option) == 0)
3220         {
3221           double
3222             threshold;
3223
3224           (void) SyncImageSettings(image_info,*image,exception);
3225           threshold=StringToDoubleInterval(args[0],(double) QuantumRange+1.0);
3226           new_image=SepiaToneImage(*image,threshold,exception);
3227           break;
3228         }
3229       if (LocaleCompare("segment",option) == 0)
3230         {
3231           (void) SyncImageSettings(image_info,*image,exception);
3232           flags=ParseGeometry(args[0],&geometry_info);
3233           if ((flags & SigmaValue) == 0)
3234             geometry_info.sigma=1.0;
3235           (void) SegmentImage(*image,(*image)->colorspace,
3236             image_info->verbose,geometry_info.rho,geometry_info.sigma,
3237             exception);
3238           break;
3239         }
3240       if (LocaleCompare("set",option) == 0)
3241         {
3242           char
3243             *value;
3244
3245           if (*argv[0] == '+')
3246             {
3247               if (LocaleNCompare(args[0],"registry:",9) == 0)
3248                 (void) DeleteImageRegistry(args[0]+9);
3249               else
3250                 if (LocaleNCompare(args[0],"argv[0]:",7) == 0)
3251                   {
3252                     (void) DeleteImageOption(image_info,args[0]+7);
3253                     (void) DeleteImageArtifact(*image,args[0]+7);
3254                   }
3255                 else
3256                   (void) DeleteImageProperty(*image,args[0]);
3257               break;
3258             }
3259           value=InterpretImageProperties(image_info,*image,argv[2],
3260             exception);
3261           if (value == (char *) NULL)
3262             break;
3263           if (LocaleNCompare(args[0],"registry:",9) == 0)
3264             (void) SetImageRegistry(StringRegistryType,args[0]+9,value,
3265               exception);
3266           else
3267             if (LocaleNCompare(args[0],"option:",7) == 0)
3268               {
3269                 (void) SetImageOption(image_info,args[0]+7,value);
3270                 (void) SetImageArtifact(*image,args[0]+7,value);
3271               }
3272             else
3273               (void) SetImageProperty(*image,args[0],value,exception);
3274           value=DestroyString(value);
3275           break;
3276         }
3277       if (LocaleCompare("shade",option) == 0)
3278         {
3279           (void) SyncImageSettings(image_info,*image,exception);
3280           flags=ParseGeometry(args[0],&geometry_info);
3281           if ((flags & SigmaValue) == 0)
3282             geometry_info.sigma=1.0;
3283           new_image=ShadeImage(*image,(*argv[0] == '-') ? MagickTrue :
3284             MagickFalse,geometry_info.rho,geometry_info.sigma,exception);
3285           break;
3286         }
3287       if (LocaleCompare("shadow",option) == 0)
3288         {
3289           (void) SyncImageSettings(image_info,*image,exception);
3290           flags=ParseGeometry(args[0],&geometry_info);
3291           if ((flags & SigmaValue) == 0)
3292             geometry_info.sigma=1.0;
3293           if ((flags & XiValue) == 0)
3294             geometry_info.xi=4.0;
3295           if ((flags & PsiValue) == 0)
3296             geometry_info.psi=4.0;
3297           new_image=ShadowImage(*image,geometry_info.rho,
3298             geometry_info.sigma,(*image)->bias,(ssize_t)
3299             ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
3300             exception);
3301           break;
3302         }
3303       if (LocaleCompare("sharpen",option) == 0)
3304         {
3305           (void) SyncImageSettings(image_info,*image,exception);
3306           flags=ParseGeometry(args[0],&geometry_info);
3307           if ((flags & SigmaValue) == 0)
3308             geometry_info.sigma=1.0;
3309           if ((flags & XiValue) == 0)
3310             geometry_info.xi=0.0;
3311           new_image=SharpenImage(*image,geometry_info.rho,
3312             geometry_info.sigma,geometry_info.xi,exception);
3313           break;
3314         }
3315       if (LocaleCompare("shave",option) == 0)
3316         {
3317           (void) SyncImageSettings(image_info,*image,exception);
3318           flags=ParsePageGeometry(*image,args[0],&geometry,exception);
3319           new_image=ShaveImage(*image,&geometry,exception);
3320           break;
3321         }
3322       if (LocaleCompare("shear",option) == 0)
3323         {
3324           (void) SyncImageSettings(image_info,*image,exception);
3325           flags=ParseGeometry(args[0],&geometry_info);
3326           if ((flags & SigmaValue) == 0)
3327             geometry_info.sigma=geometry_info.rho;
3328           new_image=ShearImage(*image,geometry_info.rho,
3329             geometry_info.sigma,exception);
3330           break;
3331         }
3332       if (LocaleCompare("sigmoidal-contrast",option) == 0)
3333         {
3334           (void) SyncImageSettings(image_info,*image,exception);
3335           flags=ParseGeometry(args[0],&geometry_info);
3336           if ((flags & SigmaValue) == 0)
3337             geometry_info.sigma=(double) QuantumRange/2.0;
3338           if ((flags & PercentValue) != 0)
3339             geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3340               100.0;
3341           (void) SigmoidalContrastImage(*image,(*argv[0] == '-') ?
3342             MagickTrue : MagickFalse,geometry_info.rho,geometry_info.sigma,
3343             exception);
3344           break;
3345         }
3346       if (LocaleCompare("sketch",option) == 0)
3347         {
3348           (void) SyncImageSettings(image_info,*image,exception);
3349           flags=ParseGeometry(args[0],&geometry_info);
3350           if ((flags & SigmaValue) == 0)
3351             geometry_info.sigma=1.0;
3352           new_image=SketchImage(*image,geometry_info.rho,
3353             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3354           break;
3355         }
3356       if (LocaleCompare("solarize",option) == 0)
3357         {
3358           double
3359             threshold;
3360
3361           (void) SyncImageSettings(image_info,*image,exception);
3362           threshold=StringToDoubleInterval(args[0],(double) QuantumRange+1.0);
3363           (void) SolarizeImage(*image,threshold,exception);
3364           break;
3365         }
3366       if (LocaleCompare("sparse-color",option) == 0)
3367         {
3368           SparseColorMethod
3369             method;
3370
3371           char
3372             *arguments;
3373
3374           (void) SyncImageSettings(image_info,*image,exception);
3375           method=(SparseColorMethod) ParseCommandOption(
3376             MagickSparseColorOptions,MagickFalse,args[0]);
3377           arguments=InterpretImageProperties(image_info,*image,argv[2],
3378             exception);
3379           if (arguments == (char *) NULL)
3380             break;
3381           new_image=SparseColorOption(*image,method,arguments,
3382             argv[0][0] == '+' ? MagickTrue : MagickFalse,exception);
3383           arguments=DestroyString(arguments);
3384           break;
3385         }
3386       if (LocaleCompare("splice",option) == 0)
3387         {
3388           (void) SyncImageSettings(image_info,*image,exception);
3389           (void) ParseGravityGeometry(*image,args[0],&geometry,exception);
3390           new_image=SpliceImage(*image,&geometry,exception);
3391           break;
3392         }
3393       if (LocaleCompare("spread",option) == 0)
3394         {
3395           (void) SyncImageSettings(image_info,*image,exception);
3396           (void) ParseGeometry(args[0],&geometry_info);
3397           new_image=SpreadImage(*image,geometry_info.rho,
3398             interpolate_method,exception);
3399           break;
3400         }
3401       if (LocaleCompare("statistic",option) == 0)
3402         {
3403           StatisticType
3404             type;
3405
3406           (void) SyncImageSettings(image_info,*image,exception);
3407           type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
3408             MagickFalse,args[0]);
3409           (void) ParseGeometry(argv[2],&geometry_info);
3410           new_image=StatisticImage(*image,type,(size_t) geometry_info.rho,
3411             (size_t) geometry_info.sigma,exception);
3412           break;
3413         }
3414       if (LocaleCompare("strip",option) == 0)
3415         {
3416           (void) SyncImageSettings(image_info,*image,exception);
3417           (void) StripImage(*image,exception);
3418           break;
3419         }
3420       if (LocaleCompare("swirl",option) == 0)
3421         {
3422           (void) SyncImageSettings(image_info,*image,exception);
3423           (void) ParseGeometry(args[0],&geometry_info);
3424           new_image=SwirlImage(*image,geometry_info.rho,
3425             interpolate_method,exception);
3426           break;
3427         }
3428       break;
3429     }
3430     case 't':
3431     {
3432       if (LocaleCompare("threshold",option) == 0)
3433         {
3434           double
3435             threshold;
3436
3437           (void) SyncImageSettings(image_info,*image,exception);
3438           if (*argv[0] == '+')
3439             threshold=(double) QuantumRange/2;
3440           else
3441             threshold=StringToDoubleInterval(args[0],(double) QuantumRange+1.0);
3442           (void) BilevelImage(*image,threshold,exception);
3443           break;
3444         }
3445       if (LocaleCompare("thumbnail",option) == 0)
3446         {
3447           /*
3448             Thumbnail image.
3449           */
3450           (void) SyncImageSettings(image_info,*image,exception);
3451           (void) ParseRegionGeometry(*image,args[0],&geometry,exception);
3452           new_image=ThumbnailImage(*image,geometry.width,geometry.height,
3453             exception);
3454           break;
3455         }
3456       if (LocaleCompare("tint",option) == 0)
3457         {
3458           (void) SyncImageSettings(image_info,*image,exception);
3459           new_image=TintImage(*image,args[0],&fill,exception);
3460           break;
3461         }
3462       if (LocaleCompare("transform",option) == 0)
3463         {
3464           (void) SyncImageSettings(image_info,*image,exception);
3465           new_image=AffineTransformImage(*image,&draw_info->affine,
3466             exception);
3467           break;
3468         }
3469       if (LocaleCompare("transparent",option) == 0)
3470         {
3471           PixelInfo
3472             target;
3473
3474           (void) SyncImageSettings(image_info,*image,exception);
3475           (void) QueryColorCompliance(args[0],AllCompliance,&target,
3476                        exception);
3477           (void) TransparentPaintImage(*image,&target,(Quantum)
3478             TransparentAlpha,*argv[0] == '-' ? MagickFalse : MagickTrue,
3479             exception);
3480           break;
3481         }
3482       if (LocaleCompare("transpose",option) == 0)
3483         {
3484           (void) SyncImageSettings(image_info,*image,exception);
3485           new_image=TransposeImage(*image,exception);
3486           break;
3487         }
3488       if (LocaleCompare("transverse",option) == 0)
3489         {
3490           (void) SyncImageSettings(image_info,*image,exception);
3491           new_image=TransverseImage(*image,exception);
3492           break;
3493         }
3494       if (LocaleCompare("treedepth",option) == 0)
3495         {
3496           quantize_info->tree_depth=StringToUnsignedLong(args[0]);
3497           break;
3498         }
3499       if (LocaleCompare("trim",option) == 0)
3500         {
3501           (void) SyncImageSettings(image_info,*image,exception);
3502           new_image=TrimImage(*image,exception);
3503           break;
3504         }
3505       if (LocaleCompare("type",option) == 0)
3506         {
3507           /* Note that "type" setting should have already been defined */
3508           (void) SyncImageSettings(image_info,*image,exception);
3509           (void) SetImageType(*image,type,exception);
3510           break;
3511         }
3512       break;
3513     }
3514     case 'u':
3515     {
3516       if (LocaleCompare("unique",option) == 0)
3517         {
3518           if (*argv[0] == '+')
3519             {
3520               (void) DeleteImageArtifact(*image,"identify:unique-colors");
3521               break;
3522             }
3523           (void) SetImageArtifact(*image,"identify:unique-colors","true");
3524           (void) SetImageArtifact(*image,"verbose","true");
3525           break;
3526         }
3527       if (LocaleCompare("unique-colors",option) == 0)
3528         {
3529           (void) SyncImageSettings(image_info,*image,exception);
3530           new_image=UniqueImageColors(*image,exception);
3531           break;
3532         }
3533       if (LocaleCompare("unsharp",option) == 0)
3534         {
3535           (void) SyncImageSettings(image_info,*image,exception);
3536           flags=ParseGeometry(args[0],&geometry_info);
3537           if ((flags & SigmaValue) == 0)
3538             geometry_info.sigma=1.0;
3539           if ((flags & XiValue) == 0)
3540             geometry_info.xi=1.0;
3541           if ((flags & PsiValue) == 0)
3542             geometry_info.psi=0.05;
3543           new_image=UnsharpMaskImage(*image,geometry_info.rho,
3544             geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3545           break;
3546         }
3547       break;
3548     }
3549     case 'v':
3550     {
3551       if (LocaleCompare("verbose",option) == 0)
3552         {
3553           (void) SetImageArtifact(*image,option,
3554                  *argv[0] == '+' ? "false" : "true");
3555           break;
3556         }
3557       if (LocaleCompare("vignette",option) == 0)
3558         {
3559           /*
3560             Vignette image.
3561           */
3562           (void) SyncImageSettings(image_info,*image,exception);
3563           flags=ParseGeometry(args[0],&geometry_info);
3564           if ((flags & SigmaValue) == 0)
3565             geometry_info.sigma=1.0;
3566           if ((flags & XiValue) == 0)
3567             geometry_info.xi=0.1*(*image)->columns;
3568           if ((flags & PsiValue) == 0)
3569             geometry_info.psi=0.1*(*image)->rows;
3570           new_image=VignetteImage(*image,geometry_info.rho,
3571             geometry_info.sigma,(*image)->bias,(ssize_t)
3572             ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
3573             exception);
3574           break;
3575         }
3576       if (LocaleCompare("virtual-pixel",option) == 0)
3577         {
3578           /* setting already defined in image_info structure */
3579           SetImageVirtualPixelMethod(*image, image_info->virtual_pixel_method);
3580           break;
3581         }
3582       break;
3583     }
3584     case 'w':
3585     {
3586       if (LocaleCompare("wave",option) == 0)
3587         {
3588           (void) SyncImageSettings(image_info,*image,exception);
3589           flags=ParseGeometry(args[0],&geometry_info);
3590           if ((flags & SigmaValue) == 0)
3591             geometry_info.sigma=1.0;
3592           new_image=WaveImage(*image,geometry_info.rho,
3593             geometry_info.sigma,interpolate_method,exception);
3594           break;
3595         }
3596       if (LocaleCompare("white-threshold",option) == 0)
3597         {
3598           (void) SyncImageSettings(image_info,*image,exception);
3599           (void) WhiteThresholdImage(*image,args[0],exception);
3600           break;
3601         }
3602       break;
3603     }
3604     default:
3605       break;
3606   }
3607   /*
3608      Replace current image with any image that was generated
3609   */
3610   if (new_image != (Image *) NULL)
3611     ReplaceImageInListReturnLast(image,new_image);
3612
3613   /*
3614     Free resources.
3615   */
3616   quantize_info=DestroyQuantizeInfo(quantize_info);
3617   draw_info=DestroyDrawInfo(draw_info);
3618   status=(MagickStatusType) (exception->severity == UndefinedException ? 1 : 0);
3619   return(status == 0 ? MagickFalse : MagickTrue);
3620 }
3621 \f
3622 /*
3623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3624 %                                                                             %
3625 %                                                                             %
3626 %                                                                             %
3627 +     S e q u e n c e O p e r a t i o n I m a g e s                           %
3628 %                                                                             %
3629 %                                                                             %
3630 %                                                                             %
3631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3632 %
3633 %  SequenceOperationImages() applies a single operation that apply to the
3634 %  entire image list (e.g. -append, -layers, -coalesce, etc.).
3635 %
3636 %  The format of the MogrifyImage method is:
3637 %
3638 %    MagickBooleanType SequenceOperationImages(ImageInfo *image_info,
3639 %        const int argc, const char **argv,Image **images,
3640 %        ExceptionInfo *exception)
3641 %
3642 %  A description of each parameter follows:
3643 %
3644 %    o image_info: the image info..
3645 %
3646 %    o argc: Specifies a pointer to an integer describing the number of
3647 %      elements in the argument vector.
3648 %
3649 %    o argv: Specifies a pointer to a text array containing the command line
3650 %      arguments.
3651 %
3652 %    o images: pointer to pointer of the first image in image list.
3653 %
3654 %    o exception: return any errors or warnings in this structure.
3655 %
3656 */
3657 WandExport MagickBooleanType SequenceOperationImages(ImageInfo *image_info,
3658   const int argc,const char **argv,Image **images,ExceptionInfo *exception)
3659 {
3660
3661   MagickStatusType
3662     status;
3663
3664   QuantizeInfo
3665     *quantize_info;
3666
3667   assert(image_info != (ImageInfo *) NULL);
3668   assert(image_info->signature == MagickSignature);
3669   assert(images != (Image **) NULL);
3670   assert((*images)->previous == (Image *) NULL);
3671   assert((*images)->signature == MagickSignature);
3672   if ((*images)->debug != MagickFalse)
3673     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3674       (*images)->filename);
3675   if ((argc <= 0) || (*argv == (char *) NULL))
3676     return(MagickTrue);
3677   status=MagickTrue;
3678
3679   switch (*(argv[0]+1))
3680   {
3681     case 'a':
3682     {
3683       if (LocaleCompare("affinity",argv[0]+1) == 0)
3684         {
3685           (void) SyncImagesSettings(image_info,*images,exception);
3686           if (*argv[0] == '+')
3687             {
3688               (void) RemapImages(quantize_info,*images,(Image *) NULL,
3689                 exception);
3690               break;
3691             }
3692           break;
3693         }
3694       if (LocaleCompare("append",argv[0]+1) == 0)
3695         {
3696           Image
3697             *append_image;
3698
3699           (void) SyncImagesSettings(image_info,*images,exception);
3700           append_image=AppendImages(*images,*argv[0] == '-' ? MagickTrue :
3701             MagickFalse,exception);
3702           if (append_image == (Image *) NULL)
3703             {
3704               status=MagickFalse;
3705               break;
3706             }
3707           *images=DestroyImageList(*images);
3708           *images=append_image;
3709           break;
3710         }
3711       if (LocaleCompare("average",argv[0]+1) == 0)
3712         {
3713           Image
3714             *average_image;
3715
3716           /*
3717             Average an image sequence (deprecated).
3718           */
3719           (void) SyncImagesSettings(image_info,*images,exception);
3720           average_image=EvaluateImages(*images,MeanEvaluateOperator,
3721             exception);
3722           if (average_image == (Image *) NULL)
3723             {
3724               status=MagickFalse;
3725               break;
3726             }
3727           *images=DestroyImageList(*images);
3728           *images=average_image;
3729           break;
3730         }
3731       break;
3732     }
3733     case 'c':
3734     {
3735       if (LocaleCompare("channel",argv[0]+1) == 0)
3736         {
3737           ChannelType
3738             channel;
3739
3740           if (*argv[0] == '+')
3741             {
3742               channel=DefaultChannels;
3743               break;
3744             }
3745           channel=(ChannelType) ParseChannelOption(argv[1]);
3746           SetPixelChannelMap(*images,channel);
3747           break;
3748         }
3749       if (LocaleCompare("clut",argv[0]+1) == 0)
3750         {
3751           Image
3752             *clut_image,
3753             *image;
3754
3755           (void) SyncImagesSettings(image_info,*images,exception);
3756           image=RemoveFirstImageFromList(images);
3757           clut_image=RemoveFirstImageFromList(images);
3758           if (clut_image == (Image *) NULL)
3759             {
3760               status=MagickFalse;
3761               break;
3762             }
3763           (void) ClutImage(image,clut_image,interpolate_method,exception);
3764           clut_image=DestroyImage(clut_image);
3765           *images=DestroyImageList(*images);
3766           *images=image;
3767           break;
3768         }
3769       if (LocaleCompare("coalesce",argv[0]+1) == 0)
3770         {
3771           Image
3772             *coalesce_image;
3773
3774           (void) SyncImagesSettings(image_info,*images,exception);
3775           coalesce_image=CoalesceImages(*images,exception);
3776           if (coalesce_image == (Image *) NULL)
3777             {
3778               status=MagickFalse;
3779               break;
3780             }
3781           *images=DestroyImageList(*images);
3782           *images=coalesce_image;
3783           break;
3784         }
3785       if (LocaleCompare("combine",argv[0]+1) == 0)
3786         {
3787           Image
3788             *combine_image;
3789
3790           (void) SyncImagesSettings(image_info,*images,exception);
3791           combine_image=CombineImages(*images,exception);
3792           if (combine_image == (Image *) NULL)
3793             {
3794               status=MagickFalse;
3795               break;
3796             }
3797           *images=DestroyImageList(*images);
3798           *images=combine_image;
3799           break;
3800         }
3801       if (LocaleCompare("composite",argv[0]+1) == 0)
3802         {
3803           Image
3804             *mask_image,
3805             *composite_image,
3806             *image;
3807
3808           RectangleInfo
3809             geometry;
3810
3811           ComposeOperator
3812             compose;
3813
3814           const char*
3815             value;
3816
3817           value=GetImageOption(image_info,"compose");
3818           if (value != (const char *) NULL)
3819             compose=(CompositeOperator) ParseCommandOption(
3820                  MagickComposeOptions,MagickFalse,value);
3821           else
3822             compose=OverCompositeOp;  /* use Over not image->compose */
3823
3824           const char*
3825             value=GetImageOption(image_info,"compose");
3826
3827            if (value != (const char *) NULL)
3828              compose=(CompositeOperator) ParseCommandOption(
3829                   MagickComposeOptions,MagickFalse,value);
3830            else
3831              compose=OverCompositeOp;  /* use Over not image->compose */
3832
3833
3834           (void) SyncImagesSettings(image_info,*images,exception);
3835           image=RemoveFirstImageFromList(images);
3836           composite_image=RemoveFirstImageFromList(images);
3837           if (composite_image == (Image *) NULL)
3838             {
3839               status=MagickFalse;
3840               break;
3841             }
3842           (void) TransformImage(&composite_image,(char *) NULL,
3843             composite_image->geometry,exception);
3844           SetGeometry(composite_image,&geometry);
3845           (void) ParseAbsoluteGeometry(composite_image->geometry,&geometry);
3846           GravityAdjustGeometry(image->columns,image->rows,image->gravity,
3847             &geometry);
3848           mask_image=RemoveFirstImageFromList(images);
3849           if (mask_image != (Image *) NULL)
3850             {
3851               if ((compose == DisplaceCompositeOp) ||
3852                   (compose == DistortCompositeOp))
3853                 {
3854                   /*
3855                     Merge Y displacement into X displacement image.
3856                   */
3857                   (void) CompositeImage(composite_image,CopyGreenCompositeOp,
3858                     mask_image,0,0,exception);
3859                   mask_image=DestroyImage(mask_image);
3860                 }
3861               else
3862                 {
3863                   /*
3864                     Set a blending mask for the composition.
3865                     Posible error, what if image->mask already set.
3866                   */
3867                   image->mask=mask_image;
3868                   (void) NegateImage(image->mask,MagickFalse,exception);
3869                 }
3870             }
3871           (void) CompositeImage(image,compose,composite_image,
3872             geometry.x,geometry.y,exception);
3873           if (mask_image != (Image *) NULL)
3874             mask_image=image->mask=DestroyImage(image->mask);
3875           composite_image=DestroyImage(composite_image);
3876           *images=DestroyImageList(*images);
3877           *images=image;
3878           break;
3879         }
3880       break;
3881     }
3882     case 'd':
3883     {
3884       if (LocaleCompare("deconstruct",argv[0]+1) == 0)
3885         {
3886           Image
3887             *deconstruct_image;
3888
3889           (void) SyncImagesSettings(image_info,*images,exception);
3890           deconstruct_image=CompareImagesLayers(*images,CompareAnyLayer,
3891             exception);
3892           if (deconstruct_image == (Image *) NULL)
3893             {
3894               status=MagickFalse;
3895               break;
3896             }
3897           *images=DestroyImageList(*images);
3898           *images=deconstruct_image;
3899           break;
3900         }
3901       if (LocaleCompare("delete",argv[0]+1) == 0)
3902         {
3903           if (*argv[0] == '+')
3904             DeleteImages(images,"-1",exception);
3905           else
3906             DeleteImages(images,argv[1],exception);
3907           break;
3908         }
3909       if (LocaleCompare("dither",argv[0]+1) == 0)
3910         {
3911           if (*argv[0] == '+')
3912             {
3913               quantize_info->dither=MagickFalse;
3914               break;
3915             }
3916           quantize_info->dither=MagickTrue;
3917           quantize_info->dither_method=(DitherMethod) ParseCommandOption(
3918             MagickDitherOptions,MagickFalse,argv[1]);
3919           break;
3920         }
3921       if (LocaleCompare("duplicate",argv[0]+1) == 0)
3922         {
3923           Image
3924             *duplicate_images;
3925
3926           if (*argv[0] == '+')
3927             duplicate_images=DuplicateImages(*images,1,"-1",exception);
3928           else
3929             {
3930               const char
3931                 *p;
3932
3933               size_t
3934                 number_duplicates;
3935
3936               number_duplicates=(size_t) StringToLong(argv[1]);
3937               p=strchr(argv[1],',');
3938               if (p == (const char *) NULL)
3939                 duplicate_images=DuplicateImages(*images,number_duplicates,
3940                   "-1",exception);
3941               else
3942                 duplicate_images=DuplicateImages(*images,number_duplicates,p,
3943                   exception);
3944             }
3945           AppendImageToList(images, duplicate_images);
3946           (void) SyncImagesSettings(image_info,*images,exception);
3947           break;
3948         }
3949       break;
3950     }
3951     case 'e':
3952     {
3953       if (LocaleCompare("evaluate-sequence",argv[0]+1) == 0)
3954         {
3955           Image
3956             *evaluate_image;
3957
3958           MagickEvaluateOperator
3959             op;
3960
3961           (void) SyncImageSettings(image_info,*images);
3962           op=(MagickEvaluateOperator) ParseCommandOption(
3963             MagickEvaluateOptions,MagickFalse,argv[1]);
3964           evaluate_image=EvaluateImages(*images,op,exception);
3965           if (evaluate_image == (Image *) NULL)
3966             {
3967               status=MagickFalse;
3968               break;
3969             }
3970           *images=DestroyImageList(*images);
3971           *images=evaluate_image;
3972           break;
3973         }
3974       break;
3975     }
3976     case 'f':
3977     {
3978       if (LocaleCompare("fft",argv[0]+1) == 0)
3979         {
3980           Image
3981             *fourier_image;
3982
3983           /*
3984             Implements the discrete Fourier transform (DFT).
3985           */
3986           (void) SyncImageSettings(image_info,*images);
3987           fourier_image=ForwardFourierTransformImage(*images,*argv[0] == '-' ?
3988             MagickTrue : MagickFalse,exception);
3989           if (fourier_image == (Image *) NULL)
3990             break;
3991           *images=DestroyImage(*images);
3992           *images=fourier_image;
3993           break;
3994         }
3995       if (LocaleCompare("flatten",argv[0]+1) == 0)
3996         {
3997           Image
3998             *flatten_image;
3999
4000           (void) SyncImagesSettings(image_info,*images,exception);
4001           flatten_image=MergeImageLayers(*images,FlattenLayer,exception);
4002           if (flatten_image == (Image *) NULL)
4003             break;
4004           *images=DestroyImageList(*images);
4005           *images=flatten_image;
4006           break;
4007         }
4008       if (LocaleCompare("fx",argv[0]+1) == 0)
4009         {
4010           Image
4011             *fx_image;
4012
4013           (void) SyncImagesSettings(image_info,*images,exception);
4014           fx_image=FxImage(*images,argv[1],exception);
4015           if (fx_image == (Image *) NULL)
4016             {
4017               status=MagickFalse;
4018               break;
4019             }
4020           *images=DestroyImageList(*images);
4021           *images=fx_image;
4022           break;
4023         }
4024       break;
4025     }
4026     case 'h':
4027     {
4028       if (LocaleCompare("hald-clut",argv[0]+1) == 0)
4029         {
4030           Image
4031             *hald_image,
4032             *image;
4033
4034           (void) SyncImagesSettings(image_info,*images,exception);
4035           image=RemoveFirstImageFromList(images);
4036           hald_image=RemoveFirstImageFromList(images);
4037           if (hald_image == (Image *) NULL)
4038             {
4039               status=MagickFalse;
4040               break;
4041             }
4042           (void) HaldClutImage(image,hald_image,exception);
4043           hald_image=DestroyImage(hald_image);
4044           if (*images != (Image *) NULL)
4045             *images=DestroyImageList(*images);
4046           *images=image;
4047           break;
4048         }
4049       break;
4050     }
4051     case 'i':
4052     {
4053       if (LocaleCompare("ift",argv[0]+1) == 0)
4054         {
4055           Image
4056             *fourier_image,
4057             *magnitude_image,
4058             *phase_image;
4059
4060           /*
4061             Implements the inverse fourier discrete Fourier transform (DFT).
4062           */
4063           (void) SyncImagesSettings(image_info,*images,exception);
4064           magnitude_image=RemoveFirstImageFromList(images);
4065           phase_image=RemoveFirstImageFromList(images);
4066           if (phase_image == (Image *) NULL)
4067             {
4068               status=MagickFalse;
4069               break;
4070             }
4071           fourier_image=InverseFourierTransformImage(magnitude_image,
4072             phase_image,*argv[0] == '-' ? MagickTrue : MagickFalse,exception);
4073           if (fourier_image == (Image *) NULL)
4074             break;
4075           if (*images != (Image *) NULL)
4076             *images=DestroyImage(*images);
4077           *images=fourier_image;
4078           break;
4079         }
4080       if (LocaleCompare("insert",argv[0]+1) == 0)
4081         {
4082           Image
4083             *p,
4084             *q;
4085
4086           index=0;
4087           if (*argv[0] != '+')
4088             index=(ssize_t) StringToLong(argv[1]);
4089           p=RemoveLastImageFromList(images);
4090           if (p == (Image *) NULL)
4091             {
4092               (void) ThrowMagickException(exception,GetMagickModule(),
4093                 OptionError,"NoSuchImage","`%s'",argv[1]);
4094               status=MagickFalse;
4095               break;
4096             }
4097           q=p;
4098           if (index == 0)
4099             PrependImageToList(images,q);
4100           else
4101             if (index == (ssize_t) GetImageListLength(*images))
4102               AppendImageToList(images,q);
4103             else
4104               {
4105                  q=GetImageFromList(*images,index-1);
4106                  if (q == (Image *) NULL)
4107                    {
4108                      (void) ThrowMagickException(exception,GetMagickModule(),
4109                        OptionError,"NoSuchImage","`%s'",argv[1]);
4110                      status=MagickFalse;
4111                      break;
4112                    }
4113                 InsertImageInList(&q,p);
4114               }
4115           *images=GetFirstImageInList(q);
4116           break;
4117         }
4118       if (LocaleCompare("interpolate",argv[0]+1) == 0)
4119         {
4120           interpolate_method=(PixelInterpolateMethod) ParseCommandOption(
4121             MagickInterpolateOptions,MagickFalse,argv[1]);
4122           break;
4123         }
4124       break;
4125     }
4126     case 'l':
4127     {
4128       if (LocaleCompare("layers",argv[0]+1) == 0)
4129         {
4130           Image
4131             *layers;
4132
4133           ImageLayerMethod
4134             method;
4135
4136           (void) SyncImagesSettings(image_info,*images,exception);
4137           layers=(Image *) NULL;
4138           method=(ImageLayerMethod) ParseCommandOption(MagickLayerOptions,
4139             MagickFalse,argv[1]);
4140           switch (method)
4141           {
4142             case CoalesceLayer:
4143             {
4144               layers=CoalesceImages(*images,exception);
4145               break;
4146             }
4147             case CompareAnyLayer:
4148             case CompareClearLayer:
4149             case CompareOverlayLayer:
4150             default:
4151             {
4152               layers=CompareImagesLayers(*images,method,exception);
4153               break;
4154             }
4155             case MergeLayer:
4156             case FlattenLayer:
4157             case MosaicLayer:
4158             case TrimBoundsLayer:
4159             {
4160               layers=MergeImageLayers(*images,method,exception);
4161               break;
4162             }
4163             case DisposeLayer:
4164             {
4165               layers=DisposeImages(*images,exception);
4166               break;
4167             }
4168             case OptimizeImageLayer:
4169             {
4170               layers=OptimizeImageLayers(*images,exception);
4171               break;
4172             }
4173             case OptimizePlusLayer:
4174             {
4175               layers=OptimizePlusImageLayers(*images,exception);
4176               break;
4177             }
4178             case OptimizeTransLayer:
4179             {
4180               OptimizeImageTransparency(*images,exception);
4181               break;
4182             }
4183             case RemoveDupsLayer:
4184             {
4185               RemoveDuplicateLayers(images,exception);
4186               break;
4187             }
4188             case RemoveZeroLayer:
4189             {
4190               RemoveZeroDelayLayers(images,exception);
4191               break;
4192             }
4193             case OptimizeLayer:
4194             {
4195               /*
4196                 General Purpose, GIF Animation Optimizer.
4197               */
4198               layers=CoalesceImages(*images,exception);
4199               if (layers == (Image *) NULL)
4200                 {
4201                   status=MagickFalse;
4202                   break;
4203                 }
4204               *images=DestroyImageList(*images);
4205               *images=layers;
4206               layers=OptimizeImageLayers(*images,exception);
4207               if (layers == (Image *) NULL)
4208                 {
4209                   status=MagickFalse;
4210                   break;
4211                 }
4212               *images=DestroyImageList(*images);
4213               *images=layers;
4214               layers=(Image *) NULL;
4215               OptimizeImageTransparency(*images,exception);
4216               (void) RemapImages(quantize_info,*images,(Image *) NULL,
4217                 exception);
4218               break;
4219             }
4220             case CompositeLayer:
4221             {
4222               Image
4223                 *source;
4224
4225               RectangleInfo
4226                 geometry;
4227
4228               ComposeOperator
4229                 compose;
4230
4231               const char*
4232                 value;
4233
4234               value=GetImageOption(image_info,"compose");
4235               if (value != (const char *) NULL)
4236                 compose=(CompositeOperator) ParseCommandOption(
4237                       MagickComposeOptions,MagickFalse,value);
4238               else
4239                 compose=OverCompositeOp;  /* use Over not image->compose */
4240
4241               /*
4242                 Split image sequence at the first 'NULL:' image.
4243               */
4244               source=(*images);
4245               while (source != (Image *) NULL)
4246               {
4247                 source=GetNextImageInList(source);
4248                 if ((source != (Image *) NULL) &&
4249                     (LocaleCompare(source->magick,"NULL") == 0))
4250                   break;
4251               }
4252               if (source != (Image *) NULL)
4253                 {
4254                   if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4255                       (GetNextImageInList(source) == (Image *) NULL))
4256                     source=(Image *) NULL;
4257                   else
4258                     {
4259                       /*
4260                         Separate the two lists, junk the null: image.
4261                       */
4262                       source=SplitImageList(source->previous);
4263                       DeleteImageFromList(&source);
4264                     }
4265                 }
4266               if (source == (Image *) NULL)
4267                 {
4268                   (void) ThrowMagickException(exception,GetMagickModule(),
4269                     OptionError,"MissingNullSeparator","layers Composite");
4270                   status=MagickFalse;
4271                   break;
4272                 }
4273               /*
4274                 Adjust offset with gravity and virtual canvas.
4275               */
4276               SetGeometry(*images,&geometry);
4277               (void) ParseAbsoluteGeometry((*images)->geometry,&geometry);
4278               geometry.width=source->page.width != 0 ?
4279                 source->page.width : source->columns;
4280               geometry.height=source->page.height != 0 ?
4281                source->page.height : source->rows;
4282               GravityAdjustGeometry((*images)->page.width != 0 ?
4283                 (*images)->page.width : (*images)->columns,
4284                 (*images)->page.height != 0 ? (*images)->page.height :
4285                 (*images)->rows,(*images)->gravity,&geometry);
4286
4287               /*
4288                 Compose the two image sequences together
4289               */
4290               CompositeLayers(*images,compose,source,geometry.x,geometry.y,
4291                 exception);
4292               source=DestroyImageList(source);
4293               break;
4294             }
4295           }
4296           if (layers == (Image *) NULL)
4297             break;
4298           *images=DestroyImageList(*images);
4299           *images=layers;
4300           break;
4301         }
4302       break;
4303     }
4304     case 'm':
4305     {
4306       if (LocaleCompare("map",argv[0]+1) == 0)
4307         {
4308           (void) SyncImagesSettings(image_info,*images,exception);
4309           if (*argv[0] == '+')
4310             {
4311               (void) RemapImages(quantize_info,*images,(Image *) NULL,
4312                 exception);
4313               break;
4314             }
4315           break;
4316         }
4317       if (LocaleCompare("maximum",argv[0]+1) == 0)
4318         {
4319           Image
4320             *maximum_image;
4321
4322           /*
4323             Maximum image sequence (deprecated).
4324           */
4325           (void) SyncImagesSettings(image_info,*images,exception);
4326           maximum_image=EvaluateImages(*images,MaxEvaluateOperator,exception);
4327           if (maximum_image == (Image *) NULL)
4328             {
4329               status=MagickFalse;
4330               break;
4331             }
4332           *images=DestroyImageList(*images);
4333           *images=maximum_image;
4334           break;
4335         }
4336       if (LocaleCompare("minimum",argv[0]+1) == 0)
4337         {
4338           Image
4339             *minimum_image;
4340
4341           /*
4342             Minimum image sequence (deprecated).
4343           */
4344           (void) SyncImagesSettings(image_info,*images,exception);
4345           minimum_image=EvaluateImages(*images,MinEvaluateOperator,exception);
4346           if (minimum_image == (Image *) NULL)
4347             {
4348               status=MagickFalse;
4349               break;
4350             }
4351           *images=DestroyImageList(*images);
4352           *images=minimum_image;
4353           break;
4354         }
4355       if (LocaleCompare("morph",argv[0]+1) == 0)
4356         {
4357           Image
4358             *morph_image;
4359
4360           (void) SyncImagesSettings(image_info,*images,exception);
4361           morph_image=MorphImages(*images,StringToUnsignedLong(argv[1]),
4362             exception);
4363           if (morph_image == (Image *) NULL)
4364             {
4365               status=MagickFalse;
4366               break;
4367             }
4368           *images=DestroyImageList(*images);
4369           *images=morph_image;
4370           break;
4371         }
4372       if (LocaleCompare("mosaic",argv[0]+1) == 0)
4373         {
4374           Image
4375             *mosaic_image;
4376
4377           (void) SyncImagesSettings(image_info,*images,exception);
4378           mosaic_image=MergeImageLayers(*images,MosaicLayer,exception);
4379           if (mosaic_image == (Image *) NULL)
4380             {
4381               status=MagickFalse;
4382               break;
4383             }
4384           *images=DestroyImageList(*images);
4385           *images=mosaic_image;
4386           break;
4387         }
4388       break;
4389     }
4390     case 'p':
4391     {
4392       if (LocaleCompare("print",argv[0]+1) == 0)
4393         {
4394           char
4395             *string;
4396
4397           (void) SyncImagesSettings(image_info,*images,exception);
4398           string=InterpretImageProperties(image_info,*images,argv[1],
4399             exception);
4400           if (string == (char *) NULL)
4401             break;
4402           (void) FormatLocaleFile(stdout,"%s",string);
4403           string=DestroyString(string);
4404         }
4405       if (LocaleCompare("process",argv[0]+1) == 0)
4406         {
4407           char
4408             **arguments;
4409
4410           int
4411             j,
4412             number_arguments;
4413
4414           (void) SyncImagesSettings(image_info,*images,exception);
4415           arguments=StringToArgv(argv[1],&number_arguments);
4416           if (arguments == (char **) NULL)
4417             break;
4418           if ((argc > 1) && (strchr(arguments[1],'=') != (char *) NULL))
4419             {
4420               char
4421                 breaker,
4422                 quote,
4423                 *token;
4424
4425               const char
4426                 *arguments;
4427
4428               int
4429                 next,
4430                 status;
4431
4432               size_t
4433                 length;
4434
4435               TokenInfo
4436                 *token_info;
4437
4438               /*
4439                 Support old style syntax, filter="-option arg".
4440               */
4441               length=strlen(argv[1]);
4442               token=(char *) NULL;
4443               if (~length >= (MaxTextExtent-1))
4444                 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4445                   sizeof(*token));
4446               if (token == (char *) NULL)
4447                 break;
4448               next=0;
4449               arguments=argv[1];
4450               token_info=AcquireTokenInfo();
4451               status=Tokenizer(token_info,0,token,length,arguments,"","=",
4452                 "\"",'\0',&breaker,&next,&quote);
4453               token_info=DestroyTokenInfo(token_info);
4454               if (status == 0)
4455                 {
4456                   const char
4457                     *argv;
4458
4459                   argv=(&(arguments[next]));
4460                   (void) InvokeDynamicImageFilter(token,&(*images),1,&argv,
4461                     exception);
4462                 }
4463               token=DestroyString(token);
4464               break;
4465             }
4466           (void) SubstituteString(&arguments[1],"-","");
4467           (void) InvokeDynamicImageFilter(arguments[1],&(*images),
4468             number_arguments-2,(const char **) arguments+2,exception);
4469           for (j=0; j < number_arguments; j++)
4470             arguments[j]=DestroyString(arguments[j]);
4471           arguments=(char **) RelinquishMagickMemory(arguments);
4472           break;
4473         }
4474       break;
4475     }
4476     case 'r':
4477     {
4478       if (LocaleCompare("reverse",argv[0]+1) == 0)
4479         {
4480           ReverseImageList(images);
4481           break;
4482         }
4483       break;
4484     }
4485     case 's':
4486     {
4487       if (LocaleCompare("smush",argv[0]+1) == 0)
4488         {
4489           Image
4490             *smush_image;
4491
4492           ssize_t
4493             offset;
4494
4495           (void) SyncImagesSettings(image_info,*images,exception);
4496           offset=(ssize_t) StringToLong(argv[1]);
4497           smush_image=SmushImages(*images,*argv[0] == '-' ? MagickTrue :
4498             MagickFalse,offset,exception);
4499           if (smush_image == (Image *) NULL)
4500             {
4501               status=MagickFalse;
4502               break;
4503             }
4504           *images=DestroyImageList(*images);
4505           *images=smush_image;
4506           break;
4507         }
4508       if (LocaleCompare("swap",argv[0]+1) == 0)
4509         {
4510           Image
4511             *p,
4512             *q,
4513             *swap;
4514
4515           ssize_t
4516             swap_index;
4517
4518           index=(-1);
4519           swap_index=(-2);
4520           if (*argv[0] != '+')
4521             {
4522               GeometryInfo
4523                 geometry_info;
4524
4525               MagickStatusType
4526                 flags;
4527
4528               swap_index=(-1);
4529               flags=ParseGeometry(argv[1],&geometry_info);
4530               index=(ssize_t) geometry_info.rho;
4531               if ((flags & SigmaValue) != 0)
4532                 swap_index=(ssize_t) geometry_info.sigma;
4533             }
4534           p=GetImageFromList(*images,index);
4535           q=GetImageFromList(*images,swap_index);
4536           if ((p == (Image *) NULL) || (q == (Image *) NULL))
4537             {
4538               (void) ThrowMagickException(exception,GetMagickModule(),
4539                 OptionError,"NoSuchImage","`%s'",(*images)->filename);
4540               status=MagickFalse;
4541               break;
4542             }
4543           if (p == q)
4544             break;
4545           swap=CloneImage(p,0,0,MagickTrue,exception);
4546           ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,exception));
4547           ReplaceImageInList(&q,swap);
4548           *images=GetFirstImageInList(q);
4549           break;
4550         }
4551       break;
4552     }
4553     case 'w':
4554     {
4555       if (LocaleCompare("write",argv[0]+1) == 0)
4556         {
4557           char
4558             key[MaxTextExtent];
4559
4560           Image
4561             *write_images;
4562
4563           ImageInfo
4564             *write_info;
4565
4566           (void) SyncImagesSettings(image_info,*images,exception);
4567           (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",argv[1]);
4568           (void) DeleteImageRegistry(key);
4569           write_images=(*images);
4570           if (*argv[0] == '+')
4571             write_images=CloneImageList(*images,exception);
4572           write_info=CloneImageInfo(image_info);
4573           status&=WriteImages(write_info,write_images,argv[1],exception);
4574           write_info=DestroyImageInfo(write_info);
4575           if (*argv[0] == '+')
4576             write_images=DestroyImageList(write_images);
4577           break;
4578         }
4579       break;
4580     }
4581     default:
4582       break;
4583   }
4584   quantize_info=DestroyQuantizeInfo(quantize_info);
4585
4586   status=(MagickStatusType) (exception->severity == UndefinedException ? 1 : 0);
4587   return(status != 0 ? MagickTrue : MagickFalse);
4588 }
4589 #endif