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