MagickWand 7.1.2-33
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/license/ %
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*MagickSafeReciprocal((double) 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*MagickSafeReciprocal((double) 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-parentheses",option+1) == 0) ||
1319 (LocaleCompare("respect-parenthesis",option+1) == 0))
1320 {
1321 /* link image and setting stacks - option is itself saved on stack! */
1322 (void) SetImageOption(_image_info,"respect-parentheses",
1323 ArgBooleanString);
1324 break;
1325 }
1326 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1327 }
1328 case 's':
1329 {
1330 if (LocaleCompare("sampling-factor",option+1) == 0)
1331 {
1332 /* FUTURE: should be converted to jpeg:sampling_factor */
1333 if (IfSetOption && (IsGeometry(arg1) == MagickFalse))
1334 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1335 (void) CloneString(&_image_info->sampling_factor,ArgOption(NULL));
1336 break;
1337 }
1338 if (LocaleCompare("scene",option+1) == 0)
1339 {
1340 /* SyncImageSettings() used to set this as a per-image attribute.
1341 What ??? Why ????
1342 */
1343 if (IfSetOption && (IsGeometry(arg1) == MagickFalse))
1344 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1345 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1346 _image_info->scene=StringToUnsignedLong(ArgOption("0"));
1347 break;
1348 }
1349 if (LocaleCompare("seed",option+1) == 0)
1350 {
1351 if (IfSetOption && (IsGeometry(arg1) == MagickFalse))
1352 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1353 SetRandomSecretKey(
1354 IfSetOption ? (unsigned long) StringToUnsignedLong(arg1)
1355 : (unsigned long) time((time_t *) NULL));
1356 break;
1357 }
1358 if (LocaleCompare("size",option+1) == 0)
1359 {
1360 /* FUTURE: string in _image_info -- convert to Option ???
1361 Look at the special handling for "size" in SetImageOption()
1362 */
1363 (void) CloneString(&_image_info->size,ArgOption(NULL));
1364 break;
1365 }
1366 if (LocaleCompare("stretch",option+1) == 0)
1367 {
1368 arg1=ArgOption("undefined");
1369 parse = ParseCommandOption(MagickStretchOptions,MagickFalse,arg1);
1370 if (parse < 0)
1371 CLIWandExceptArgBreak(OptionError,"UnrecognizedStretchType",
1372 option,arg1);
1373 _draw_info->stretch=(StretchType) parse;
1374 break;
1375 }
1376 if (LocaleCompare("stroke",option+1) == 0)
1377 {
1378 /* set stroke color OR stroke-pattern
1379 UPDATE: ensure stroke color is not destroyed is a pattern
1380 is given. Just in case the color is also used for other purposes.
1381 */
1382 MagickBooleanType
1383 status;
1384
1385 ExceptionInfo
1386 *sans;
1387
1388 PixelInfo
1389 color;
1390
1391 arg1 = ArgOption("none"); /* +fill turns it off! */
1392 (void) SetImageOption(_image_info,option+1,arg1);
1393 if (_draw_info->stroke_pattern != (Image *) NULL)
1394 _draw_info->stroke_pattern=DestroyImage(_draw_info->stroke_pattern);
1395
1396 /* is it a color or a image? -- ignore exceptions */
1397 sans=AcquireExceptionInfo();
1398 status=QueryColorCompliance(arg1,AllCompliance,&color,sans);
1399 sans=DestroyExceptionInfo(sans);
1400
1401 if (status == MagickFalse)
1402 _draw_info->stroke_pattern=GetImageCache(_image_info,arg1,_exception);
1403 else
1404 _draw_info->stroke=color;
1405 break;
1406 }
1407 if (LocaleCompare("strokewidth",option+1) == 0)
1408 {
1409 if (IfSetOption && (IsGeometry(arg1) == MagickFalse))
1410 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1411 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1412 _draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1413 (char **) NULL);
1414 break;
1415 }
1416 if (LocaleCompare("style",option+1) == 0)
1417 {
1418 arg1=ArgOption("undefined");
1419 parse = ParseCommandOption(MagickStyleOptions,MagickFalse,arg1);
1420 if (parse < 0)
1421 CLIWandExceptArgBreak(OptionError,"UnrecognizedStyleType",
1422 option,arg1);
1423 _draw_info->style=(StyleType) parse;
1424 break;
1425 }
1426#if 0
1427 if (LocaleCompare("subimage-search",option+1) == 0)
1428 {
1429 /* FUTURE: this is only used by CompareImages() which is used
1430 only by the "compare" CLI program at this time. */
1431 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1432 break;
1433 }
1434#endif
1435 if (LocaleCompare("synchronize",option+1) == 0)
1436 {
1437 /* FUTURE: synchronize to storage - but what does that mean? */
1438 _image_info->synchronize = ArgBoolean;
1439 break;
1440 }
1441 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1442 }
1443 case 't':
1444 {
1445 if (LocaleCompare("taint",option+1) == 0)
1446 {
1447 /* SyncImageSettings() used to set per-image attribute. */
1448 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1449 break;
1450 }
1451 if (LocaleCompare("texture",option+1) == 0)
1452 {
1453 /* Note: arguments do not have percent escapes expanded */
1454 /* FUTURE: move _image_info string to option splay-tree
1455 Other than "montage" what uses "texture" ????
1456 */
1457 (void) CloneString(&_image_info->texture,ArgOption(NULL));
1458 break;
1459 }
1460 if (LocaleCompare("tile",option+1) == 0)
1461 {
1462 /* Note: arguments do not have percent escapes expanded */
1463 _draw_info->fill_pattern=IfSetOption
1464 ?GetImageCache(_image_info,arg1,_exception)
1465 :DestroyImage(_draw_info->fill_pattern);
1466 break;
1467 }
1468 if (LocaleCompare("tile-offset",option+1) == 0)
1469 {
1470 /* SyncImageSettings() used to set per-image attribute. ??? */
1471 arg1=ArgOption("0");
1472 if (IsGeometry(arg1) == MagickFalse)
1473 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1474 (void) SetImageOption(_image_info,option+1,arg1);
1475 break;
1476 }
1477 if (LocaleCompare("transparent-color",option+1) == 0)
1478 {
1479 /* FUTURE: both _image_info attribute & ImageOption in use!
1480 _image_info only used for generating new images.
1481 SyncImageSettings() used to set per-image attribute.
1482
1483 Note that +transparent-color, means fall-back to image
1484 attribute so ImageOption is deleted, not set to a default.
1485 */
1486 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1487 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1488 &_image_info->transparent_color,_exception);
1489 break;
1490 }
1491 if (LocaleCompare("treedepth",option+1) == 0)
1492 {
1493 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1494 _quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1495 break;
1496 }
1497 if (LocaleCompare("type",option+1) == 0)
1498 {
1499 /* SyncImageSettings() used to set per-image attribute. */
1500 parse=ParseCommandOption(MagickTypeOptions,MagickFalse,
1501 ArgOption("undefined"));
1502 if (parse < 0)
1503 CLIWandExceptArgBreak(OptionError,"UnrecognizedImageType",
1504 option,arg1);
1505 _image_info->type=(ImageType) parse;
1506 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1507 break;
1508 }
1509 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1510 }
1511 case 'u':
1512 {
1513 if (LocaleCompare("undercolor",option+1) == 0)
1514 {
1515 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1516 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1517 &_draw_info->undercolor,_exception);
1518 break;
1519 }
1520 if (LocaleCompare("units",option+1) == 0)
1521 {
1522 /* SyncImageSettings() used to set per-image attribute.
1523 Should this effect _draw_info X and Y resolution?
1524 FUTURE: this probably should be part of the density setting
1525 */
1526 parse=ParseCommandOption(MagickResolutionOptions,MagickFalse,
1527 ArgOption("undefined"));
1528 if (parse < 0)
1529 CLIWandExceptArgBreak(OptionError,"UnrecognizedUnitsType",
1530 option,arg1);
1531 _image_info->units=(ResolutionType) parse;
1532 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1533 break;
1534 }
1535 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1536 }
1537 case 'v':
1538 {
1539 if (LocaleCompare("verbose",option+1) == 0)
1540 {
1541 /* FUTURE: Remember all options become image artifacts
1542 _image_info->verbose is only used by coders.
1543 */
1544 (void) SetImageOption(_image_info,option+1,ArgBooleanString);
1545 _image_info->verbose= ArgBoolean;
1546 _image_info->ping=MagickFalse; /* verbose can't be a ping */
1547 break;
1548 }
1549 if (LocaleCompare("virtual-pixel",option+1) == 0)
1550 {
1551 /* SyncImageSettings() used to set per-image attribute.
1552 This is VERY deep in the image caching structure.
1553 */
1554 parse=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
1555 ArgOption("undefined"));
1556 if (parse < 0)
1557 CLIWandExceptArgBreak(OptionError,"UnrecognizedVirtualPixelMethod",
1558 option,arg1);
1559 (void) SetImageOption(_image_info,option+1,ArgOption(NULL));
1560 break;
1561 }
1562 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1563 }
1564 case 'w':
1565 {
1566 if (LocaleCompare("weight",option+1) == 0)
1567 {
1568 ssize_t
1569 weight;
1570
1571 weight=ParseCommandOption(MagickWeightOptions,MagickFalse,arg1);
1572 if (weight == -1)
1573 weight=(ssize_t) StringToUnsignedLong(arg1);
1574 _draw_info->weight=(size_t) weight;
1575 break;
1576 }
1577 if (LocaleCompare("white-point",option+1) == 0)
1578 {
1579 /* Used as a image chromaticity setting
1580 SyncImageSettings() used to set per-image attribute.
1581 */
1582 arg1=ArgOption("0.0");
1583 if (IsGeometry(arg1) == MagickFalse)
1584 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1585 (void) SetImageOption(_image_info,option+1,arg1);
1586 break;
1587 }
1588 if (LocaleCompare("word-break",option+1) == 0)
1589 {
1590 parse=ParseCommandOption(MagickWordBreakOptions,MagickFalse,
1591 ArgOption("undefined"));
1592 if (parse < 0)
1593 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1594 (void) SetImageOption(_image_info,option+1, ArgOption(NULL));
1595 break;
1596 }
1597 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1598 }
1599 default:
1600 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1601 }
1602
1603 /* clean up percent escape interpreted strings */
1604 if ((arg1 && arg1n) && (arg1 != arg1n ))
1605 arg1=DestroyString((char *) arg1);
1606 if ((arg2 && arg2n) && (arg2 != arg2n ))
1607 arg2=DestroyString((char *) arg2);
1608
1609#undef _image_info
1610#undef _exception
1611#undef _draw_info
1612#undef _quantize_info
1613#undef IfSetOption
1614#undef ArgBoolean
1615#undef ArgBooleanNot
1616#undef ArgBooleanString
1617#undef ArgOption
1618
1619 return;
1620}
1621␌
1622/*
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624% %
1625% %
1626% %
1627+ C L I S i m p l e O p e r a t o r I m a g e s %
1628% %
1629% %
1630% %
1631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632%
1633% CLISimpleOperatorImages() applies one simple image operation given to all
1634% the images in the CLI wand, using any per-image or global settings that was
1635% previously saved in the CLI wand.
1636%
1637% It is assumed that any such settings are up-to-date.
1638%
1639% The format of the WandSimpleOperatorImages method is:
1640%
1641% MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,const char *option,
1642% const char *arg1, const char *arg2,ExceptionInfo *exception)
1643%
1644% A description of each parameter follows:
1645%
1646% o cli_wand: structure holding settings and images to be operated on
1647%
1648% o option: The option string for the operation
1649%
1650% o arg1, arg2: optional argument strings to the operation
1651%
1652*/
1653
1654/*
1655 CLISimpleOperatorImage() is an Internal subrountine to apply one simple
1656 image operation to the current image pointed to by the CLI wand.
1657
1658 The image in the list may be modified in three different ways...
1659 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1660 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1661 * one image replace by a list of images (-separate and -crop only!)
1662
1663 In each case the result replaces the single original image in the list, as
1664 well as the pointer to the modified image (last image added if replaced by a
1665 list of images) is returned.
1666
1667 As the image pointed to may be replaced, the first image in the list may
1668 also change. GetFirstImageInList() should be used by caller if they wish
1669 return the Image pointer to the first image in list.
1670*/
1671static MagickBooleanType CLISimpleOperatorImage(MagickCLI *cli_wand,
1672 const char *option, const char *arg1n, const char *arg2n,
1673 ExceptionInfo *exception)
1674{
1675 Image *
1676 new_image;
1677
1678 GeometryInfo
1679 geometry_info;
1680
1681 RectangleInfo
1682 geometry;
1683
1684 MagickStatusType
1685 flags;
1686
1687 ssize_t
1688 parse;
1689
1690 const char /* percent escaped versions of the args */
1691 *arg1,
1692 *arg2;
1693
1694#define _image_info (cli_wand->wand.image_info)
1695#define _image (cli_wand->wand.images)
1696#define _exception (cli_wand->wand.exception)
1697#define _draw_info (cli_wand->draw_info)
1698#define _quantize_info (cli_wand->quantize_info)
1699#define _process_flags (cli_wand->process_flags)
1700#define _option_type ((CommandOptionFlags) cli_wand->command->flags)
1701#define IfNormalOp (*option=='-')
1702#define IfPlusOp (*option!='-')
1703#define IsNormalOp IfNormalOp ? MagickTrue : MagickFalse
1704#define IsPlusOp IfNormalOp ? MagickFalse : MagickTrue
1705
1706 assert(cli_wand != (MagickCLI *) NULL);
1707 assert(cli_wand->signature == MagickWandSignature);
1708 assert(cli_wand->wand.signature == MagickWandSignature);
1709 assert(_image != (Image *) NULL); /* an image must be present */
1710 if (cli_wand->wand.debug != MagickFalse)
1711 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
1712
1713 arg1 = arg1n,
1714 arg2 = arg2n;
1715
1716 /* Interpret Percent Escapes in Arguments - using first image */
1717 if ( (((_process_flags & ProcessInterpretProperties) != 0 )
1718 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
1719 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
1720 /* Interpret Percent escapes in argument 1 */
1721 if (arg1n != (char *) NULL) {
1722 arg1=InterpretImageProperties(_image_info,_image,arg1n,_exception);
1723 if (arg1 == (char *) NULL) {
1724 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1725 arg1=arg1n; /* use the given argument as is */
1726 }
1727 }
1728 if (arg2n != (char *) NULL) {
1729 arg2=InterpretImageProperties(_image_info,_image,arg2n,_exception);
1730 if (arg2 == (char *) NULL) {
1731 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
1732 arg2=arg2n; /* use the given argument as is */
1733 }
1734 }
1735 }
1736#undef _process_flags
1737#undef _option_type
1738
1739#if 0
1740 (void) FormatLocaleFile(stderr,
1741 "CLISimpleOperatorImage: \"%s\" \"%s\" \"%s\"\n",option,arg1,arg2);
1742#endif
1743
1744 new_image = (Image *) NULL; /* the replacement image, if not null at end */
1745 SetGeometryInfo(&geometry_info);
1746
1747 switch (*(option+1))
1748 {
1749 case 'a':
1750 {
1751 if (LocaleCompare("adaptive-blur",option+1) == 0)
1752 {
1753 flags=ParseGeometry(arg1,&geometry_info);
1754 if ((flags & (RhoValue|SigmaValue)) == 0)
1755 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1756 if ((flags & SigmaValue) == 0)
1757 geometry_info.sigma=1.0;
1758 new_image=AdaptiveBlurImage(_image,geometry_info.rho,
1759 geometry_info.sigma,_exception);
1760 break;
1761 }
1762 if (LocaleCompare("adaptive-resize",option+1) == 0)
1763 {
1764 /* FUTURE: Roll into a resize special operator */
1765 if (IsGeometry(arg1) == MagickFalse)
1766 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1767 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
1768 new_image=AdaptiveResizeImage(_image,geometry.width,geometry.height,
1769 _exception);
1770 break;
1771 }
1772 if (LocaleCompare("adaptive-sharpen",option+1) == 0)
1773 {
1774 flags=ParseGeometry(arg1,&geometry_info);
1775 if ((flags & (RhoValue|SigmaValue)) == 0)
1776 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1777 if ((flags & SigmaValue) == 0)
1778 geometry_info.sigma=1.0;
1779 new_image=AdaptiveSharpenImage(_image,geometry_info.rho,
1780 geometry_info.sigma,_exception);
1781 break;
1782 }
1783 if (LocaleCompare("alpha",option+1) == 0)
1784 {
1785 parse=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,arg1);
1786 if (parse < 0)
1787 CLIWandExceptArgBreak(OptionError,"UnrecognizedAlphaChannelOption",
1788 option,arg1);
1789 (void) SetImageAlphaChannel(_image,(AlphaChannelOption) parse,
1790 _exception);
1791 break;
1792 }
1793 if (LocaleCompare("annotate",option+1) == 0)
1794 {
1795 char
1796 buffer[MagickPathExtent];
1797
1798 SetGeometryInfo(&geometry_info);
1799 flags=ParseGeometry(arg1,&geometry_info);
1800 if (flags == 0)
1801 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1802 if ((flags & SigmaValue) == 0)
1803 geometry_info.sigma=geometry_info.rho;
1804 (void) CloneString(&_draw_info->text,arg2);
1805 (void) FormatLocaleString(buffer,MagickPathExtent,"%+f%+f",
1806 geometry_info.xi,geometry_info.psi);
1807 (void) CloneString(&_draw_info->geometry,buffer);
1808 _draw_info->affine.sx=cos(DegreesToRadians(
1809 fmod(geometry_info.rho,360.0)));
1810 _draw_info->affine.rx=sin(DegreesToRadians(
1811 fmod(geometry_info.rho,360.0)));
1812 _draw_info->affine.ry=(-sin(DegreesToRadians(
1813 fmod(geometry_info.sigma,360.0))));
1814 _draw_info->affine.sy=cos(DegreesToRadians(
1815 fmod(geometry_info.sigma,360.0)));
1816 (void) AnnotateImage(_image,_draw_info,_exception);
1817 GetAffineMatrix(&_draw_info->affine);
1818 break;
1819 }
1820 if (LocaleCompare("auto-gamma",option+1) == 0)
1821 {
1822 (void) AutoGammaImage(_image,_exception);
1823 break;
1824 }
1825 if (LocaleCompare("auto-level",option+1) == 0)
1826 {
1827 (void) AutoLevelImage(_image,_exception);
1828 break;
1829 }
1830 if (LocaleCompare("auto-orient",option+1) == 0)
1831 {
1832 new_image=AutoOrientImage(_image,_image->orientation,_exception);
1833 break;
1834 }
1835 if (LocaleCompare("auto-threshold",option+1) == 0)
1836 {
1837 AutoThresholdMethod
1838 method;
1839
1840 method=(AutoThresholdMethod) ParseCommandOption(
1841 MagickAutoThresholdOptions,MagickFalse,arg1);
1842 (void) AutoThresholdImage(_image,method,_exception);
1843 break;
1844 }
1845 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1846 }
1847 case 'b':
1848 {
1849 if (LocaleCompare("bilateral-blur",option+1) == 0)
1850 {
1851 flags=ParseGeometry(arg1,&geometry_info);
1852 if ((flags & (RhoValue|SigmaValue)) == 0)
1853 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1854 if ((flags & SigmaValue) == 0)
1855 geometry_info.sigma=geometry_info.rho;
1856 if ((flags & XiValue) == 0)
1857 geometry_info.xi=1.0*sqrt(geometry_info.rho*geometry_info.rho+
1858 geometry_info.sigma*geometry_info.sigma);
1859 if ((flags & PsiValue) == 0)
1860 geometry_info.psi=0.25*sqrt(geometry_info.rho*geometry_info.rho+
1861 geometry_info.sigma*geometry_info.sigma);
1862 new_image=BilateralBlurImage(_image,(size_t) geometry_info.rho,
1863 (size_t) geometry_info.sigma,geometry_info.xi,geometry_info.psi,
1864 _exception);
1865 break;
1866 }
1867 if (LocaleCompare("black-threshold",option+1) == 0)
1868 {
1869 if (IsGeometry(arg1) == MagickFalse)
1870 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1871 (void) BlackThresholdImage(_image,arg1,_exception);
1872 break;
1873 }
1874 if (LocaleCompare("blue-shift",option+1) == 0)
1875 {
1876 geometry_info.rho=1.5;
1877 if (IfNormalOp) {
1878 flags=ParseGeometry(arg1,&geometry_info);
1879 if ((flags & RhoValue) == 0)
1880 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1881 }
1882 new_image=BlueShiftImage(_image,geometry_info.rho,_exception);
1883 break;
1884 }
1885 if (LocaleCompare("blur",option+1) == 0)
1886 {
1887 flags=ParseGeometry(arg1,&geometry_info);
1888 if ((flags & (RhoValue|SigmaValue)) == 0)
1889 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1890 if ((flags & SigmaValue) == 0)
1891 geometry_info.sigma=1.0;
1892 new_image=BlurImage(_image,geometry_info.rho,geometry_info.sigma,
1893 _exception);
1894 break;
1895 }
1896 if (LocaleCompare("border",option+1) == 0)
1897 {
1898 CompositeOperator
1899 compose;
1900
1901 const char*
1902 value;
1903
1904 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
1905 if ((flags & (WidthValue | HeightValue)) == 0)
1906 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1907 compose=OverCompositeOp;
1908 value=GetImageOption(_image_info,"compose");
1909 if (value != (const char *) NULL)
1910 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
1911 MagickFalse,value);
1912 new_image=BorderImage(_image,&geometry,compose,_exception);
1913 break;
1914 }
1915 if (LocaleCompare("brightness-contrast",option+1) == 0)
1916 {
1917 double
1918 brightness,
1919 contrast;
1920
1921 flags=ParseGeometry(arg1,&geometry_info);
1922 if ((flags & RhoValue) == 0)
1923 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1924 brightness=geometry_info.rho;
1925 contrast=0.0;
1926 if ((flags & SigmaValue) != 0)
1927 contrast=geometry_info.sigma;
1928 (void) BrightnessContrastImage(_image,brightness,contrast,
1929 _exception);
1930 break;
1931 }
1932 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
1933 }
1934 case 'c':
1935 {
1936 if (LocaleCompare("canny",option+1) == 0)
1937 {
1938 flags=ParseGeometry(arg1,&geometry_info);
1939 if ((flags & (RhoValue|SigmaValue)) == 0)
1940 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1941 if ((flags & SigmaValue) == 0)
1942 geometry_info.sigma=1.0;
1943 if ((flags & XiValue) == 0)
1944 geometry_info.xi=10;
1945 if ((flags & PsiValue) == 0)
1946 geometry_info.psi=30;
1947 if ((flags & PercentValue) != 0)
1948 {
1949 geometry_info.xi/=100.0;
1950 geometry_info.psi/=100.0;
1951 }
1952 new_image=CannyEdgeImage(_image,geometry_info.rho,geometry_info.sigma,
1953 geometry_info.xi,geometry_info.psi,_exception);
1954 break;
1955 }
1956 if (LocaleCompare("cdl",option+1) == 0)
1957 {
1958 char
1959 *color_correction_collection; /* Note: arguments do not have percent escapes expanded */
1960
1961 /*
1962 Color correct with a color decision list.
1963 */
1964 color_correction_collection=FileToString(arg1,~0UL,_exception);
1965 if (color_correction_collection == (char *) NULL)
1966 break;
1967 (void) ColorDecisionListImage(_image,color_correction_collection,
1968 _exception);
1969 color_correction_collection=DestroyString(color_correction_collection);
1970 break;
1971 }
1972 if (LocaleCompare("channel",option+1) == 0)
1973 {
1974 if (IfPlusOp)
1975 {
1976 (void) SetPixelChannelMask(_image,DefaultChannels);
1977 break;
1978 }
1979 parse=ParseChannelOption(arg1);
1980 if (parse < 0)
1981 CLIWandExceptArgBreak(OptionError,"UnrecognizedChannelType",option,
1982 arg1);
1983 (void) SetPixelChannelMask(_image,(ChannelType) parse);
1984 break;
1985 }
1986 if (LocaleCompare("charcoal",option+1) == 0)
1987 {
1988 flags=ParseGeometry(arg1,&geometry_info);
1989 if ((flags & (RhoValue|SigmaValue)) == 0)
1990 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
1991 if ((flags & SigmaValue) == 0)
1992 geometry_info.sigma=1.0;
1993 if ((flags & XiValue) == 0)
1994 geometry_info.xi=1.0;
1995 new_image=CharcoalImage(_image,geometry_info.rho,geometry_info.sigma,
1996 _exception);
1997 break;
1998 }
1999 if (LocaleCompare("chop",option+1) == 0)
2000 {
2001 if (IsGeometry(arg1) == MagickFalse)
2002 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2003 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
2004 new_image=ChopImage(_image,&geometry,_exception);
2005 break;
2006 }
2007 if (LocaleCompare("clahe",option+1) == 0)
2008 {
2009 if (IsGeometry(arg1) == MagickFalse)
2010 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2011 flags=ParseGeometry(arg1,&geometry_info);
2012 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2013 (void) CLAHEImage(_image,geometry.width,geometry.height,
2014 (size_t) geometry.x,geometry_info.psi,_exception);
2015 break;
2016 }
2017 if (LocaleCompare("clamp",option+1) == 0)
2018 {
2019 (void) ClampImage(_image,_exception);
2020 break;
2021 }
2022 if (LocaleCompare("clip",option+1) == 0)
2023 {
2024 if (IfNormalOp)
2025 (void) ClipImage(_image,_exception);
2026 else /* "+mask" remove the write mask */
2027 (void) SetImageMask(_image,WritePixelMask,(const Image *) NULL,
2028 _exception);
2029 break;
2030 }
2031 if (LocaleCompare("clip-mask",option+1) == 0)
2032 {
2033 Image
2034 *clip_mask;
2035
2036 if (IfPlusOp) {
2037 /* use "+clip-mask" Remove the write mask for -clip-path */
2038 (void) SetImageMask(_image,WritePixelMask,(const Image *) NULL,
2039 _exception);
2040 break;
2041 }
2042 clip_mask=GetImageCache(_image_info,arg1,_exception);
2043 if (clip_mask == (Image *) NULL)
2044 break;
2045 (void) SetImageMask(_image,WritePixelMask,clip_mask,_exception);
2046 clip_mask=DestroyImage(clip_mask);
2047 break;
2048 }
2049 if (LocaleCompare("clip-path",option+1) == 0)
2050 {
2051 (void) ClipImagePath(_image,arg1,IsNormalOp,_exception);
2052 /* Note: Use "+clip-mask" remove the write mask added */
2053 break;
2054 }
2055 if (LocaleCompare("colorize",option+1) == 0)
2056 {
2057 if (IsGeometry(arg1) == MagickFalse)
2058 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2059 new_image=ColorizeImage(_image,arg1,&_draw_info->fill,_exception);
2060 break;
2061 }
2062 if (LocaleCompare("color-matrix",option+1) == 0)
2063 {
2064 KernelInfo
2065 *kernel;
2066
2067 kernel=AcquireKernelInfo(arg1,exception);
2068 if (kernel == (KernelInfo *) NULL)
2069 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2070 new_image=ColorMatrixImage(_image,kernel,_exception);
2071 kernel=DestroyKernelInfo(kernel);
2072 break;
2073 }
2074 if (LocaleCompare("colors",option+1) == 0)
2075 {
2076 /* Reduce the number of colors in the image.
2077 FUTURE: also provide 'plus version with image 'color counts'
2078 */
2079 _quantize_info->number_colors=StringToUnsignedLong(arg1);
2080 _quantize_info->measure_error=_image_info->verbose;
2081 if (_quantize_info->number_colors == 0)
2082 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2083 if ((_image->storage_class == DirectClass) ||
2084 _image->colors > _quantize_info->number_colors)
2085 (void) QuantizeImage(_quantize_info,_image,_exception);
2086 else
2087 (void) CompressImageColormap(_image,_exception);
2088 break;
2089 }
2090 if (LocaleCompare("colorspace",option+1) == 0)
2091 {
2092 /* WARNING: this is both a image_info setting (already done)
2093 and a operator to change image colorspace.
2094
2095 FUTURE: default colorspace should be sRGB!
2096 Unless some type of 'linear colorspace' mode is set.
2097
2098 Note that +colorspace sets "undefined" or no effect on
2099 new images, but forces images already in memory back to RGB!
2100 That seems to be a little strange!
2101 */
2102 (void) TransformImageColorspace(_image,
2103 IfNormalOp ? _image_info->colorspace : sRGBColorspace,
2104 _exception);
2105 break;
2106 }
2107 if (LocaleCompare("color-threshold",option+1) == 0)
2108 {
2109 PixelInfo
2110 start,
2111 stop;
2112
2113 /*
2114 Color threshold image.
2115 */
2116 if (*option == '+')
2117 (void) GetColorRange("white-black",&start,&stop,_exception);
2118 else
2119 (void) GetColorRange(arg1,&start,&stop,_exception);
2120 (void) ColorThresholdImage(_image,&start,&stop,_exception);
2121 break;
2122 }
2123 if (LocaleCompare("connected-components",option+1) == 0)
2124 {
2125 if (IsGeometry(arg1) == MagickFalse)
2126 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2127 new_image=ConnectedComponentsImage(_image,(size_t)
2128 StringToInteger(arg1),(CCObjectInfo **) NULL,_exception);
2129 break;
2130 }
2131 if (LocaleCompare("contrast",option+1) == 0)
2132 {
2133 CLIWandWarnReplaced(IfNormalOp?"-level":"+level");
2134 (void) ContrastImage(_image,IsNormalOp,_exception);
2135 break;
2136 }
2137 if (LocaleCompare("contrast-stretch",option+1) == 0)
2138 {
2139 double
2140 black_point,
2141 white_point;
2142
2143 flags=ParseGeometry(arg1,&geometry_info);
2144 if ((flags & RhoValue) == 0)
2145 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2146 black_point=geometry_info.rho;
2147 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2148 black_point;
2149 if ((flags & PercentValue) != 0)
2150 {
2151 black_point*=(double) _image->columns*_image->rows/100.0;
2152 white_point*=(double) _image->columns*_image->rows/100.0;
2153 }
2154 white_point=(double) _image->columns*_image->rows-white_point;
2155 (void) ContrastStretchImage(_image,black_point,white_point,
2156 _exception);
2157 break;
2158 }
2159 if (LocaleCompare("convolve",option+1) == 0)
2160 {
2161 double
2162 gamma;
2163
2164 KernelInfo
2165 *kernel_info;
2166
2167 ssize_t
2168 j;
2169
2170 kernel_info=AcquireKernelInfo(arg1,exception);
2171 if (kernel_info == (KernelInfo *) NULL)
2172 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2173 gamma=0.0;
2174 for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2175 gamma+=kernel_info->values[j];
2176 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
2177 for (j=0; j < (ssize_t) (kernel_info->width*kernel_info->height); j++)
2178 kernel_info->values[j]*=gamma;
2179 new_image=MorphologyImage(_image,CorrelateMorphology,1,kernel_info,
2180 _exception);
2181 kernel_info=DestroyKernelInfo(kernel_info);
2182 break;
2183 }
2184 if (LocaleCompare("crop",option+1) == 0)
2185 {
2186 /* WARNING: This can generate multiple images! */
2187 if (IsGeometry(arg1) == MagickFalse)
2188 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2189 new_image=CropImageToTiles(_image,arg1,_exception);
2190 break;
2191 }
2192 if (LocaleCompare("cycle",option+1) == 0)
2193 {
2194 if (IsGeometry(arg1) == MagickFalse)
2195 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2196 (void) CycleColormapImage(_image,(ssize_t) StringToLong(arg1),
2197 _exception);
2198 break;
2199 }
2200 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2201 }
2202 case 'd':
2203 {
2204 if (LocaleCompare("decipher",option+1) == 0)
2205 {
2206 /* Note: arguments do not have percent escapes expanded */
2207 StringInfo
2208 *passkey;
2209
2210 passkey=FileToStringInfo(arg1,~0UL,_exception);
2211 if (passkey == (StringInfo *) NULL)
2212 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2213
2214 (void) PasskeyDecipherImage(_image,passkey,_exception);
2215 passkey=DestroyStringInfo(passkey);
2216 break;
2217 }
2218 if (LocaleCompare("depth",option+1) == 0)
2219 {
2220 /* The _image_info->depth setting has already been set
2221 We just need to apply it to all images in current sequence
2222
2223 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2224 That is it really is an operation, not a setting! Arrgghhh
2225
2226 FUTURE: this should not be an operator!!!
2227 */
2228 (void) SetImageDepth(_image,_image_info->depth,_exception);
2229 break;
2230 }
2231 if (LocaleCompare("deskew",option+1) == 0)
2232 {
2233 double
2234 threshold;
2235
2236 if (IfNormalOp) {
2237 if (IsGeometry(arg1) == MagickFalse)
2238 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2239 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
2240 }
2241 else
2242 threshold=40.0*(double) QuantumRange/100.0;
2243 new_image=DeskewImage(_image,threshold,_exception);
2244 break;
2245 }
2246 if (LocaleCompare("despeckle",option+1) == 0)
2247 {
2248 new_image=DespeckleImage(_image,_exception);
2249 break;
2250 }
2251 if (LocaleCompare("distort",option+1) == 0)
2252 {
2253 double
2254 *args;
2255
2256 ssize_t
2257 count;
2258
2259 parse = ParseCommandOption(MagickDistortOptions,MagickFalse,arg1);
2260 if ( parse < 0 )
2261 CLIWandExceptArgBreak(OptionError,"UnrecognizedDistortMethod",
2262 option,arg1);
2263 if ((DistortMethod) parse == ResizeDistortion)
2264 {
2265 double
2266 resize_args[2];
2267 /* Special Case - Argument is actually a resize geometry!
2268 ** Convert that to an appropriate distortion argument array.
2269 ** FUTURE: make a separate special resize operator
2270 Roll into a resize special operator */
2271 if (IsGeometry(arg2) == MagickFalse)
2272 CLIWandExceptArgBreak(OptionError,"InvalidGeometry",
2273 option,arg2);
2274 (void) ParseRegionGeometry(_image,arg2,&geometry,_exception);
2275 resize_args[0]=(double) geometry.width;
2276 resize_args[1]=(double) geometry.height;
2277 new_image=DistortImage(_image,(DistortMethod) parse,
2278 (size_t)2,resize_args,MagickTrue,_exception);
2279 break;
2280 }
2281 /* convert argument string into an array of doubles */
2282 args = StringToArrayOfDoubles(arg2,&count,_exception);
2283 if (args == (double *) NULL )
2284 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2285
2286 new_image=DistortImage(_image,(DistortMethod) parse,(size_t)
2287 count,args,IsPlusOp,_exception);
2288 args=(double *) RelinquishMagickMemory(args);
2289 break;
2290 }
2291 if (LocaleCompare("draw",option+1) == 0)
2292 {
2293 (void) CloneString(&_draw_info->primitive,arg1);
2294 (void) DrawImage(_image,_draw_info,_exception);
2295 (void) CloneString(&_draw_info->primitive,(char *) NULL);
2296 break;
2297 }
2298 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2299 }
2300 case 'e':
2301 {
2302 if (LocaleCompare("edge",option+1) == 0)
2303 {
2304 flags=ParseGeometry(arg1,&geometry_info);
2305 if ((flags & (RhoValue|SigmaValue)) == 0)
2306 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2307 new_image=EdgeImage(_image,geometry_info.rho,_exception);
2308 break;
2309 }
2310 if (LocaleCompare("emboss",option+1) == 0)
2311 {
2312 flags=ParseGeometry(arg1,&geometry_info);
2313 if ((flags & (RhoValue|SigmaValue)) == 0)
2314 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2315 if ((flags & SigmaValue) == 0)
2316 geometry_info.sigma=1.0;
2317 new_image=EmbossImage(_image,geometry_info.rho,
2318 geometry_info.sigma,_exception);
2319 break;
2320 }
2321 if (LocaleCompare("encipher",option+1) == 0)
2322 {
2323 /* Note: arguments do not have percent escapes expanded */
2324 StringInfo
2325 *passkey;
2326
2327 passkey=FileToStringInfo(arg1,~0UL,_exception);
2328 if (passkey != (StringInfo *) NULL)
2329 {
2330 (void) PasskeyEncipherImage(_image,passkey,_exception);
2331 passkey=DestroyStringInfo(passkey);
2332 }
2333 break;
2334 }
2335 if (LocaleCompare("enhance",option+1) == 0)
2336 {
2337 new_image=EnhanceImage(_image,_exception);
2338 break;
2339 }
2340 if (LocaleCompare("equalize",option+1) == 0)
2341 {
2342 (void) EqualizeImage(_image,_exception);
2343 break;
2344 }
2345 if (LocaleCompare("evaluate",option+1) == 0)
2346 {
2347 double
2348 constant;
2349
2350 parse = ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
2351 if ( parse < 0 )
2352 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
2353 option,arg1);
2354 if (IsGeometry(arg2) == MagickFalse)
2355 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
2356 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
2357 (void) EvaluateImage(_image,(MagickEvaluateOperator)parse,constant,
2358 _exception);
2359 break;
2360 }
2361 if (LocaleCompare("extent",option+1) == 0)
2362 {
2363 if (IsGeometry(arg1) == MagickFalse)
2364 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2365 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
2366 if (geometry.width == 0)
2367 geometry.width=_image->columns;
2368 if (geometry.height == 0)
2369 geometry.height=_image->rows;
2370 new_image=ExtentImage(_image,&geometry,_exception);
2371 break;
2372 }
2373 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2374 }
2375 case 'f':
2376 {
2377 if (LocaleCompare("features",option+1) == 0)
2378 {
2379 CLIWandWarnReplaced("-verbose -define identify:features=");
2380 if (*option == '+')
2381 {
2382 (void) DeleteImageArtifact(_image,"identify:features");
2383 break;
2384 }
2385 (void) SetImageArtifact(_image,"identify:features",arg1);
2386 (void) SetImageArtifact(_image,"verbose","true");
2387 break;
2388 }
2389 if (LocaleCompare("flip",option+1) == 0)
2390 {
2391 new_image=FlipImage(_image,_exception);
2392 break;
2393 }
2394 if (LocaleCompare("flop",option+1) == 0)
2395 {
2396 new_image=FlopImage(_image,_exception);
2397 break;
2398 }
2399 if (LocaleCompare("floodfill",option+1) == 0)
2400 {
2401 PixelInfo
2402 target;
2403
2404 if (IsGeometry(arg1) == MagickFalse)
2405 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2406 (void) ParsePageGeometry(_image,arg1,&geometry,_exception);
2407 (void) QueryColorCompliance(arg2,AllCompliance,&target,_exception);
2408 (void) FloodfillPaintImage(_image,_draw_info,&target,geometry.x,
2409 geometry.y,IsPlusOp,_exception);
2410 break;
2411 }
2412 if (LocaleCompare("frame",option+1) == 0)
2413 {
2414 FrameInfo
2415 frame_info;
2416
2417 CompositeOperator
2418 compose;
2419
2420 const char*
2421 value;
2422
2423 value=GetImageOption(_image_info,"compose");
2424 compose=OverCompositeOp; /* use Over not _image->compose */
2425 if (value != (const char *) NULL)
2426 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
2427 MagickFalse,value);
2428 if (IsGeometry(arg1) == MagickFalse)
2429 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2430 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
2431 frame_info.width=geometry.width;
2432 frame_info.height=geometry.height;
2433 frame_info.outer_bevel=geometry.x;
2434 frame_info.inner_bevel=geometry.y;
2435 frame_info.x=(ssize_t) frame_info.width;
2436 frame_info.y=(ssize_t) frame_info.height;
2437 frame_info.width=_image->columns+2*frame_info.width;
2438 frame_info.height=_image->rows+2*frame_info.height;
2439 new_image=FrameImage(_image,&frame_info,compose,_exception);
2440 break;
2441 }
2442 if (LocaleCompare("function",option+1) == 0)
2443 {
2444 double
2445 *args;
2446
2447 ssize_t
2448 count;
2449
2450 parse=ParseCommandOption(MagickFunctionOptions,MagickFalse,arg1);
2451 if ( parse < 0 )
2452 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",
2453 option,arg1);
2454 /* convert argument string into an array of doubles */
2455 args = StringToArrayOfDoubles(arg2,&count,_exception);
2456 if (args == (double *) NULL )
2457 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg2);
2458
2459 (void) FunctionImage(_image,(MagickFunction)parse,(size_t) count,args,
2460 _exception);
2461 args=(double *) RelinquishMagickMemory(args);
2462 break;
2463 }
2464 if (LocaleCompare("fx",option+1) == 0)
2465 {
2466 new_image=FxImage(_image,arg1,_exception);
2467 break;
2468 }
2469 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2470 }
2471 case 'g':
2472 {
2473 if (LocaleCompare("gamma",option+1) == 0)
2474 {
2475 double
2476 constant;
2477
2478 if (IsGeometry(arg1) == MagickFalse)
2479 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2480 constant=StringToDouble(arg1,(char **) NULL);
2481#if 0
2482 /* Using Gamma, via a cache */
2483 if (IfPlusOp)
2484 constant=MagickSafeReciprocal(constant);
2485 (void) GammaImage(_image,constant,_exception);
2486#else
2487 /* Using Evaluate POW, direct update of values - more accurate */
2488 if (IfNormalOp)
2489 constant=MagickSafeReciprocal(constant);
2490 (void) EvaluateImage(_image,PowEvaluateOperator,constant,_exception);
2491 _image->gamma*=StringToDouble(arg1,(char **) NULL);
2492#endif
2493 /* Set gamma setting -- Old meaning of "+gamma"
2494 * _image->gamma=StringToDouble(arg1,(char **) NULL);
2495 */
2496 break;
2497 }
2498 if (LocaleCompare("gaussian-blur",option+1) == 0)
2499 {
2500 flags=ParseGeometry(arg1,&geometry_info);
2501 if ((flags & (RhoValue|SigmaValue)) == 0)
2502 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2503 if ((flags & SigmaValue) == 0)
2504 geometry_info.sigma=1.0;
2505 new_image=GaussianBlurImage(_image,geometry_info.rho,
2506 geometry_info.sigma,_exception);
2507 break;
2508 }
2509 if (LocaleCompare("gaussian",option+1) == 0)
2510 {
2511 CLIWandWarnReplaced("-gaussian-blur");
2512 (void) CLISimpleOperatorImage(cli_wand,"-gaussian-blur",arg1,NULL,exception);
2513 }
2514 if (LocaleCompare("geometry",option+1) == 0)
2515 {
2516 /*
2517 Record Image offset for composition. (A Setting)
2518 Resize last _image. (ListOperator) -- DEPRECIATE
2519 FUTURE: Why if no 'offset' does this resize ALL images?
2520 Also why is the setting recorded in the IMAGE non-sense!
2521 */
2522 if (IfPlusOp)
2523 { /* remove the previous composition geometry offset! */
2524 if (_image->geometry != (char *) NULL)
2525 _image->geometry=DestroyString(_image->geometry);
2526 break;
2527 }
2528 if (IsGeometry(arg1) == MagickFalse)
2529 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2530 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2531 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
2532 (void) CloneString(&_image->geometry,arg1);
2533 else
2534 new_image=ResizeImage(_image,geometry.width,geometry.height,
2535 _image->filter,_exception);
2536 break;
2537 }
2538 if (LocaleCompare("grayscale",option+1) == 0)
2539 {
2540 parse=ParseCommandOption(MagickPixelIntensityOptions,
2541 MagickFalse,arg1);
2542 if (parse < 0)
2543 CLIWandExceptArgBreak(OptionError,"UnrecognizedIntensityMethod",
2544 option,arg1);
2545 (void) GrayscaleImage(_image,(PixelIntensityMethod) parse,_exception);
2546 break;
2547 }
2548 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2549 }
2550 case 'h':
2551 {
2552 if (LocaleCompare("hough-lines",option+1) == 0)
2553 {
2554 flags=ParseGeometry(arg1,&geometry_info);
2555 if ((flags & (RhoValue|SigmaValue)) == 0)
2556 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2557 if ((flags & SigmaValue) == 0)
2558 geometry_info.sigma=geometry_info.rho;
2559 if ((flags & XiValue) == 0)
2560 geometry_info.xi=40;
2561 new_image=HoughLineImage(_image,(size_t) geometry_info.rho,
2562 (size_t) geometry_info.sigma,(size_t) geometry_info.xi,_exception);
2563 break;
2564 }
2565 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2566 }
2567 case 'i':
2568 {
2569 if (LocaleCompare("identify",option+1) == 0)
2570 {
2571 const char
2572 *format,
2573 *text;
2574
2575 format=GetImageOption(_image_info,"format");
2576 if (format == (char *) NULL)
2577 {
2578 (void) IdentifyImage(_image,stdout,_image_info->verbose,
2579 _exception);
2580 break;
2581 }
2582 text=InterpretImageProperties(_image_info,_image,format,_exception);
2583 if (text == (char *) NULL)
2584 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
2585 option);
2586 (void) fputs(text,stdout);
2587 text=DestroyString((char *)text);
2588 break;
2589 }
2590 if (LocaleCompare("implode",option+1) == 0)
2591 {
2592 flags=ParseGeometry(arg1,&geometry_info);
2593 if ((flags & RhoValue) == 0)
2594 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2595 new_image=ImplodeImage(_image,geometry_info.rho,_image->interpolate,
2596 _exception);
2597 break;
2598 }
2599 if (LocaleCompare("integral",option+1) == 0)
2600 {
2601 new_image=IntegralImage(_image,_exception);
2602 break;
2603 }
2604 if (LocaleCompare("interpolative-resize",option+1) == 0)
2605 {
2606 /* FUTURE: New to IMv7
2607 Roll into a resize special operator */
2608 if (IsGeometry(arg1) == MagickFalse)
2609 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2610 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
2611 new_image=InterpolativeResizeImage(_image,geometry.width,
2612 geometry.height,_image->interpolate,_exception);
2613 break;
2614 }
2615 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2616 }
2617 case 'k':
2618 {
2619 if (LocaleCompare("kmeans",option+1) == 0)
2620 {
2621 /*
2622 K-means clustering.
2623 */
2624 flags=ParseGeometry(arg1,&geometry_info);
2625 if ((flags & (RhoValue|SigmaValue)) == 0)
2626 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2627 if ((flags & SigmaValue) == 0)
2628 geometry_info.sigma=300.0;
2629 if ((flags & XiValue) == 0)
2630 geometry_info.xi=0.0001;
2631 (void) KmeansImage(_image,(size_t) geometry_info.rho,(size_t)
2632 geometry_info.sigma,geometry_info.xi,_exception);
2633 break;
2634 }
2635 if (LocaleCompare("kuwahara",option+1) == 0)
2636 {
2637 /*
2638 Edge preserving blur.
2639 */
2640 flags=ParseGeometry(arg1,&geometry_info);
2641 if ((flags & (RhoValue|SigmaValue)) == 0)
2642 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2643 if ((flags & SigmaValue) == 0)
2644 geometry_info.sigma=geometry_info.rho-0.5;
2645 new_image=KuwaharaImage(_image,geometry_info.rho,geometry_info.sigma,
2646 _exception);
2647 break;
2648 }
2649 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2650 }
2651 case 'l':
2652 {
2653 if (LocaleCompare("lat",option+1) == 0)
2654 {
2655 flags=ParseGeometry(arg1,&geometry_info);
2656 if ((flags & (RhoValue|SigmaValue)) == 0)
2657 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2658 if ((flags & SigmaValue) == 0)
2659 geometry_info.sigma=1.0;
2660 if ((flags & PercentValue) != 0)
2661 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2662 new_image=AdaptiveThresholdImage(_image,(size_t) geometry_info.rho,
2663 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2664 _exception);
2665 break;
2666 }
2667 if (LocaleCompare("level",option+1) == 0)
2668 {
2669 double
2670 black_point,
2671 gamma,
2672 white_point;
2673
2674 flags=ParseGeometry(arg1,&geometry_info);
2675 if ((flags & RhoValue) == 0)
2676 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2677 black_point=geometry_info.rho;
2678 white_point=(double) QuantumRange;
2679 if ((flags & SigmaValue) != 0)
2680 white_point=geometry_info.sigma;
2681 gamma=1.0;
2682 if ((flags & XiValue) != 0)
2683 gamma=geometry_info.xi;
2684 if ((flags & PercentValue) != 0)
2685 {
2686 black_point*=(double) QuantumRange/100.0;
2687 white_point*=(double) QuantumRange/100.0;
2688 }
2689 if ((flags & SigmaValue) == 0)
2690 white_point=(double) QuantumRange-black_point;
2691 if (IfPlusOp || ((flags & AspectValue) != 0))
2692 (void) LevelizeImage(_image,black_point,white_point,gamma,_exception);
2693 else
2694 (void) LevelImage(_image,black_point,white_point,gamma,_exception);
2695 break;
2696 }
2697 if (LocaleCompare("level-colors",option+1) == 0)
2698 {
2699 char
2700 token[MagickPathExtent];
2701
2702 const char
2703 *p;
2704
2705 PixelInfo
2706 black_point,
2707 white_point;
2708
2709 p=(const char *) arg1;
2710 (void) GetNextToken(p,&p,MagickPathExtent,token); /* get black point color */
2711 if ((isalpha((int) ((unsigned char) *token)) != 0) || ((*token == '#') != 0))
2712 (void) QueryColorCompliance(token,AllCompliance,
2713 &black_point,_exception);
2714 else
2715 (void) QueryColorCompliance("#000000",AllCompliance,
2716 &black_point,_exception);
2717 if (isalpha((int) ((unsigned char) *token)) || (*token == '#'))
2718 (void) GetNextToken(p,&p,MagickPathExtent,token);
2719 if (*token == '\0')
2720 white_point=black_point; /* set everything to that color */
2721 else
2722 {
2723 if ((isalpha((int) ((unsigned char) *token)) == 0) && ((*token == '#') == 0))
2724 (void) GetNextToken(p,&p,MagickPathExtent,token); /* Get white point color. */
2725 if ((isalpha((int) ((unsigned char) *token)) != 0) || ((*token == '#') != 0))
2726 (void) QueryColorCompliance(token,AllCompliance,
2727 &white_point,_exception);
2728 else
2729 (void) QueryColorCompliance("#ffffff",AllCompliance,
2730 &white_point,_exception);
2731 }
2732 (void) LevelImageColors(_image,&black_point,&white_point,
2733 IsPlusOp,_exception);
2734 break;
2735 }
2736 if (LocaleCompare("linear-stretch",option+1) == 0)
2737 {
2738 double
2739 black_point,
2740 white_point;
2741
2742 flags=ParseGeometry(arg1,&geometry_info);
2743 if ((flags & RhoValue) == 0)
2744 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2745 black_point=geometry_info.rho;
2746 white_point=(double) _image->columns*_image->rows;
2747 if ((flags & SigmaValue) != 0)
2748 white_point=geometry_info.sigma;
2749 if ((flags & PercentValue) != 0)
2750 {
2751 black_point*=(double) _image->columns*_image->rows/100.0;
2752 white_point*=(double) _image->columns*_image->rows/100.0;
2753 }
2754 if ((flags & SigmaValue) == 0)
2755 white_point=(double) _image->columns*_image->rows-
2756 black_point;
2757 (void) LinearStretchImage(_image,black_point,white_point,_exception);
2758 break;
2759 }
2760 if (LocaleCompare("liquid-rescale",option+1) == 0)
2761 {
2762 /* FUTURE: Roll into a resize special operator */
2763 if (IsGeometry(arg1) == MagickFalse)
2764 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2765 flags=ParseRegionGeometry(_image,arg1,&geometry,_exception);
2766 if ((flags & XValue) == 0)
2767 geometry.x=1;
2768 if ((flags & YValue) == 0)
2769 geometry.y=0;
2770 new_image=LiquidRescaleImage(_image,geometry.width,
2771 geometry.height,1.0*geometry.x,1.0*geometry.y,_exception);
2772 break;
2773 }
2774 if (LocaleCompare("local-contrast",option+1) == 0)
2775 {
2776 flags=ParseGeometry(arg1,&geometry_info);
2777 if ((flags & RhoValue) == 0)
2778 geometry_info.rho=10;
2779 if ((flags & SigmaValue) == 0)
2780 geometry_info.sigma=12.5;
2781 new_image=LocalContrastImage(_image,geometry_info.rho,
2782 geometry_info.sigma,exception);
2783 break;
2784 }
2785 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2786 }
2787 case 'm':
2788 {
2789 if (LocaleCompare("magnify",option+1) == 0)
2790 {
2791 new_image=MagnifyImage(_image,_exception);
2792 break;
2793 }
2794 if (LocaleCompare("map",option+1) == 0)
2795 {
2796 CLIWandWarnReplaced("-remap");
2797 (void) CLISimpleOperatorImage(cli_wand,"-remap",arg1,NULL,exception);
2798 break;
2799 }
2800 if (LocaleCompare("mask",option+1) == 0)
2801 {
2802 Image
2803 *mask;
2804
2805 if (IfPlusOp)
2806 {
2807 /*
2808 Remove a mask.
2809 */
2810 (void) SetImageMask(_image,WritePixelMask,(const Image *) NULL,
2811 _exception);
2812 break;
2813 }
2814 /*
2815 Set the image mask.
2816 */
2817 mask=GetImageCache(_image_info,arg1,_exception);
2818 if (mask == (Image *) NULL)
2819 break;
2820 (void) SetImageMask(_image,WritePixelMask,mask,_exception);
2821 mask=DestroyImage(mask);
2822 break;
2823 }
2824 if (LocaleCompare("matte",option+1) == 0)
2825 {
2826 CLIWandWarnReplaced(IfNormalOp?"-alpha Set":"-alpha Off");
2827 (void) SetImageAlphaChannel(_image,IfNormalOp ? SetAlphaChannel :
2828 DeactivateAlphaChannel, _exception);
2829 break;
2830 }
2831 if (LocaleCompare("mean-shift",option+1) == 0)
2832 {
2833 flags=ParseGeometry(arg1,&geometry_info);
2834 if ((flags & (RhoValue|SigmaValue)) == 0)
2835 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2836 if ((flags & SigmaValue) == 0)
2837 geometry_info.sigma=1.0;
2838 if ((flags & XiValue) == 0)
2839 geometry_info.xi=0.10*(double) QuantumRange;
2840 if ((flags & PercentValue) != 0)
2841 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
2842 new_image=MeanShiftImage(_image,(size_t) geometry_info.rho,
2843 (size_t) geometry_info.sigma,geometry_info.xi,_exception);
2844 break;
2845 }
2846 if (LocaleCompare("median",option+1) == 0)
2847 {
2848 CLIWandWarnReplaced("-statistic Median");
2849 (void) CLISimpleOperatorImage(cli_wand,"-statistic","Median",arg1,exception);
2850 break;
2851 }
2852 if (LocaleCompare("mode",option+1) == 0)
2853 {
2854 /* FUTURE: note this is also a special "montage" option */
2855 CLIWandWarnReplaced("-statistic Mode");
2856 (void) CLISimpleOperatorImage(cli_wand,"-statistic","Mode",arg1,
2857 exception);
2858 break;
2859 }
2860 if (LocaleCompare("modulate",option+1) == 0)
2861 {
2862 if (IsGeometry(arg1) == MagickFalse)
2863 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2864 (void) ModulateImage(_image,arg1,_exception);
2865 break;
2866 }
2867 if (LocaleCompare("monitor",option+1) == 0)
2868 {
2869 (void) SetImageProgressMonitor(_image, IfNormalOp ? MonitorProgress :
2870 (MagickProgressMonitor) NULL,(void *) NULL);
2871 break;
2872 }
2873 if (LocaleCompare("moments",option+1) == 0)
2874 {
2875 CLIWandWarnReplaced("-verbose -define identify:moments=");
2876 if (*option == '+')
2877 {
2878 (void) DeleteImageArtifact(_image,"identify:moments");
2879 break;
2880 }
2881 (void) SetImageArtifact(_image,"identify:moments","true");
2882 (void) SetImageArtifact(_image,"verbose","true");
2883 break;
2884 }
2885 if (LocaleCompare("monochrome",option+1) == 0)
2886 {
2887 (void) SetImageType(_image,BilevelType,_exception);
2888 break;
2889 }
2890 if (LocaleCompare("morphology",option+1) == 0)
2891 {
2892 char
2893 token[MagickPathExtent];
2894
2895 const char
2896 *p;
2897
2898 KernelInfo
2899 *kernel;
2900
2901 ssize_t
2902 iterations;
2903
2904 p=arg1;
2905 (void) GetNextToken(p,&p,MagickPathExtent,token);
2906 parse=ParseCommandOption(MagickMorphologyOptions,MagickFalse,token);
2907 if ( parse < 0 )
2908 CLIWandExceptArgBreak(OptionError,"UnrecognizedFunction",option,
2909 arg1);
2910 iterations=1L;
2911 (void) GetNextToken(p,&p,MagickPathExtent,token);
2912 if ((*p == ':') || (*p == ','))
2913 (void) GetNextToken(p,&p,MagickPathExtent,token);
2914 if ((*p != '\0'))
2915 iterations=(ssize_t) StringToLong(p);
2916 kernel=AcquireKernelInfo(arg2,exception);
2917 if (kernel == (KernelInfo *) NULL)
2918 CLIWandExceptArgBreak(OptionError,"UnabletoParseKernel",option,arg2);
2919 new_image=MorphologyImage(_image,(MorphologyMethod)parse,iterations,
2920 kernel,_exception);
2921 kernel=DestroyKernelInfo(kernel);
2922 break;
2923 }
2924 if (LocaleCompare("motion-blur",option+1) == 0)
2925 {
2926 flags=ParseGeometry(arg1,&geometry_info);
2927 if ((flags & (RhoValue|SigmaValue)) == 0)
2928 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
2929 if ((flags & SigmaValue) == 0)
2930 geometry_info.sigma=1.0;
2931 new_image=MotionBlurImage(_image,geometry_info.rho,
2932 geometry_info.sigma,geometry_info.xi,_exception);
2933 break;
2934 }
2935 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2936 }
2937 case 'n':
2938 {
2939 if (LocaleCompare("negate",option+1) == 0)
2940 {
2941 (void) NegateImage(_image, IsPlusOp, _exception);
2942 break;
2943 }
2944 if (LocaleCompare("noise",option+1) == 0)
2945 {
2946 double
2947 attenuate;
2948
2949 const char*
2950 value;
2951
2952 if (IfNormalOp)
2953 {
2954 CLIWandWarnReplaced("-statistic NonPeak");
2955 (void) CLISimpleOperatorImage(cli_wand,"-statistic","NonPeak",arg1,exception);
2956 break;
2957 }
2958 parse=ParseCommandOption(MagickNoiseOptions,MagickFalse,arg1);
2959 if ( parse < 0 )
2960 CLIWandExceptArgBreak(OptionError,"UnrecognizedNoiseType",
2961 option,arg1);
2962 attenuate=1.0;
2963 value=GetImageOption(_image_info,"attenuate");
2964 if (value != (const char *) NULL)
2965 attenuate=StringToDouble(value,(char **) NULL);
2966 new_image=AddNoiseImage(_image,(NoiseType)parse,attenuate,
2967 _exception);
2968 break;
2969 }
2970 if (LocaleCompare("normalize",option+1) == 0)
2971 {
2972 (void) NormalizeImage(_image,_exception);
2973 break;
2974 }
2975 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2976 }
2977 case 'o':
2978 {
2979 if (LocaleCompare("opaque",option+1) == 0)
2980 {
2981 PixelInfo
2982 target;
2983
2984 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
2985 (void) OpaquePaintImage(_image,&target,&_draw_info->fill,IsPlusOp,
2986 _exception);
2987 break;
2988 }
2989 if (LocaleCompare("ordered-dither",option+1) == 0)
2990 {
2991 (void) OrderedDitherImage(_image,arg1,_exception);
2992 break;
2993 }
2994 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
2995 }
2996 case 'p':
2997 {
2998 if (LocaleCompare("paint",option+1) == 0)
2999 {
3000 flags=ParseGeometry(arg1,&geometry_info);
3001 if ((flags & (RhoValue|SigmaValue)) == 0)
3002 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3003 new_image=OilPaintImage(_image,geometry_info.rho,geometry_info.sigma,
3004 _exception);
3005 break;
3006 }
3007 if (LocaleCompare("perceptible",option+1) == 0)
3008 {
3009 (void) PerceptibleImage(_image,StringToDouble(arg1,(char **) NULL),
3010 _exception);
3011 break;
3012 }
3013 if (LocaleCompare("polaroid",option+1) == 0)
3014 {
3015 const char
3016 *caption;
3017
3018 double
3019 angle;
3020
3021 if (IfPlusOp) {
3022 RandomInfo
3023 *random_info;
3024
3025 random_info=AcquireRandomInfo();
3026 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
3027 random_info=DestroyRandomInfo(random_info);
3028 }
3029 else {
3030 flags=ParseGeometry(arg1,&geometry_info);
3031 if ((flags & RhoValue) == 0)
3032 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3033 angle=geometry_info.rho;
3034 }
3035 caption=GetImageProperty(_image,"caption",_exception);
3036 new_image=PolaroidImage(_image,_draw_info,caption,angle,
3037 _image->interpolate,_exception);
3038 break;
3039 }
3040 if (LocaleCompare("posterize",option+1) == 0)
3041 {
3042 flags=ParseGeometry(arg1,&geometry_info);
3043 if ((flags & RhoValue) == 0)
3044 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3045 (void) PosterizeImage(_image,(size_t) geometry_info.rho,
3046 _quantize_info->dither_method,_exception);
3047 break;
3048 }
3049 if (LocaleCompare("preview",option+1) == 0)
3050 {
3051 /* FUTURE: should be a 'Genesis' option?
3052 Option however is also in WandSettingOptionInfo()
3053 Why???
3054 */
3055 parse=ParseCommandOption(MagickPreviewOptions, MagickFalse,arg1);
3056 if ( parse < 0 )
3057 CLIWandExceptArgBreak(OptionError,"UnrecognizedPreviewType",
3058 option,arg1);
3059 new_image=PreviewImage(_image,(PreviewType)parse,_exception);
3060 break;
3061 }
3062 if (LocaleCompare("profile",option+1) == 0)
3063 {
3064 const char
3065 *name;
3066
3067 const StringInfo
3068 *profile;
3069
3070 Image
3071 *profile_image;
3072
3073 ImageInfo
3074 *profile_info;
3075
3076 /* Note: arguments do not have percent escapes expanded */
3077 if (IfPlusOp)
3078 { /* Remove a profile from the _image. */
3079 (void) ProfileImage(_image,arg1,(const unsigned char *)
3080 NULL,0,_exception);
3081 break;
3082 }
3083 /* Associate a profile with the _image. */
3084 profile_info=CloneImageInfo(_image_info);
3085 profile=GetImageProfile(_image,"iptc");
3086 if (profile != (const StringInfo *) NULL)
3087 profile_info->profile=(void *) CloneStringInfo(profile);
3088 profile_image=GetImageCache(profile_info,arg1,_exception);
3089 profile_info=DestroyImageInfo(profile_info);
3090 if (profile_image == (Image *) NULL)
3091 {
3092 StringInfo
3093 *new_profile;
3094
3095 profile_info=CloneImageInfo(_image_info);
3096 (void) CopyMagickString(profile_info->filename,arg1,
3097 MagickPathExtent);
3098 new_profile=FileToStringInfo(profile_info->filename,~0UL,
3099 _exception);
3100 if (new_profile != (StringInfo *) NULL)
3101 {
3102 (void) SetImageInfo(profile_info,0,_exception);
3103 (void) ProfileImage(_image,profile_info->magick,
3104 GetStringInfoDatum(new_profile),(size_t)
3105 GetStringInfoLength(new_profile),_exception);
3106 new_profile=DestroyStringInfo(new_profile);
3107 }
3108 profile_info=DestroyImageInfo(profile_info);
3109 break;
3110 }
3111 ResetImageProfileIterator(profile_image);
3112 name=GetNextImageProfile(profile_image);
3113 while (name != (const char *) NULL)
3114 {
3115 profile=GetImageProfile(profile_image,name);
3116 if (profile != (const StringInfo *) NULL)
3117 (void) ProfileImage(_image,name,GetStringInfoDatum(profile),
3118 (size_t) GetStringInfoLength(profile),_exception);
3119 name=GetNextImageProfile(profile_image);
3120 }
3121 profile_image=DestroyImage(profile_image);
3122 break;
3123 }
3124 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3125 }
3126 case 'r':
3127 {
3128 if (LocaleCompare("raise",option+1) == 0)
3129 {
3130 if (IsGeometry(arg1) == MagickFalse)
3131 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3132 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3133 (void) RaiseImage(_image,&geometry,IsNormalOp,_exception);
3134 break;
3135 }
3136 if (LocaleCompare("random-threshold",option+1) == 0)
3137 {
3138 double
3139 min_threshold,
3140 max_threshold;
3141
3142 if (IsGeometry(arg1) == MagickFalse)
3143 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3144 min_threshold=0.0;
3145 max_threshold=(double) QuantumRange;
3146 flags=ParseGeometry(arg1,&geometry_info);
3147 min_threshold=geometry_info.rho;
3148 max_threshold=geometry_info.sigma;
3149 if ((flags & SigmaValue) == 0)
3150 max_threshold=min_threshold;
3151 if (arg1 == (char *) NULL)
3152 break;
3153 if (strchr(arg1,'%') != (char *) NULL)
3154 {
3155 max_threshold*=(0.01*(double) QuantumRange);
3156 min_threshold*=(0.01*(double) QuantumRange);
3157 }
3158 (void) RandomThresholdImage(_image,min_threshold,max_threshold,
3159 _exception);
3160 break;
3161 }
3162 if (LocaleCompare("range-threshold",option+1) == 0)
3163 {
3164 /*
3165 Range threshold image.
3166 */
3167 if (IsGeometry(arg1) == MagickFalse)
3168 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3169 flags=ParseGeometry(arg1,&geometry_info);
3170 if ((flags & SigmaValue) == 0)
3171 geometry_info.sigma=geometry_info.rho;
3172 if ((flags & XiValue) == 0)
3173 geometry_info.xi=geometry_info.sigma;
3174 if ((flags & PsiValue) == 0)
3175 geometry_info.psi=geometry_info.xi;
3176 if (strchr(arg1,'%') != (char *) NULL)
3177 {
3178 geometry_info.rho*=(0.01*(double) QuantumRange);
3179 geometry_info.sigma*=(0.01*(double) QuantumRange);
3180 geometry_info.xi*=(0.01*(double) QuantumRange);
3181 geometry_info.psi*=(0.01*(double) QuantumRange);
3182 }
3183 (void) RangeThresholdImage(_image,geometry_info.rho,
3184 geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3185 break;
3186 }
3187 if (LocaleCompare("read-mask",option+1) == 0)
3188 {
3189 /* Note: arguments do not have percent escapes expanded */
3190 Image
3191 *mask;
3192
3193 if (IfPlusOp)
3194 { /* Remove a mask. */
3195 (void) SetImageMask(_image,ReadPixelMask,(const Image *) NULL,
3196 _exception);
3197 break;
3198 }
3199 /* Set the image mask. */
3200 mask=GetImageCache(_image_info,arg1,_exception);
3201 if (mask == (Image *) NULL)
3202 break;
3203 (void) SetImageMask(_image,ReadPixelMask,mask,_exception);
3204 mask=DestroyImage(mask);
3205 break;
3206 }
3207 if (LocaleCompare("recolor",option+1) == 0)
3208 {
3209 CLIWandWarnReplaced("-color-matrix");
3210 (void) CLISimpleOperatorImage(cli_wand,"-color-matrix",arg1,NULL,
3211 exception);
3212 }
3213 if (LocaleCompare("region",option+1) == 0)
3214 {
3215 if (*option == '+')
3216 {
3217 (void) SetImageRegionMask(_image,WritePixelMask,
3218 (const RectangleInfo *) NULL,_exception);
3219 break;
3220 }
3221 if (IsGeometry(arg1) == MagickFalse)
3222 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3223 (void) ParseGravityGeometry(_image,arg1,&geometry,_exception);
3224 (void) SetImageRegionMask(_image,WritePixelMask,&geometry,_exception);
3225 break;
3226 }
3227 if (LocaleCompare("remap",option+1) == 0)
3228 {
3229 /* Note: arguments do not have percent escapes expanded */
3230 Image
3231 *remap_image;
3232
3233 remap_image=GetImageCache(_image_info,arg1,_exception);
3234 if (remap_image == (Image *) NULL)
3235 break;
3236 (void) RemapImage(_quantize_info,_image,remap_image,_exception);
3237 remap_image=DestroyImage(remap_image);
3238 break;
3239 }
3240 if (LocaleCompare("repage",option+1) == 0)
3241 {
3242 if (IfNormalOp)
3243 {
3244 if (IsGeometry(arg1) == MagickFalse)
3245 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
3246 arg1);
3247 (void) ResetImagePage(_image,arg1);
3248 }
3249 else
3250 (void) ParseAbsoluteGeometry("0x0+0+0",&_image->page);
3251 break;
3252 }
3253 if (LocaleCompare("resample",option+1) == 0)
3254 {
3255 /* FUTURE: Roll into a resize special operation */
3256 flags=ParseGeometry(arg1,&geometry_info);
3257 if ((flags & (RhoValue|SigmaValue)) == 0)
3258 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3259 if ((flags & SigmaValue) == 0)
3260 geometry_info.sigma=geometry_info.rho;
3261 new_image=ResampleImage(_image,geometry_info.rho,
3262 geometry_info.sigma,_image->filter,_exception);
3263 break;
3264 }
3265 if (LocaleCompare("reshape",option+1) == 0)
3266 {
3267 if (IsGeometry(arg1) == MagickFalse)
3268 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3269 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3270 (void) ReshapePixelCache(_image,geometry.width,geometry.height,
3271 _exception);
3272 break;
3273 }
3274 if (LocaleCompare("resize",option+1) == 0)
3275 {
3276 if (IsGeometry(arg1) == MagickFalse)
3277 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3278 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3279 new_image=ResizeImage(_image,geometry.width,geometry.height,
3280 _image->filter,_exception);
3281 break;
3282 }
3283 if (LocaleCompare("roll",option+1) == 0)
3284 {
3285 if (IsGeometry(arg1) == MagickFalse)
3286 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3287 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3288 if ((flags & PercentValue) != 0)
3289 {
3290 geometry.x*=(ssize_t) (_image->columns/100.0);
3291 geometry.y*=(ssize_t) (_image->rows/100.0);
3292 }
3293 new_image=RollImage(_image,geometry.x,geometry.y,_exception);
3294 break;
3295 }
3296 if (LocaleCompare("rotate",option+1) == 0)
3297 {
3298 flags=ParseGeometry(arg1,&geometry_info);
3299 if ((flags & RhoValue) == 0)
3300 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3301 if ((flags & GreaterValue) != 0 && (_image->columns <= _image->rows))
3302 break;
3303 if ((flags & LessValue) != 0 && (_image->columns >= _image->rows))
3304 break;
3305 new_image=RotateImage(_image,geometry_info.rho,_exception);
3306 break;
3307 }
3308 if (LocaleCompare("rotational-blur",option+1) == 0)
3309 {
3310 flags=ParseGeometry(arg1,&geometry_info);
3311 if ((flags & RhoValue) == 0)
3312 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3313 new_image=RotationalBlurImage(_image,geometry_info.rho,_exception);
3314 break;
3315 }
3316 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3317 }
3318 case 's':
3319 {
3320 if (LocaleCompare("sample",option+1) == 0)
3321 {
3322 /* FUTURE: Roll into a resize special operator */
3323 if (IsGeometry(arg1) == MagickFalse)
3324 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3325 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3326 new_image=SampleImage(_image,geometry.width,geometry.height,
3327 _exception);
3328 break;
3329 }
3330 if (LocaleCompare("scale",option+1) == 0)
3331 {
3332 /* FUTURE: Roll into a resize special operator */
3333 if (IsGeometry(arg1) == MagickFalse)
3334 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3335 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3336 new_image=ScaleImage(_image,geometry.width,geometry.height,
3337 _exception);
3338 break;
3339 }
3340 if (LocaleCompare("segment",option+1) == 0)
3341 {
3342 flags=ParseGeometry(arg1,&geometry_info);
3343 if ((flags & (RhoValue|SigmaValue)) == 0)
3344 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3345 if ((flags & SigmaValue) == 0)
3346 geometry_info.sigma=1.0;
3347 (void) SegmentImage(_image,_image->colorspace,
3348 _image_info->verbose,geometry_info.rho,geometry_info.sigma,
3349 _exception);
3350 break;
3351 }
3352 if (LocaleCompare("selective-blur",option+1) == 0)
3353 {
3354 flags=ParseGeometry(arg1,&geometry_info);
3355 if ((flags & (RhoValue|SigmaValue)) == 0)
3356 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3357 if ((flags & SigmaValue) == 0)
3358 geometry_info.sigma=1.0;
3359 if ((flags & PercentValue) != 0)
3360 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
3361 new_image=SelectiveBlurImage(_image,geometry_info.rho,
3362 geometry_info.sigma,geometry_info.xi,_exception);
3363 break;
3364 }
3365 if (LocaleCompare("separate",option+1) == 0)
3366 {
3367 /* WARNING: This can generate multiple images! */
3368 /* FUTURE - this may be replaced by a "-channel" method */
3369 new_image=SeparateImages(_image,_exception);
3370 break;
3371 }
3372 if (LocaleCompare("sepia-tone",option+1) == 0)
3373 {
3374 if (IsGeometry(arg1) == MagickFalse)
3375 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3376 new_image=SepiaToneImage(_image,StringToDoubleInterval(arg1,
3377 (double) QuantumRange+1.0),_exception);
3378 break;
3379 }
3380 if (LocaleCompare("shade",option+1) == 0)
3381 {
3382 flags=ParseGeometry(arg1,&geometry_info);
3383 if (((flags & RhoValue) == 0) || ((flags & SigmaValue) == 0))
3384 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3385 new_image=ShadeImage(_image,IsNormalOp,geometry_info.rho,
3386 geometry_info.sigma,_exception);
3387 break;
3388 }
3389 if (LocaleCompare("shadow",option+1) == 0)
3390 {
3391 flags=ParseGeometry(arg1,&geometry_info);
3392 if ((flags & (RhoValue|SigmaValue)) == 0)
3393 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3394 if ((flags & SigmaValue) == 0)
3395 geometry_info.sigma=1.0;
3396 if ((flags & XiValue) == 0)
3397 geometry_info.xi=4.0;
3398 if ((flags & PsiValue) == 0)
3399 geometry_info.psi=4.0;
3400 new_image=ShadowImage(_image,geometry_info.rho,geometry_info.sigma,
3401 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3402 ceil(geometry_info.psi-0.5),_exception);
3403 break;
3404 }
3405 if (LocaleCompare("sharpen",option+1) == 0)
3406 {
3407 flags=ParseGeometry(arg1,&geometry_info);
3408 if ((flags & (RhoValue|SigmaValue)) == 0)
3409 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3410 if ((flags & SigmaValue) == 0)
3411 geometry_info.sigma=1.0;
3412 if ((flags & XiValue) == 0)
3413 geometry_info.xi=0.0;
3414 new_image=SharpenImage(_image,geometry_info.rho,geometry_info.sigma,
3415 _exception);
3416 break;
3417 }
3418 if (LocaleCompare("shave",option+1) == 0)
3419 {
3420 if (IsGeometry(arg1) == MagickFalse)
3421 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3422 flags=ParsePageGeometry(_image,arg1,&geometry,_exception);
3423 new_image=ShaveImage(_image,&geometry,_exception);
3424 break;
3425 }
3426 if (LocaleCompare("shear",option+1) == 0)
3427 {
3428 flags=ParseGeometry(arg1,&geometry_info);
3429 if ((flags & RhoValue) == 0)
3430 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3431 if ((flags & SigmaValue) == 0)
3432 geometry_info.sigma=geometry_info.rho;
3433 new_image=ShearImage(_image,geometry_info.rho,geometry_info.sigma,
3434 _exception);
3435 break;
3436 }
3437 if (LocaleCompare("sigmoidal-contrast",option+1) == 0)
3438 {
3439 flags=ParseGeometry(arg1,&geometry_info);
3440 if ((flags & RhoValue) == 0)
3441 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3442 if ((flags & SigmaValue) == 0)
3443 geometry_info.sigma=(double) QuantumRange/2.0;
3444 if ((flags & PercentValue) != 0)
3445 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3446 100.0;
3447 (void) SigmoidalContrastImage(_image,IsNormalOp,geometry_info.rho,
3448 geometry_info.sigma,_exception);
3449 break;
3450 }
3451 if (LocaleCompare("sketch",option+1) == 0)
3452 {
3453 flags=ParseGeometry(arg1,&geometry_info);
3454 if ((flags & (RhoValue|SigmaValue)) == 0)
3455 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3456 if ((flags & SigmaValue) == 0)
3457 geometry_info.sigma=1.0;
3458 new_image=SketchImage(_image,geometry_info.rho,
3459 geometry_info.sigma,geometry_info.xi,_exception);
3460 break;
3461 }
3462 if (LocaleCompare("solarize",option+1) == 0)
3463 {
3464 if (IsGeometry(arg1) == MagickFalse)
3465 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3466 (void) SolarizeImage(_image,StringToDoubleInterval(arg1,(double)
3467 QuantumRange+1.0),_exception);
3468 break;
3469 }
3470 if (LocaleCompare("sort-pixels",option+1) == 0)
3471 {
3472 (void) SortImagePixels(_image,_exception);
3473 break;
3474 }
3475 if (LocaleCompare("sparse-color",option+1) == 0)
3476 {
3477 parse=ParseCommandOption(MagickSparseColorOptions,MagickFalse,arg1);
3478 if (parse < 0)
3479 CLIWandExceptArgBreak(OptionError,"UnrecognizedSparseColorMethod",
3480 option,arg1);
3481 new_image=SparseColorOption(_image,(SparseColorMethod)parse,arg2,
3482 _exception);
3483 break;
3484 }
3485 if (LocaleCompare("splice",option+1) == 0)
3486 {
3487 if (IsGeometry(arg1) == MagickFalse)
3488 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3489 flags=ParseGravityGeometry(_image,arg1,&geometry,_exception);
3490 new_image=SpliceImage(_image,&geometry,_exception);
3491 break;
3492 }
3493 if (LocaleCompare("spread",option+1) == 0)
3494 {
3495 flags=ParseGeometry(arg1,&geometry_info);
3496 if ((flags & RhoValue) == 0)
3497 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3498 new_image=SpreadImage(_image,_image->interpolate,geometry_info.rho,
3499 _exception);
3500 break;
3501 }
3502 if (LocaleCompare("statistic",option+1) == 0)
3503 {
3504 parse=ParseCommandOption(MagickStatisticOptions,MagickFalse,arg1);
3505 if ( parse < 0 )
3506 CLIWandExceptArgBreak(OptionError,"UnrecognizedStatisticType",
3507 option,arg1);
3508 flags=ParseGeometry(arg2,&geometry_info);
3509 if ((flags & RhoValue) == 0)
3510 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg2);
3511 if ((flags & SigmaValue) == 0)
3512 geometry_info.sigma=geometry_info.rho;
3513 new_image=StatisticImage(_image,(StatisticType)parse,
3514 (size_t) geometry_info.rho,(size_t) geometry_info.sigma,
3515 _exception);
3516 break;
3517 }
3518 if (LocaleCompare("strip",option+1) == 0)
3519 {
3520 (void) StripImage(_image,_exception);
3521 break;
3522 }
3523 if (LocaleCompare("swirl",option+1) == 0)
3524 {
3525 flags=ParseGeometry(arg1,&geometry_info);
3526 if ((flags & RhoValue) == 0)
3527 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3528 new_image=SwirlImage(_image,geometry_info.rho,
3529 _image->interpolate,_exception);
3530 break;
3531 }
3532 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3533 }
3534 case 't':
3535 {
3536 if (LocaleCompare("threshold",option+1) == 0)
3537 {
3538 double
3539 threshold;
3540
3541 threshold=(double) QuantumRange/2;
3542 if (IfNormalOp) {
3543 if (IsGeometry(arg1) == MagickFalse)
3544 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3545 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
3546 }
3547 (void) BilevelImage(_image,threshold,_exception);
3548 break;
3549 }
3550 if (LocaleCompare("thumbnail",option+1) == 0)
3551 {
3552 if (IsGeometry(arg1) == MagickFalse)
3553 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3554 (void) ParseRegionGeometry(_image,arg1,&geometry,_exception);
3555 new_image=ThumbnailImage(_image,geometry.width,geometry.height,
3556 _exception);
3557 break;
3558 }
3559 if (LocaleCompare("tint",option+1) == 0)
3560 {
3561 if (IsGeometry(arg1) == MagickFalse)
3562 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3563 new_image=TintImage(_image,arg1,&_draw_info->fill,_exception);
3564 break;
3565 }
3566 if (LocaleCompare("transform",option+1) == 0)
3567 {
3568 CLIWandWarnReplaced("+distort AffineProjection");
3569 new_image=AffineTransformImage(_image,&_draw_info->affine,_exception);
3570 break;
3571 }
3572 if (LocaleCompare("transparent",option+1) == 0)
3573 {
3574 PixelInfo
3575 target;
3576
3577 (void) QueryColorCompliance(arg1,AllCompliance,&target,_exception);
3578 (void) TransparentPaintImage(_image,&target,(Quantum)
3579 TransparentAlpha,IsPlusOp,_exception);
3580 break;
3581 }
3582 if (LocaleCompare("transpose",option+1) == 0)
3583 {
3584 new_image=TransposeImage(_image,_exception);
3585 break;
3586 }
3587 if (LocaleCompare("transverse",option+1) == 0)
3588 {
3589 new_image=TransverseImage(_image,_exception);
3590 break;
3591 }
3592 if (LocaleCompare("trim",option+1) == 0)
3593 {
3594 new_image=TrimImage(_image,_exception);
3595 break;
3596 }
3597 if (LocaleCompare("type",option+1) == 0)
3598 {
3599 /* Note that "type" setting should have already been defined */
3600 (void) SetImageType(_image,_image_info->type,_exception);
3601 break;
3602 }
3603 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3604 }
3605 case 'u':
3606 {
3607 if (LocaleCompare("unique",option+1) == 0)
3608 {
3609 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3610 Option is not documented, bt appears to be for "identify".
3611 We may need a identify specific verbose!
3612 */
3613 if (IsPlusOp) {
3614 (void) DeleteImageArtifact(_image,"identify:unique-colors");
3615 break;
3616 }
3617 (void) SetImageArtifact(_image,"identify:unique-colors","true");
3618 (void) SetImageArtifact(_image,"verbose","true");
3619 break;
3620 }
3621 if (LocaleCompare("unique-colors",option+1) == 0)
3622 {
3623 new_image=UniqueImageColors(_image,_exception);
3624 break;
3625 }
3626 if (LocaleCompare("unsharp",option+1) == 0)
3627 {
3628 flags=ParseGeometry(arg1,&geometry_info);
3629 if ((flags & (RhoValue|SigmaValue)) == 0)
3630 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3631 if ((flags & SigmaValue) == 0)
3632 geometry_info.sigma=1.0;
3633 if ((flags & XiValue) == 0)
3634 geometry_info.xi=1.0;
3635 if ((flags & PsiValue) == 0)
3636 geometry_info.psi=0.05;
3637 new_image=UnsharpMaskImage(_image,geometry_info.rho,
3638 geometry_info.sigma,geometry_info.xi,geometry_info.psi,_exception);
3639 break;
3640 }
3641 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3642 }
3643 case 'v':
3644 {
3645 if (LocaleCompare("verbose",option+1) == 0)
3646 {
3647 /* FUTURE: move to SyncImageSettings() and AcquireImage()???
3648 three places! ImageArtifact ImageOption _image_info->verbose
3649 Some how new images also get this artifact!
3650 */
3651 (void) SetImageArtifact(_image,option+1,IfNormalOp ? "true" :
3652 "false" );
3653 break;
3654 }
3655 if (LocaleCompare("vignette",option+1) == 0)
3656 {
3657 flags=ParseGeometry(arg1,&geometry_info);
3658 if ((flags & (RhoValue|SigmaValue)) == 0)
3659 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3660 if ((flags & SigmaValue) == 0)
3661 geometry_info.sigma=1.0;
3662 if ((flags & XiValue) == 0)
3663 geometry_info.xi=0.1*_image->columns;
3664 if ((flags & PsiValue) == 0)
3665 geometry_info.psi=0.1*_image->rows;
3666 if ((flags & PercentValue) != 0)
3667 {
3668 geometry_info.xi*=(double) _image->columns/100.0;
3669 geometry_info.psi*=(double) _image->rows/100.0;
3670 }
3671 new_image=VignetteImage(_image,geometry_info.rho,geometry_info.sigma,
3672 (ssize_t) ceil(geometry_info.xi-0.5),(ssize_t)
3673 ceil(geometry_info.psi-0.5),_exception);
3674 break;
3675 }
3676 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3677 }
3678 case 'w':
3679 {
3680 if (LocaleCompare("wave",option+1) == 0)
3681 {
3682 flags=ParseGeometry(arg1,&geometry_info);
3683 if ((flags & (RhoValue|SigmaValue)) == 0)
3684 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3685 if ((flags & SigmaValue) == 0)
3686 geometry_info.sigma=1.0;
3687 new_image=WaveImage(_image,geometry_info.rho,geometry_info.sigma,
3688 _image->interpolate,_exception);
3689 break;
3690 }
3691 if (LocaleCompare("wavelet-denoise",option+1) == 0)
3692 {
3693 flags=ParseGeometry(arg1,&geometry_info);
3694 if ((flags & RhoValue) == 0)
3695 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3696 if ((flags & PercentValue) != 0)
3697 {
3698 geometry_info.rho=(double) QuantumRange*geometry_info.rho/100.0;
3699 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3700 100.0;
3701 }
3702 if ((flags & SigmaValue) == 0)
3703 geometry_info.sigma=0.0;
3704 new_image=WaveletDenoiseImage(_image,geometry_info.rho,
3705 geometry_info.sigma,_exception);
3706 break;
3707 }
3708 if (LocaleCompare("white-balance",option+1) == 0)
3709 {
3710 (void) WhiteBalanceImage(_image,_exception);
3711 break;
3712 }
3713 if (LocaleCompare("white-threshold",option+1) == 0)
3714 {
3715 if (IsGeometry(arg1) == MagickFalse)
3716 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
3717 (void) WhiteThresholdImage(_image,arg1,_exception);
3718 break;
3719 }
3720 if (LocaleCompare("write-mask",option+1) == 0)
3721 {
3722 /* Note: arguments do not have percent escapes expanded */
3723 Image
3724 *mask;
3725
3726 if (IfPlusOp)
3727 { /* Remove a mask. */
3728 (void) SetImageMask(_image,WritePixelMask,(const Image *) NULL,
3729 _exception);
3730 break;
3731 }
3732 /* Set the image mask. */
3733 mask=GetImageCache(_image_info,arg1,_exception);
3734 if (mask == (Image *) NULL)
3735 break;
3736 (void) SetImageMask(_image,WritePixelMask,mask,_exception);
3737 mask=DestroyImage(mask);
3738 break;
3739 }
3740 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3741 }
3742 default:
3743 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3744 }
3745 /* clean up percent escape interpreted strings */
3746 if (arg1 != arg1n )
3747 arg1=DestroyString((char *)arg1);
3748 if (arg2 != arg2n )
3749 arg2=DestroyString((char *)arg2);
3750
3751 /* Replace current image with any image that was generated
3752 and set image point to last image (so image->next is correct) */
3753 if (new_image != (Image *) NULL)
3754 ReplaceImageInListReturnLast(&_image,new_image);
3755
3756 return(MagickTrue);
3757#undef _image_info
3758#undef _draw_info
3759#undef _quantize_info
3760#undef _image
3761#undef _exception
3762#undef IfNormalOp
3763#undef IfPlusOp
3764#undef IsNormalOp
3765#undef IsPlusOp
3766}
3767
3768static MagickBooleanType CLISimpleOperatorImages(MagickCLI *cli_wand,
3769 const char *option,const char *arg1,const char *arg2,ExceptionInfo *exception)
3770{
3771#if !USE_WAND_METHODS
3772 size_t
3773 n,
3774 i;
3775#endif
3776
3777 assert(cli_wand != (MagickCLI *) NULL);
3778 assert(cli_wand->signature == MagickWandSignature);
3779 assert(cli_wand->wand.signature == MagickWandSignature);
3780 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3781
3782 if (cli_wand->wand.debug != MagickFalse)
3783 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3784 "- Simple Operator: %s \"%s\" \"%s\"", option,arg1,arg2);
3785
3786#if !USE_WAND_METHODS
3787 /* FUTURE add appropriate tracing */
3788 i=0;
3789 n=GetImageListLength(cli_wand->wand.images);
3790 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3791 while (1) {
3792 i++;
3793 CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3794 if ( cli_wand->wand.images->next == (Image *) NULL )
3795 break;
3796 cli_wand->wand.images=cli_wand->wand.images->next;
3797 }
3798 assert( i == n );
3799 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3800#else
3801 MagickResetIterator(&cli_wand->wand);
3802 while (MagickNextImage(&cli_wand->wand) != MagickFalse)
3803 (void) CLISimpleOperatorImage(cli_wand, option, arg1, arg2,exception);
3804 MagickResetIterator(&cli_wand->wand);
3805#endif
3806 return(MagickTrue);
3807}
3808␌
3809/*
3810%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3811% %
3812% %
3813% %
3814+ C L I L i s t O p e r a t o r I m a g e s %
3815% %
3816% %
3817% %
3818%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3819%
3820% CLIListOperatorImages() applies a single operation that is apply to the
3821% entire image list as a whole. The result is often a complete replacement
3822% of the image list with a completely new list, or with just a single image
3823% result.
3824%
3825% The format of the MogrifyImage method is:
3826%
3827% MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3828% const char *option,const char *arg1,const char *arg2)
3829%
3830% A description of each parameter follows:
3831%
3832% o cli_wand: structure holding settings to be applied
3833%
3834% o option: The option string for the operation
3835%
3836% o arg1, arg2: optional argument strings to the operation
3837% arg2 is currently not used
3838%
3839*/
3840static MagickBooleanType CLIListOperatorImages(MagickCLI *cli_wand,
3841 const char *option,const char *arg1n,const char *arg2n)
3842{
3843 const char /* percent escaped versions of the args */
3844 *arg1,
3845 *arg2;
3846
3847 Image
3848 *new_images;
3849
3850 MagickStatusType
3851 status;
3852
3853 ssize_t
3854 parse;
3855
3856#define _image_info (cli_wand->wand.image_info)
3857#define _images (cli_wand->wand.images)
3858#define _exception (cli_wand->wand.exception)
3859#define _draw_info (cli_wand->draw_info)
3860#define _quantize_info (cli_wand->quantize_info)
3861#define _process_flags (cli_wand->process_flags)
3862#define _option_type ((CommandOptionFlags) cli_wand->command->flags)
3863#define IfNormalOp (*option=='-')
3864#define IfPlusOp (*option!='-')
3865#define IsNormalOp IfNormalOp ? MagickTrue : MagickFalse
3866
3867 assert(cli_wand != (MagickCLI *) NULL);
3868 assert(cli_wand->signature == MagickWandSignature);
3869 assert(cli_wand->wand.signature == MagickWandSignature);
3870 assert(_images != (Image *) NULL); /* _images must be present */
3871
3872 if (cli_wand->wand.debug != MagickFalse)
3873 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
3874 "- List Operator: %s \"%s\" \"%s\"", option,
3875 arg1n == (const char *) NULL ? "null" : arg1n,
3876 arg2n == (const char *) NULL ? "null" : arg2n);
3877
3878 arg1 = arg1n;
3879 arg2 = arg2n;
3880
3881 /* Interpret Percent Escapes in Arguments - using first image */
3882 if ( (((_process_flags & ProcessInterpretProperties) != 0 )
3883 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
3884 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
3885 /* Interpret Percent escapes in argument 1 */
3886 if (arg1n != (char *) NULL) {
3887 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
3888 if (arg1 == (char *) NULL) {
3889 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3890 arg1=arg1n; /* use the given argument as is */
3891 }
3892 }
3893 if (arg2n != (char *) NULL) {
3894 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
3895 if (arg2 == (char *) NULL) {
3896 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
3897 arg2=arg2n; /* use the given argument as is */
3898 }
3899 }
3900 }
3901#undef _process_flags
3902#undef _option_type
3903
3904 status=MagickTrue;
3905 new_images=NewImageList();
3906
3907 switch (*(option+1))
3908 {
3909 case 'a':
3910 {
3911 if (LocaleCompare("append",option+1) == 0)
3912 {
3913 new_images=AppendImages(_images,IsNormalOp,_exception);
3914 break;
3915 }
3916 if (LocaleCompare("average",option+1) == 0)
3917 {
3918 CLIWandWarnReplaced("-evaluate-sequence Mean");
3919 (void) CLIListOperatorImages(cli_wand,"-evaluate-sequence","Mean",
3920 NULL);
3921 break;
3922 }
3923 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
3924 }
3925 case 'c':
3926 {
3927 if (LocaleCompare("channel-fx",option+1) == 0)
3928 {
3929 new_images=ChannelFxImage(_images,arg1,_exception);
3930 break;
3931 }
3932 if (LocaleCompare("clut",option+1) == 0)
3933 {
3934 Image
3935 *clut_image;
3936
3937 /* FUTURE - make this a compose option, and thus can be used
3938 with layers compose or even compose last image over all other
3939 _images.
3940 */
3941 new_images=RemoveFirstImageFromList(&_images);
3942 clut_image=RemoveFirstImageFromList(&_images);
3943 /* FUTURE - produce Exception, rather than silent fail */
3944 if (clut_image == (Image *) NULL)
3945 {
3946 (void) ThrowMagickException(_exception,GetMagickModule(),
3947 OptionError,"ImageSequenceRequired","`%s'",option);
3948 new_images=DestroyImage(new_images);
3949 status=MagickFalse;
3950 break;
3951 }
3952 (void) ClutImage(new_images,clut_image,new_images->interpolate,
3953 _exception);
3954 clut_image=DestroyImage(clut_image);
3955 break;
3956 }
3957 if (LocaleCompare("coalesce",option+1) == 0)
3958 {
3959 new_images=CoalesceImages(_images,_exception);
3960 break;
3961 }
3962 if (LocaleCompare("combine",option+1) == 0)
3963 {
3964 parse=(ssize_t) _images->colorspace;
3965 if (_images->number_channels < GetImageListLength(_images))
3966 parse=sRGBColorspace;
3967 if ( IfPlusOp )
3968 parse=ParseCommandOption(MagickColorspaceOptions,MagickFalse,arg1);
3969 if (parse < 0)
3970 CLIWandExceptArgBreak(OptionError,"UnrecognizedColorspace",option,
3971 arg1);
3972 new_images=CombineImages(_images,(ColorspaceType) parse,_exception);
3973 break;
3974 }
3975 if (LocaleCompare("compare",option+1) == 0)
3976 {
3977 double
3978 distortion;
3979
3980 Image
3981 *image,
3982 *reconstruct_image;
3983
3984 MetricType
3985 metric;
3986
3987 /*
3988 Mathematically and visually annotate the difference between an
3989 image and its reconstruction.
3990 */
3991 image=RemoveFirstImageFromList(&_images);
3992 reconstruct_image=RemoveFirstImageFromList(&_images);
3993 /* FUTURE - produce Exception, rather than silent fail */
3994 if (reconstruct_image == (Image *) NULL)
3995 {
3996 (void) ThrowMagickException(_exception,GetMagickModule(),
3997 OptionError,"ImageSequenceRequired","`%s'",option);
3998 image=DestroyImage(image);
3999 status=MagickFalse;
4000 break;
4001 }
4002 metric=UndefinedErrorMetric;
4003 option=GetImageOption(_image_info,"metric");
4004 if (option != (const char *) NULL)
4005 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4006 MagickFalse,option);
4007 new_images=CompareImages(image,reconstruct_image,metric,&distortion,
4008 _exception);
4009 (void) distortion;
4010 reconstruct_image=DestroyImage(reconstruct_image);
4011 image=DestroyImage(image);
4012 break;
4013 }
4014 if (LocaleCompare("complex",option+1) == 0)
4015 {
4016 parse=ParseCommandOption(MagickComplexOptions,MagickFalse,arg1);
4017 if (parse < 0)
4018 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
4019 option,arg1);
4020 new_images=ComplexImages(_images,(ComplexOperator) parse,_exception);
4021 break;
4022 }
4023 if (LocaleCompare("composite",option+1) == 0)
4024 {
4025 CompositeOperator
4026 compose;
4027
4028 const char*
4029 value;
4030
4031 MagickBooleanType
4032 clip_to_self;
4033
4034 Image
4035 *mask_image,
4036 *source_image;
4037
4038 RectangleInfo
4039 geometry;
4040
4041 /* Compose value from "-compose" option only */
4042 value=GetImageOption(_image_info,"compose");
4043 if (value == (const char *) NULL)
4044 compose=OverCompositeOp; /* use Over not source_image->compose */
4045 else
4046 compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
4047 MagickFalse,value);
4048
4049 /* Get "clip-to-self" expert setting (false is normal) */
4050 clip_to_self=GetCompositeClipToSelf(compose);
4051 value=GetImageOption(_image_info,"compose:clip-to-self");
4052 if (value != (const char *) NULL)
4053 clip_to_self=IsStringTrue(value);
4054 value=GetImageOption(_image_info,"compose:outside-overlay");
4055 if (value != (const char *) NULL)
4056 clip_to_self=IsStringFalse(value); /* deprecated */
4057
4058 new_images=RemoveFirstImageFromList(&_images);
4059 source_image=RemoveFirstImageFromList(&_images);
4060 if (source_image == (Image *) NULL)
4061 {
4062 (void) ThrowMagickException(_exception,GetMagickModule(),
4063 OptionError,"ImageSequenceRequired","`%s'",option);
4064 new_images=DestroyImage(new_images);
4065 status=MagickFalse;
4066 break;
4067 }
4068
4069 /* FUTURE - this should not be here! - should be part of -geometry */
4070 if (source_image->geometry != (char *) NULL)
4071 {
4072 RectangleInfo
4073 resize_geometry;
4074
4075 (void) ParseRegionGeometry(source_image,source_image->geometry,
4076 &resize_geometry,_exception);
4077 if ((source_image->columns != resize_geometry.width) ||
4078 (source_image->rows != resize_geometry.height))
4079 {
4080 Image
4081 *resize_image;
4082
4083 resize_image=ResizeImage(source_image,resize_geometry.width,
4084 resize_geometry.height,source_image->filter,_exception);
4085 if (resize_image != (Image *) NULL)
4086 {
4087 source_image=DestroyImage(source_image);
4088 source_image=resize_image;
4089 }
4090 }
4091 }
4092 SetGeometry(source_image,&geometry);
4093 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
4094 GravityAdjustGeometry(new_images->columns,new_images->rows,
4095 new_images->gravity, &geometry);
4096 mask_image=RemoveFirstImageFromList(&_images);
4097 if (mask_image == (Image *) NULL)
4098 status&=(MagickStatusType) CompositeImage(new_images,source_image,
4099 compose,clip_to_self,geometry.x,geometry.y,_exception);
4100 else
4101 {
4102 Image
4103 *canvas_image;
4104
4105 canvas_image=CloneImage(new_images,0,0,MagickTrue,_exception);
4106 if (canvas_image == (Image *) NULL)
4107 break;
4108 switch (compose)
4109 {
4110 case BlendCompositeOp:
4111 {
4112 status&=(MagickStatusType) CompositeImage(new_images,
4113 source_image,compose,clip_to_self,geometry.x,geometry.y,
4114 _exception);
4115 status&=(MagickStatusType) CompositeImage(new_images,
4116 mask_image,CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
4117 break;
4118 }
4119 case DisplaceCompositeOp:
4120 case DistortCompositeOp:
4121 {
4122 status&=(MagickStatusType) CompositeImage(source_image,
4123 mask_image,CopyGreenCompositeOp,MagickTrue,0,0,_exception);
4124 (void) SetImageColorspace(source_image,sRGBColorspace,
4125 _exception);
4126 status&=(MagickStatusType) CompositeImage(new_images,
4127 source_image,compose,clip_to_self,geometry.x,geometry.y,
4128 _exception);
4129 break;
4130 }
4131 case SaliencyBlendCompositeOp:
4132 case SeamlessBlendCompositeOp:
4133 {
4134 status&=(MagickStatusType) CompositeImage(source_image,
4135 mask_image,CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
4136 status&=(MagickStatusType) CompositeImage(new_images,
4137 source_image,compose,clip_to_self,geometry.x,geometry.y,
4138 _exception);
4139 break;
4140 }
4141 default:
4142 {
4143 Image
4144 *clone_image;
4145
4146 clone_image=CloneImage(new_images,0,0,MagickTrue,_exception);
4147 if (clone_image == (Image *) NULL)
4148 break;
4149 status&=(MagickStatusType) CompositeImage(new_images,
4150 source_image,compose,clip_to_self,geometry.x,geometry.y,
4151 _exception);
4152 status&=(MagickStatusType) CompositeImage(new_images,
4153 mask_image,CopyAlphaCompositeOp,MagickTrue,0,0,_exception);
4154 status&=(MagickStatusType) CompositeImage(clone_image,
4155 new_images,OverCompositeOp,clip_to_self,0,0,_exception);
4156 new_images=DestroyImageList(new_images);
4157 new_images=clone_image;
4158 break;
4159 }
4160 }
4161 switch (compose)
4162 {
4163 case DisplaceCompositeOp:
4164 case DistortCompositeOp:
4165 {
4166 status&=(MagickStatusType) CompositeImage(canvas_image,
4167 new_images,CopyCompositeOp,clip_to_self,0,0,_exception);
4168 break;
4169 }
4170 default:
4171 {
4172 status&=(MagickStatusType) CompositeImage(canvas_image,
4173 new_images,OverCompositeOp,clip_to_self,0,0,_exception);
4174 break;
4175 }
4176 }
4177 new_images=DestroyImageList(new_images);
4178 new_images=canvas_image;
4179 mask_image=DestroyImage(mask_image);
4180 }
4181 source_image=DestroyImage(source_image);
4182 break;
4183 }
4184 if (LocaleCompare("copy",option+1) == 0)
4185 {
4186 Image
4187 *source_image;
4188
4189 OffsetInfo
4190 offset;
4191
4192 RectangleInfo
4193 geometry;
4194
4195 /*
4196 Copy image pixels.
4197 */
4198 if (IsGeometry(arg1) == MagickFalse)
4199 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4200 if (IsGeometry(arg2) == MagickFalse)
4201 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4202 (void) ParsePageGeometry(_images,arg2,&geometry,_exception);
4203 offset.x=geometry.x;
4204 offset.y=geometry.y;
4205 source_image=_images;
4206 if (source_image->next != (Image *) NULL)
4207 source_image=source_image->next;
4208 (void) ParsePageGeometry(source_image,arg1,&geometry,_exception);
4209 (void) CopyImagePixels(_images,source_image,&geometry,&offset,
4210 _exception);
4211 break;
4212 }
4213 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4214 }
4215 case 'd':
4216 {
4217 if (LocaleCompare("deconstruct",option+1) == 0)
4218 {
4219 CLIWandWarnReplaced("-layers CompareAny");
4220 (void) CLIListOperatorImages(cli_wand,"-layers","CompareAny",NULL);
4221 break;
4222 }
4223 if (LocaleCompare("delete",option+1) == 0)
4224 {
4225 if (!IfNormalOp)
4226 {
4227 DeleteImages(&_images,"-1",_exception);
4228 break;
4229 }
4230 if (LocaleNCompare(arg1,"registry:",9) == 0)
4231 {
4232 (void) DeleteImageRegistry(arg1+9);
4233 break;
4234 }
4235 if (IsSceneGeometry(arg1,MagickFalse) == MagickFalse)
4236 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
4237 DeleteImages(&_images,arg1,_exception);
4238 break;
4239 }
4240 if (LocaleCompare("duplicate",option+1) == 0)
4241 {
4242 if (!IfNormalOp)
4243 new_images=DuplicateImages(_images,1,"-1",_exception);
4244 else
4245 {
4246 const char
4247 *p;
4248
4249 size_t
4250 number_duplicates;
4251
4252 if (IsGeometry(arg1) == MagickFalse)
4253 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,
4254 arg1);
4255 number_duplicates=(size_t) StringToLong(arg1);
4256 if (arg1 == (char *) NULL)
4257 break;
4258 p=strchr(arg1,',');
4259 if (p == (const char *) NULL)
4260 new_images=DuplicateImages(_images,number_duplicates,"-1",
4261 _exception);
4262 else
4263 new_images=DuplicateImages(_images,number_duplicates,p+1,
4264 _exception);
4265 }
4266 AppendImageToList(&_images, new_images);
4267 new_images=(Image *) NULL;
4268 break;
4269 }
4270 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4271 }
4272 case 'e':
4273 {
4274 if (LocaleCompare("evaluate-sequence",option+1) == 0)
4275 {
4276 parse=ParseCommandOption(MagickEvaluateOptions,MagickFalse,arg1);
4277 if (parse < 0)
4278 CLIWandExceptArgBreak(OptionError,"UnrecognizedEvaluateOperator",
4279 option,arg1);
4280 new_images=EvaluateImages(_images,(MagickEvaluateOperator) parse,
4281 _exception);
4282 break;
4283 }
4284 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4285 }
4286 case 'f':
4287 {
4288 if (LocaleCompare("fft",option+1) == 0)
4289 {
4290 new_images=ForwardFourierTransformImage(_images,IsNormalOp,
4291 _exception);
4292 break;
4293 }
4294 if (LocaleCompare("flatten",option+1) == 0)
4295 {
4296 /* REDIRECTED to use -layers flatten instead */
4297 (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4298 break;
4299 }
4300 if (LocaleCompare("fx",option+1) == 0)
4301 {
4302 new_images=FxImage(_images,arg1,_exception);
4303 break;
4304 }
4305 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4306 }
4307 case 'h':
4308 {
4309 if (LocaleCompare("hald-clut",option+1) == 0)
4310 {
4311 /* FUTURE - make this a compose option (and thus layers compose )
4312 or perhaps compose last image over all other _images.
4313 */
4314 Image
4315 *hald_image;
4316
4317 new_images=RemoveFirstImageFromList(&_images);
4318 hald_image=RemoveLastImageFromList(&_images);
4319 if (hald_image == (Image *) NULL)
4320 {
4321 (void) ThrowMagickException(_exception,GetMagickModule(),
4322 OptionError,"ImageSequenceRequired","`%s'",option);
4323 new_images=DestroyImage(new_images);
4324 status=MagickFalse;
4325 break;
4326 }
4327 (void) HaldClutImage(new_images,hald_image,_exception);
4328 hald_image=DestroyImage(hald_image);
4329 break;
4330 }
4331 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4332 }
4333 case 'i':
4334 {
4335 if (LocaleCompare("ift",option+1) == 0)
4336 {
4337 Image
4338 *magnitude_image,
4339 *phase_image;
4340
4341 magnitude_image=RemoveFirstImageFromList(&_images);
4342 phase_image=RemoveFirstImageFromList(&_images);
4343 if (phase_image == (Image *) NULL)
4344 {
4345 (void) ThrowMagickException(_exception,GetMagickModule(),
4346 OptionError,"ImageSequenceRequired","`%s'",option);
4347 magnitude_image=DestroyImage(magnitude_image);
4348 status=MagickFalse;
4349 break;
4350 }
4351 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
4352 IsNormalOp,_exception);
4353 magnitude_image=DestroyImage(magnitude_image);
4354 phase_image=DestroyImage(phase_image);
4355 break;
4356 }
4357 if (LocaleCompare("insert",option+1) == 0)
4358 {
4359 Image
4360 *insert_image,
4361 *index_image;
4362
4363 ssize_t
4364 index;
4365
4366 if (IfNormalOp && (IsGeometry(arg1) == MagickFalse))
4367 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4368 index=0;
4369 insert_image=RemoveLastImageFromList(&_images);
4370 if (IfNormalOp)
4371 index=(ssize_t) StringToLong(arg1);
4372 index_image=insert_image;
4373 if (index == 0)
4374 PrependImageToList(&_images,insert_image);
4375 else if (index == (ssize_t) GetImageListLength(_images))
4376 AppendImageToList(&_images,insert_image);
4377 else
4378 {
4379 index_image=GetImageFromList(_images,index-1);
4380 if (index_image == (Image *) NULL)
4381 {
4382 insert_image=DestroyImage(insert_image);
4383 CLIWandExceptArgBreak(OptionError,"NoSuchImage",option,arg1);
4384 }
4385 InsertImageInList(&index_image,insert_image);
4386 }
4387 _images=GetFirstImageInList(index_image);
4388 break;
4389 }
4390 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4391 }
4392 case 'l':
4393 {
4394 if (LocaleCompare("layers",option+1) == 0)
4395 {
4396 parse=ParseCommandOption(MagickLayerOptions,MagickFalse,arg1);
4397 if ( parse < 0 )
4398 CLIWandExceptArgBreak(OptionError,"UnrecognizedLayerMethod",
4399 option,arg1);
4400 switch ((LayerMethod) parse)
4401 {
4402 case CoalesceLayer:
4403 {
4404 new_images=CoalesceImages(_images,_exception);
4405 break;
4406 }
4407 case CompareAnyLayer:
4408 case CompareClearLayer:
4409 case CompareOverlayLayer:
4410 default:
4411 {
4412 new_images=CompareImagesLayers(_images,(LayerMethod) parse,
4413 _exception);
4414 break;
4415 }
4416 case MergeLayer:
4417 case FlattenLayer:
4418 case MosaicLayer:
4419 case TrimBoundsLayer:
4420 {
4421 new_images=MergeImageLayers(_images,(LayerMethod) parse,
4422 _exception);
4423 break;
4424 }
4425 case DisposeLayer:
4426 {
4427 new_images=DisposeImages(_images,_exception);
4428 break;
4429 }
4430 case OptimizeImageLayer:
4431 {
4432 new_images=OptimizeImageLayers(_images,_exception);
4433 break;
4434 }
4435 case OptimizePlusLayer:
4436 {
4437 new_images=OptimizePlusImageLayers(_images,_exception);
4438 break;
4439 }
4440 case OptimizeTransLayer:
4441 {
4442 OptimizeImageTransparency(_images,_exception);
4443 break;
4444 }
4445 case RemoveDupsLayer:
4446 {
4447 RemoveDuplicateLayers(&_images,_exception);
4448 break;
4449 }
4450 case RemoveZeroLayer:
4451 {
4452 RemoveZeroDelayLayers(&_images,_exception);
4453 break;
4454 }
4455 case OptimizeLayer:
4456 { /* General Purpose, GIF Animation Optimizer. */
4457 new_images=CoalesceImages(_images,_exception);
4458 if (new_images == (Image *) NULL)
4459 break;
4460 _images=DestroyImageList(_images);
4461 _images=OptimizeImageLayers(new_images,_exception);
4462 if (_images == (Image *) NULL)
4463 break;
4464 new_images=DestroyImageList(new_images);
4465 OptimizeImageTransparency(_images,_exception);
4466 (void) RemapImages(_quantize_info,_images,(Image *) NULL,
4467 _exception);
4468 break;
4469 }
4470 case CompositeLayer:
4471 {
4472 Image
4473 *source;
4474
4475 RectangleInfo
4476 geometry;
4477
4478 CompositeOperator
4479 compose;
4480
4481 const char*
4482 value;
4483
4484 value=GetImageOption(_image_info,"compose");
4485 compose=OverCompositeOp; /* Default to Over */
4486 if (value != (const char *) NULL)
4487 compose=(CompositeOperator) ParseCommandOption(
4488 MagickComposeOptions,MagickFalse,value);
4489
4490 /* Split image sequence at the first 'NULL:' image. */
4491 source=_images;
4492 while (source != (Image *) NULL)
4493 {
4494 source=GetNextImageInList(source);
4495 if ((source != (Image *) NULL) &&
4496 (LocaleCompare(source->magick,"NULL") == 0))
4497 break;
4498 }
4499 if (source != (Image *) NULL)
4500 {
4501 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
4502 (GetNextImageInList(source) == (Image *) NULL))
4503 source=(Image *) NULL;
4504 else
4505 { /* Separate the two lists, junk the null: image. */
4506 source=SplitImageList(source->previous);
4507 DeleteImageFromList(&source);
4508 }
4509 }
4510 if (source == (Image *) NULL)
4511 {
4512 (void) ThrowMagickException(_exception,GetMagickModule(),
4513 OptionError,"MissingNullSeparator","layers Composite");
4514 break;
4515 }
4516 /* Adjust offset with gravity and virtual canvas. */
4517 SetGeometry(_images,&geometry);
4518 (void) ParseAbsoluteGeometry(_images->geometry,&geometry);
4519 geometry.width=source->page.width != 0 ?
4520 source->page.width : source->columns;
4521 geometry.height=source->page.height != 0 ?
4522 source->page.height : source->rows;
4523 GravityAdjustGeometry(_images->page.width != 0 ?
4524 _images->page.width : _images->columns,
4525 _images->page.height != 0 ? _images->page.height :
4526 _images->rows,_images->gravity,&geometry);
4527
4528 /* Compose the two image sequences together */
4529 CompositeLayers(_images,compose,source,geometry.x,geometry.y,
4530 _exception);
4531 source=DestroyImageList(source);
4532 break;
4533 }
4534 }
4535 break;
4536 }
4537 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4538 }
4539 case 'm':
4540 {
4541 if (LocaleCompare("map",option+1) == 0)
4542 {
4543 CLIWandWarnReplaced("+remap");
4544 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4545 break;
4546 }
4547 if (LocaleCompare("metric",option+1) == 0)
4548 {
4549 (void) SetImageOption(_image_info,option+1,arg1);
4550 break;
4551 }
4552 if (LocaleCompare("morph",option+1) == 0)
4553 {
4554 Image
4555 *morph_image;
4556
4557 if (IsGeometry(arg1) == MagickFalse)
4558 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4559 morph_image=MorphImages(_images,StringToUnsignedLong(arg1),
4560 _exception);
4561 if (morph_image == (Image *) NULL)
4562 break;
4563 _images=DestroyImageList(_images);
4564 _images=morph_image;
4565 break;
4566 }
4567 if (LocaleCompare("mosaic",option+1) == 0)
4568 {
4569 /* REDIRECTED to use -layers mosaic instead */
4570 (void) CLIListOperatorImages(cli_wand,"-layers",option+1,NULL);
4571 break;
4572 }
4573 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4574 }
4575 case 'p':
4576 {
4577 if (LocaleCompare("poly",option+1) == 0)
4578 {
4579 double
4580 *args;
4581
4582 ssize_t
4583 count;
4584
4585 /* convert argument string into an array of doubles */
4586 args = StringToArrayOfDoubles(arg1,&count,_exception);
4587 if (args == (double *) NULL )
4588 CLIWandExceptArgBreak(OptionError,"InvalidNumberList",option,arg1);
4589 new_images=PolynomialImage(_images,(size_t) (count >> 1),args,
4590 _exception);
4591 args=(double *) RelinquishMagickMemory(args);
4592 break;
4593 }
4594 if (LocaleCompare("process",option+1) == 0)
4595 {
4596#define DestroyArguments(arguments,number_arguments) \
4597 do \
4598 { \
4599 ssize_t j = 0; \
4600 for ( ; j < (ssize_t) (number_arguments); j++) \
4601 (arguments)[j]=DestroyString((arguments)[j]); \
4602 (arguments)=(char **) RelinquishMagickMemory(arguments); \
4603 } while (0)
4604
4605 char
4606 **arguments;
4607
4608 int
4609 number_arguments;
4610
4611 arguments=StringToArgv(arg1,&number_arguments);
4612 if ((arguments == (char **) NULL) || (number_arguments == 1))
4613 {
4614 DestroyArguments(arguments,number_arguments);
4615 break;
4616 }
4617 if (strchr(arguments[1],'=') != (char *) NULL)
4618 {
4619 char
4620 breaker,
4621 quote,
4622 *token;
4623
4624 const char
4625 *p;
4626
4627 int
4628 next,
4629 tokenizer_status;
4630
4631 size_t
4632 length;
4633
4634 TokenInfo
4635 *token_info;
4636
4637 /*
4638 Support old style syntax, filter="-option arg1".
4639 */
4640 assert(arg1 != (const char *) NULL);
4641 length=strlen(arg1);
4642 token=(char *) NULL;
4643 if (~length >= (MagickPathExtent-1))
4644 token=(char *) AcquireQuantumMemory(length+MagickPathExtent,
4645 sizeof(*token));
4646 if (token == (char *) NULL)
4647 {
4648 DestroyArguments(arguments,number_arguments);
4649 break;
4650 }
4651 next=0;
4652 p=arg1;
4653 token_info=AcquireTokenInfo();
4654 tokenizer_status=Tokenizer(token_info,0,token,length,p,"","=",
4655 "\"",'\0',&breaker,&next,&quote);
4656 token_info=DestroyTokenInfo(token_info);
4657 if (tokenizer_status == 0)
4658 {
4659 const char
4660 *argv;
4661
4662 argv=(&(p[next]));
4663 (void) InvokeDynamicImageFilter(token,&_images,1,&argv,
4664 _exception);
4665 }
4666 token=DestroyString(token);
4667 DestroyArguments(arguments,number_arguments);
4668 break;
4669 }
4670 (void) SubstituteString(&arguments[1],"-","");
4671 (void) InvokeDynamicImageFilter(arguments[1],&_images,
4672 number_arguments-2,(const char **) arguments+2,_exception);
4673 DestroyArguments(arguments,number_arguments);
4674 break;
4675 }
4676 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4677 }
4678 case 'r':
4679 {
4680 if (LocaleCompare("remap",option+1) == 0)
4681 {
4682 (void) RemapImages(_quantize_info,_images,(Image *) NULL,_exception);
4683 break;
4684 }
4685 if (LocaleCompare("reverse",option+1) == 0)
4686 {
4687 ReverseImageList(&_images);
4688 break;
4689 }
4690 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4691 }
4692 case 's':
4693 {
4694 if (LocaleCompare("smush",option+1) == 0)
4695 {
4696 /* FUTURE: this option needs more work to make better */
4697 ssize_t
4698 offset;
4699
4700 if (IsGeometry(arg1) == MagickFalse)
4701 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4702 offset=(ssize_t) StringToLong(arg1);
4703 new_images=SmushImages(_images,IsNormalOp,offset,_exception);
4704 break;
4705 }
4706 if (LocaleCompare("subimage",option+1) == 0)
4707 {
4708 Image
4709 *base_image,
4710 *compare_image;
4711
4712 const char
4713 *value;
4714
4715 MetricType
4716 metric;
4717
4718 double
4719 similarity;
4720
4721 RectangleInfo
4722 offset;
4723
4724 base_image=GetImageFromList(_images,0);
4725 compare_image=GetImageFromList(_images,1);
4726
4727 /* Comparison Metric */
4728 metric=UndefinedErrorMetric;
4729 value=GetImageOption(_image_info,"metric");
4730 if (value != (const char *) NULL)
4731 metric=(MetricType) ParseCommandOption(MagickMetricOptions,
4732 MagickFalse,value);
4733
4734 new_images=SimilarityImage(base_image,compare_image,metric,0.0,
4735 &offset,&similarity,_exception);
4736
4737 if (new_images != (Image *) NULL)
4738 {
4739 (void) FormatImageProperty(new_images,"subimage:similarity",
4740 "%.*g",GetMagickPrecision(),similarity);
4741 (void) FormatImageProperty(new_images,"subimage:x","%+ld",(long)
4742 offset.x);
4743 (void) FormatImageProperty(new_images,"subimage:y","%+ld",(long)
4744 offset.y);
4745 (void) FormatImageProperty(new_images,"subimage:offset",
4746 "%lux%lu%+ld%+ld",(unsigned long) offset.width,(unsigned long)
4747 offset.height,(long) offset.x,(long) offset.y);
4748 }
4749 break;
4750 }
4751 if (LocaleCompare("swap",option+1) == 0)
4752 {
4753 Image
4754 *p,
4755 *q,
4756 *swap;
4757
4758 ssize_t
4759 index,
4760 swap_index;
4761
4762 index=(-1);
4763 swap_index=(-2);
4764 if (IfNormalOp) {
4765 GeometryInfo
4766 geometry_info;
4767
4768 MagickStatusType
4769 flags;
4770
4771 swap_index=(-1);
4772 flags=ParseGeometry(arg1,&geometry_info);
4773 if ((flags & RhoValue) == 0)
4774 CLIWandExceptArgBreak(OptionError,"InvalidArgument",option,arg1);
4775 index=(ssize_t) geometry_info.rho;
4776 if ((flags & SigmaValue) != 0)
4777 swap_index=(ssize_t) geometry_info.sigma;
4778 }
4779 p=GetImageFromList(_images,index);
4780 q=GetImageFromList(_images,swap_index);
4781 if ((p == (Image *) NULL) || (q == (Image *) NULL)) {
4782 if (IfNormalOp)
4783 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1)
4784 else
4785 CLIWandExceptionBreak(OptionError,"TwoOrMoreImagesRequired",option);
4786 }
4787 if (p == q)
4788 CLIWandExceptArgBreak(OptionError,"InvalidImageIndex",option,arg1);
4789 swap=CloneImage(p,0,0,MagickTrue,_exception);
4790 if (swap == (Image *) NULL)
4791 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4792 option,(char *) NULL);
4793 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,_exception));
4794 ReplaceImageInList(&q,swap);
4795 _images=GetFirstImageInList(q);
4796 break;
4797 }
4798 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4799 }
4800 default:
4801 CLIWandExceptionBreak(OptionError,"UnrecognizedOption",option);
4802 }
4803
4804 /* clean up percent escape interpreted strings */
4805 if (arg1 != arg1n )
4806 arg1=DestroyString((char *)arg1);
4807 if (arg2 != arg2n )
4808 arg2=DestroyString((char *)arg2);
4809
4810 /* if new image list generated, replace existing image list */
4811 if (new_images == (Image *) NULL)
4812 return(status == 0 ? MagickFalse : MagickTrue);
4813 _images=DestroyImageList(_images);
4814 _images=GetFirstImageInList(new_images);
4815 return(status == 0 ? MagickFalse : MagickTrue);
4816
4817#undef _image_info
4818#undef _images
4819#undef _exception
4820#undef _draw_info
4821#undef _quantize_info
4822#undef IfNormalOp
4823#undef IfPlusOp
4824#undef IsNormalOp
4825}
4826␌
4827/*
4828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4829% %
4830% %
4831% %
4832+ C L I N o I m a g e O p e r a t i o n s %
4833% %
4834% %
4835% %
4836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4837%
4838% CLINoImageOperator() Applies operations that may not actually need images
4839% in an image list.
4840%
4841% The classic operators of this type is "-read", which actually creates
4842% images even when no images are present. Or image stack operators, which
4843% can be applied (push or pop) to an empty image list.
4844%
4845% Note that these operators may involve other special 'option' prefix
4846% characters other than '-' or '+', namely parenthesis and braces.
4847%
4848% The format of the CLINoImageOption method is:
4849%
4850% void CLINoImageOption(MagickCLI *cli_wand,const char *option,
4851% const char *arg1, const char *arg2)
4852%
4853% A description of each parameter follows:
4854%
4855% o cli_wand: the main CLI Wand to use. (sometimes not required)
4856%
4857% o option: The special option (with any switch char) to process
4858%
4859% o arg1 & arg2: Argument for option, if required
4860% Currently arg2 is not used.
4861%
4862*/
4863static void CLINoImageOperator(MagickCLI *cli_wand,const char *option,
4864 const char *arg1n,const char *arg2n)
4865{
4866 const char /* percent escaped versions of the args */
4867 *arg1 = arg1n,
4868 *arg2 = arg2n;
4869
4870#define _image_info (cli_wand->wand.image_info)
4871#define _images (cli_wand->wand.images)
4872#define _exception (cli_wand->wand.exception)
4873#define _process_flags (cli_wand->process_flags)
4874#define _option_type ((CommandOptionFlags) cli_wand->command->flags)
4875#define IfNormalOp (*option=='-')
4876#define IfPlusOp (*option!='-')
4877
4878 assert(cli_wand != (MagickCLI *) NULL);
4879 assert(cli_wand->signature == MagickWandSignature);
4880 assert(cli_wand->wand.signature == MagickWandSignature);
4881
4882 if (cli_wand->wand.debug != MagickFalse)
4883 (void) CLILogEvent(cli_wand,CommandEvent,GetMagickModule(),
4884 "- NoImage Operator: %s \"%s\" \"%s\"", option,
4885 arg1n != (char *) NULL ? arg1n : "",
4886 arg2n != (char *) NULL ? arg2n : "");
4887
4888 /* Interpret Percent Escapes in Arguments - using first image */
4889 if ( (((_process_flags & ProcessInterpretProperties) != 0 )
4890 || ((_option_type & AlwaysInterpretArgsFlag) != 0)
4891 ) && ((_option_type & NeverInterpretArgsFlag) == 0) ) {
4892 /* Interpret Percent escapes in argument 1 */
4893 if (arg1n != (char *) NULL) {
4894 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
4895 if (arg1 == (char *) NULL) {
4896 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4897 arg1=arg1n; /* use the given argument as is */
4898 }
4899 }
4900 if (arg2n != (char *) NULL) {
4901 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
4902 if (arg2 == (char *) NULL) {
4903 CLIWandException(OptionWarning,"InterpretPropertyFailure",option);
4904 arg2=arg2n; /* use the given argument as is */
4905 }
4906 }
4907 }
4908#undef _process_flags
4909#undef _option_type
4910
4911 do { /* break to exit code */
4912 /*
4913 No-op options (ignore these)
4914 */
4915 if (LocaleCompare("noop",option+1) == 0) /* zero argument */
4916 break;
4917 if (LocaleCompare("sans",option+1) == 0) /* one argument */
4918 break;
4919 if (LocaleCompare("sans0",option+1) == 0) /* zero argument */
4920 break;
4921 if (LocaleCompare("sans1",option+1) == 0) /* one argument */
4922 break;
4923 if (LocaleCompare("sans2",option+1) == 0) /* two arguments */
4924 break;
4925 /*
4926 Image Reading
4927 */
4928 if ( ( LocaleCompare("read",option+1) == 0 ) ||
4929 ( LocaleCompare("--",option) == 0 ) ) {
4930 int argc;
4931 char **argv;
4932 ssize_t i;
4933
4934 argc = 1;
4935 argv = (char **) &arg1;
4936
4937 if (ExpandFilenames(&argc,&argv) == MagickFalse)
4938 CLIWandExceptArgBreak(ResourceLimitError,"MemoryAllocationFailed",
4939 option,(char *) NULL);
4940
4941 for (i=0; i < (ssize_t) argc; i++) {
4942 Image *new_images;
4943 if (_image_info->ping != MagickFalse)
4944 new_images=PingImages(_image_info,argv[i],_exception);
4945 else
4946 new_images=ReadImages(_image_info,argv[i],_exception);
4947 AppendImageToList(&_images, new_images);
4948 argv[i]=DestroyString(argv[i]);
4949 }
4950 argv=(char **) RelinquishMagickMemory(argv);
4951 break;
4952 }
4953 /*
4954 Image Writing
4955 Note: Writing a empty image list is valid in specific cases
4956 */
4957 if (LocaleCompare("write",option+1) == 0) {
4958 char key[MagickPathExtent];
4959 Image *write_images;
4960 ImageInfo *write_info;
4961
4962 if ( _images == (Image *) NULL ) {
4963 if ( LocaleCompare(arg1,"null:") == 0 )
4964 break;
4965 CLIWandExceptArgBreak(OptionError,"NoImagesForWrite",option,arg1);
4966 }
4967
4968 (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",arg1);
4969 (void) DeleteImageRegistry(key);
4970 write_images=CloneImageList(_images,_exception);
4971 write_info=CloneImageInfo(_image_info);
4972 if (write_images != (Image *) NULL)
4973 (void) WriteImages(write_info,write_images,arg1,_exception);
4974 write_info=DestroyImageInfo(write_info);
4975 write_images=DestroyImageList(write_images);
4976 break;
4977 }
4978 /*
4979 Parenthesis and Brace operations
4980 */
4981 if (LocaleCompare("(",option) == 0) {
4982 CLIStack *node;
4983 size_t size;
4984
4985 size=0;
4986 node=cli_wand->image_list_stack;
4987 for ( ; node != (CLIStack *) NULL; node=node->next)
4988 size++;
4989 if ( size >= MAX_STACK_DEPTH )
4990 CLIWandExceptionBreak(OptionError,"ParenthesisNestedTooDeeply",option);
4991 node=(CLIStack *) AcquireMagickMemory(sizeof(*node));
4992 if (node == (CLIStack *) NULL)
4993 CLIWandExceptionBreak(ResourceLimitFatalError,
4994 "MemoryAllocationFailed",option);
4995 node->data = (void *)cli_wand->wand.images;
4996 node->next = cli_wand->image_list_stack;
4997 cli_wand->image_list_stack = node;
4998 cli_wand->wand.images = NewImageList();
4999
5000 if (IsStringTrue(GetImageOption(cli_wand->wand.image_info,
5001 "respect-parentheses")) != MagickFalse)
5002 option="{"; /* fall-thru so as to push image settings too */
5003 else
5004 break;
5005 /* fall thru to operation */
5006 }
5007 if (LocaleCompare("{",option) == 0) {
5008 CLIStack *node;
5009 size_t size;
5010
5011 size=0;
5012 node=cli_wand->image_info_stack;
5013 for ( ; node != (CLIStack *) NULL; node=node->next)
5014 size++;
5015 if ( size >= MAX_STACK_DEPTH )
5016 CLIWandExceptionBreak(OptionError,"CurlyBracesNestedTooDeeply",option);
5017 node=(CLIStack *) AcquireMagickMemory(sizeof(*node));
5018 if (node == (CLIStack *) NULL)
5019 CLIWandExceptionBreak(ResourceLimitFatalError,
5020 "MemoryAllocationFailed",option);
5021
5022 node->data = (void *)cli_wand->wand.image_info;
5023 node->next = cli_wand->image_info_stack;
5024
5025 cli_wand->image_info_stack = node;
5026 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
5027 if (cli_wand->wand.image_info == (ImageInfo *) NULL) {
5028 CLIWandException(ResourceLimitFatalError,"MemoryAllocationFailed",
5029 option);
5030 cli_wand->wand.image_info = (ImageInfo *)node->data;
5031 node = (CLIStack *)RelinquishMagickMemory(node);
5032 break;
5033 }
5034
5035 break;
5036 }
5037 if (LocaleCompare(")",option) == 0) {
5038 CLIStack *node;
5039
5040 node = (CLIStack *)cli_wand->image_list_stack;
5041 if ( node == (CLIStack *) NULL)
5042 CLIWandExceptionBreak(OptionError,"UnbalancedParenthesis",option);
5043 cli_wand->image_list_stack = node->next;
5044
5045 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
5046 cli_wand->wand.images= (Image *)node->data;
5047 node = (CLIStack *)RelinquishMagickMemory(node);
5048
5049 node = cli_wand->image_info_stack;
5050 if ( node != (CLIStack *) NULL)
5051 {
5052 if (IsStringTrue(GetImageOption(cli_wand->wand.image_info,"respect-parentheses")) != MagickFalse)
5053 option="}"; /* fall-thru so as to pop image settings too */
5054 else
5055 break;
5056 }
5057 else
5058 break;
5059 /* fall thru to next if */
5060 }
5061 if (LocaleCompare("}",option) == 0) {
5062 CLIStack *node;
5063
5064 node = (CLIStack *)cli_wand->image_info_stack;
5065 if ( node == (CLIStack *) NULL)
5066 CLIWandExceptionBreak(OptionError,"UnbalancedCurlyBraces",option);
5067 cli_wand->image_info_stack = node->next;
5068
5069 (void) DestroyImageInfo(cli_wand->wand.image_info);
5070 cli_wand->wand.image_info = (ImageInfo *)node->data;
5071 node = (CLIStack *)RelinquishMagickMemory(node);
5072
5073 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
5074 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
5075 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
5076
5077 break;
5078 }
5079 if (LocaleCompare("print",option+1) == 0)
5080 {
5081 (void) FormatLocaleFile(stdout,"%s",arg1);
5082 break;
5083 }
5084 if (LocaleCompare("set",option+1) == 0)
5085 {
5086 /* Settings are applied to each image in memory in turn (if any).
5087 While a option: only need to be applied once globally.
5088
5089 NOTE: Arguments have not been automatically percent expanded
5090 */
5091
5092 StringInfo *profile = (StringInfo *) NULL;
5093
5094 /* FIX: avoid leaking previously interpreted arg1 from header */
5095 if (arg1 != arg1n)
5096 arg1 = DestroyString((char *) arg1);
5097
5098 /* escape the 'key' once only, using first image. */
5099 arg1=InterpretImageProperties(_image_info,_images,arg1n,_exception);
5100 if (arg1 == (char *) NULL)
5101 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
5102 option);
5103
5104 if (LocaleNCompare(arg1,"registry:",9) == 0)
5105 {
5106 if (IfPlusOp)
5107 {
5108 (void) DeleteImageRegistry(arg1+9);
5109 arg1=DestroyString((char *)arg1);
5110 break;
5111 }
5112
5113 /* FIX: avoid leaking previously interpreted arg2 from header */
5114 if (arg2 != arg2n)
5115 arg2 = DestroyString((char *) arg2);
5116
5117 arg2=InterpretImageProperties(_image_info,_images,arg2n,_exception);
5118 if (arg2 == (char *) NULL) {
5119 arg1=DestroyString((char *)arg1);
5120 CLIWandExceptionBreak(OptionWarning,"InterpretPropertyFailure",
5121 option);
5122 }
5123 (void) SetImageRegistry(StringRegistryType,arg1+9,arg2,_exception);
5124 arg1=DestroyString((char *)arg1);
5125 arg2=DestroyString((char *)arg2);
5126 break;
5127 }
5128 if (LocaleNCompare(arg1,"option:",7) == 0)
5129 {
5130 /* delete equivalent artifact from all images (if any) */
5131 if (_images != (Image *) NULL)
5132 {
5133 MagickResetIterator(&cli_wand->wand);
5134 while (MagickNextImage(&cli_wand->wand) != MagickFalse)
5135 (void) DeleteImageArtifact(_images,arg1+7);
5136 MagickResetIterator(&cli_wand->wand);
5137 }
5138 /* now set/delete the global option as needed */
5139 /* FUTURE: make escapes in a global 'option:' delayed */
5140 arg2=(char *) NULL;
5141 if (IfNormalOp)
5142 {
5143 /* FIX: avoid leaking previously interpreted arg2 from header */
5144 if (arg2 != arg2n)
5145 arg2 = DestroyString((char *) arg2);
5146
5147 arg2=InterpretImageProperties(_image_info,_images,arg2n,
5148 _exception);
5149 if (arg2 == (char *) NULL)
5150 CLIWandExceptionBreak(OptionWarning,
5151 "InterpretPropertyFailure",option);
5152 }
5153 (void) SetImageOption(_image_info,arg1+7,arg2);
5154 arg1=DestroyString((char *) arg1);
5155 arg2=DestroyString((char *) arg2);
5156 break;
5157 }
5158 if (LocaleCompare(arg1,"profile") == 0)
5159 {
5160 if (arg2 != (char *) NULL)
5161 (void) CopyMagickString(_image_info->filename,arg2,
5162 MagickPathExtent);
5163 (void) SetImageInfo(_image_info,1,_exception);
5164 if (LocaleCompare(_image_info->filename,"-") != 0)
5165 profile=FileToStringInfo(_image_info->filename,~0UL,_exception);
5166 }
5167 /* Set Artifacts/Properties/Attributes all images (required) */
5168 if ( _images == (Image *) NULL )
5169 {
5170 if (profile != (StringInfo *) NULL)
5171 profile=DestroyStringInfo(profile);
5172 CLIWandExceptArgBreak(OptionWarning,"NoImageForProperty",option,arg1);
5173 }
5174
5175 MagickResetIterator(&cli_wand->wand);
5176 while (MagickNextImage(&cli_wand->wand) != MagickFalse)
5177 {
5178 arg2=(char *) NULL;
5179 if (IfNormalOp)
5180 {
5181 /* FIX: avoid leaking previously interpreted arg2 from header */
5182 if (arg2 != arg2n)
5183 arg2 = DestroyString((char *) arg2);
5184
5185 arg2=InterpretImageProperties(_image_info,_images,arg2n,
5186 _exception);
5187 if (arg2 == (char *) NULL)
5188 {
5189 if (profile != (StringInfo *) NULL)
5190 profile=DestroyStringInfo(profile);
5191 CLIWandExceptionBreak(OptionWarning,
5192 "InterpretPropertyFailure",option);
5193 }
5194 }
5195 if (LocaleNCompare(arg1,"artifact:",9) == 0)
5196 (void) SetImageArtifact(_images,arg1+9,arg2);
5197 else if (LocaleNCompare(arg1,"property:",9) == 0)
5198 (void) SetImageProperty(_images,arg1+9,arg2,_exception);
5199 else
5200 (void) SetImageProperty(_images,arg1,arg2,_exception);
5201 if (profile != (StringInfo *) NULL)
5202 (void) SetImageProfile(_images,_image_info->magick,profile,
5203 _exception);
5204 arg2=DestroyString((char *)arg2);
5205 }
5206 if (profile != (StringInfo *) NULL)
5207 profile=DestroyStringInfo(profile);
5208 MagickResetIterator(&cli_wand->wand);
5209 arg1=DestroyString((char *)arg1);
5210 break;
5211 }
5212 if (LocaleCompare("clone",option+1) == 0) {
5213 Image *new_images;
5214
5215 if (*option == '+') {
5216 /* FIX: avoid leaking previously interpreted arg1 from header */
5217 if (arg1 != arg1n)
5218 arg1 = DestroyString((char *)arg1);
5219 arg1=AcquireString("-1");
5220 }
5221 if (IsSceneGeometry(arg1,MagickFalse) == MagickFalse)
5222 CLIWandExceptionBreak(OptionError,"InvalidArgument",option);
5223 new_images=cli_wand->wand.images;
5224 if (cli_wand->image_list_stack != (CLIStack *) NULL)
5225 new_images=(Image *) cli_wand->image_list_stack->data;
5226 if (new_images == (Image *) NULL)
5227 CLIWandExceptionBreak(OptionError,"UnableToCloneImage",option);
5228 new_images=CloneImages(new_images,arg1,_exception);
5229 if (new_images == (Image *) NULL)
5230 CLIWandExceptionBreak(OptionError,"NoSuchImage",option);
5231 AppendImageToList(&_images,new_images);
5232 break;
5233 }
5234 /*
5235 Informational Operations.
5236
5237 Note that these do not require either a cli-wand or images!
5238 Though currently a cli-wand much be provided regardless.
5239 */
5240 if (LocaleCompare("version",option+1) == 0)
5241 {
5242 ListMagickVersion(stdout);
5243 break;
5244 }
5245 if (LocaleCompare("list",option+1) == 0)
5246 {
5247 ssize_t list;
5248
5249 /*
5250 FUTURE: This 'switch' should really be part of MagickCore
5251 */
5252 list=ParseCommandOption(MagickListOptions,MagickFalse,arg1);
5253 if (list < 0)
5254 {
5255 CLIWandExceptionArg(OptionError,"UnrecognizedListType",option,arg1);
5256 break;
5257 }
5258 switch (list)
5259 {
5260 case MagickCoderOptions:
5261 {
5262 (void) ListCoderInfo((FILE *) NULL,_exception);
5263 break;
5264 }
5265 case MagickColorOptions:
5266 {
5267 (void) ListColorInfo((FILE *) NULL,_exception);
5268 break;
5269 }
5270 case MagickConfigureOptions:
5271 {
5272 (void) ListConfigureInfo((FILE *) NULL,_exception);
5273 break;
5274 }
5275 case MagickDelegateOptions:
5276 {
5277 (void) ListDelegateInfo((FILE *) NULL,_exception);
5278 break;
5279 }
5280 case MagickFontOptions:
5281 {
5282 (void) ListTypeInfo((FILE *) NULL,_exception);
5283 break;
5284 }
5285 case MagickFormatOptions:
5286 (void) ListMagickInfo((FILE *) NULL,_exception);
5287 break;
5288 case MagickLocaleOptions:
5289 (void) ListLocaleInfo((FILE *) NULL,_exception);
5290 break;
5291 case MagickLogOptions:
5292 (void) ListLogInfo((FILE *) NULL,_exception);
5293 break;
5294 case MagickMagicOptions:
5295 (void) ListMagicInfo((FILE *) NULL,_exception);
5296 break;
5297 case MagickMimeOptions:
5298 (void) ListMimeInfo((FILE *) NULL,_exception);
5299 break;
5300 case MagickModuleOptions:
5301 (void) ListModuleInfo((FILE *) NULL,_exception);
5302 break;
5303 case MagickPagesizeOptions:
5304 (void) ListPagesizes((FILE *) NULL,_exception);
5305 break;
5306 case MagickPolicyOptions:
5307 (void) ListPolicyInfo((FILE *) NULL,_exception);
5308 break;
5309 case MagickResourceOptions:
5310 (void) ListMagickResourceInfo((FILE *) NULL,_exception);
5311 break;
5312 case MagickThresholdOptions:
5313 (void) ListThresholdMaps((FILE *) NULL,_exception);
5314 break;
5315 default:
5316 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
5317 _exception);
5318 break;
5319 }
5320 break;
5321 }
5322
5323 CLIWandException(OptionError,"UnrecognizedOption",option);
5324
5325DisableMSCWarning(4127)
5326 } while (0); /* break to exit code. */
5327RestoreMSCWarning
5328
5329 /* clean up percent escape interpreted strings */
5330 if (arg1 != arg1n )
5331 arg1=DestroyString((char *)arg1);
5332 if (arg2 != arg2n )
5333 arg2=DestroyString((char *)arg2);
5334
5335#undef _image_info
5336#undef _images
5337#undef _exception
5338#undef IfNormalOp
5339#undef IfPlusOp
5340}
5341␌
5342/*
5343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5344% %
5345% %
5346% %
5347+ C L I O p t i o n %
5348% %
5349% %
5350% %
5351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5352%
5353% CLIOption() Processes the given option using the given CLI Magick Wand.
5354% The option arguments can be variable in number, though at this time no more
5355% that two is actually used by any option (this may change). Excess options
5356% are simply ignored.
5357%
5358% If the cli_wand->command pointer is non-null, then it is assumed that the
5359% option has already been search for up from the CommandOptions[] table in
5360% "MagickCore/options.c" using GetCommandOptionInfo(). If not set this
5361% routine will do the lookup instead. The pointer is reset afterward.
5362%
5363% This action allows the caller to lookup and pre-handle any 'special'
5364% options, (such as implicit reads) before calling this general option
5365% handler to deal with 'standard' command line options.
5366%
5367% The format of the CLIOption method is:
5368%
5369% void CLIOption(MagickCLI *cli_wand,const char *option, ...)
5370%
5371% A description of each parameter follows:
5372%
5373% o cli_wand: the main CLI Wand to use.
5374%
5375% o option: The special option (with any switch char) to process
5376%
5377% o args: any required arguments for an option (variable number)
5378%
5379% Example Usage...
5380%
5381% CLIoption(cli_wand,"-read","rose:");
5382% CLIoption(cli_wand,"-virtual-pixel","transparent");
5383% CLIoption(cli_wand,"-distort","SRT:","30");
5384% CLIoption(cli_wand,"-write","rotated_rose.png");
5385%
5386*/
5387WandExport void CLIOption(MagickCLI *cli_wand,const char *option,...)
5388{
5389 const char /* extracted option args from args */
5390 *arg1,
5391 *arg2;
5392
5393 CommandOptionFlags
5394 option_type;
5395
5396 assert(cli_wand != (MagickCLI *) NULL);
5397 assert(cli_wand->signature == MagickWandSignature);
5398 assert(cli_wand->wand.signature == MagickWandSignature);
5399
5400 do { /* Break Code Block for error handling */
5401
5402 /* get information about option */
5403 if ( cli_wand->command == (const OptionInfo *) NULL )
5404 cli_wand->command = GetCommandOptionInfo(option);
5405#if 0
5406 (void) FormatLocaleFile(stderr, "CLIOption \"%s\" matched \"%s\"\n",
5407 option, cli_wand->command->mnemonic );
5408#endif
5409 option_type=(CommandOptionFlags) cli_wand->command->flags;
5410
5411 if ( option_type == UndefinedOptionFlag )
5412 CLIWandExceptionReturn(OptionFatalError,"UnrecognizedOption",option);
5413
5414 assert( LocaleCompare(cli_wand->command->mnemonic,option) == 0 );
5415
5416 /* deprecated options */
5417 if ( (option_type & DeprecateOptionFlag) != 0 )
5418 CLIWandExceptionBreak(OptionError,"DeprecatedOptionNoCode",option);
5419
5420 /* options that this module does not handle */
5421 if ((option_type & (SpecialOptionFlag|GenesisOptionFlag)) != 0 )
5422 CLIWandExceptionBreak(OptionFatalError,"InvalidUseOfOption",option);
5423
5424 /* Get argument strings from VarArgs
5425 How can you determine if enough arguments was supplied?
5426 What happens if not enough arguments were supplied?
5427 */
5428 { size_t
5429 count = (size_t) cli_wand->command->type;
5430
5431 va_list
5432 operands;
5433
5434 va_start(operands,option);
5435
5436 arg1=arg2=NULL;
5437 if ( count >= 1 )
5438 arg1=(const char *) va_arg(operands, const char *);
5439 if ( count >= 2 )
5440 arg2=(const char *) va_arg(operands, const char *);
5441
5442 va_end(operands);
5443#if 0
5444 (void) FormatLocaleFile(stderr,
5445 "CLIOption: \"%s\" Count: %ld Flags: %04x Args: \"%s\" \"%s\"\n",
5446 option,(long) count,option_type,arg1,arg2);
5447#endif
5448 }
5449
5450 /*
5451 Call the appropriate option handler
5452 */
5453
5454 /* FUTURE: this is temporary - get 'settings' to handle distribution of
5455 settings to images attributes,proprieties,artifacts */
5456 if ( cli_wand->wand.images != (Image *) NULL )
5457 (void) SyncImagesSettings(cli_wand->wand.image_info,cli_wand->wand.images,
5458 cli_wand->wand.exception);
5459
5460 if ( (option_type & SettingOptionFlags) != 0 ) {
5461 CLISettingOptionInfo(cli_wand, option, arg1, arg2);
5462 /*
5463 FUTURE: Sync Specific Settings into Image Properties (not global)
5464 */
5465 }
5466
5467 /* Operators that do not need images - read, write, stack, clone */
5468 if ((option_type & NoImageOperatorFlag) != 0)
5469 CLINoImageOperator(cli_wand, option, arg1, arg2);
5470
5471 /* FUTURE: The not a setting part below is a temporary hack due to
5472 * some options being both a Setting and a Simple operator.
5473 * Specifically -monitor, -depth, and -colorspace */
5474 if ( cli_wand->wand.images == (Image *) NULL )
5475 if ( ((option_type & (SimpleOperatorFlag|ListOperatorFlag)) != 0 ) &&
5476 ((option_type & SettingOptionFlags) == 0 )) /* temp hack */
5477 CLIWandExceptionBreak(OptionError,"NoImagesFound",option);
5478
5479 /* Operators which loop of individual images, simply */
5480 if ( (option_type & SimpleOperatorFlag) != 0 &&
5481 cli_wand->wand.images != (Image *) NULL) /* temp hack */
5482 {
5483 ExceptionInfo *exception=AcquireExceptionInfo();
5484 (void) CLISimpleOperatorImages(cli_wand, option, arg1, arg2,exception);
5485 exception=DestroyExceptionInfo(exception);
5486 }
5487
5488 /* Operators that work on the image list as a whole */
5489 if ( (option_type & ListOperatorFlag) != 0 )
5490 (void) CLIListOperatorImages(cli_wand, option, arg1, arg2);
5491
5492DisableMSCWarning(4127)
5493 } while (0); /* end Break code block */
5494RestoreMSCWarning
5495
5496 cli_wand->command = (const OptionInfo *) NULL; /* prevent re-use later */
5497}