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