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