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