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