blob: e29c1b421aa55e31f97cc423cc0e731b40c9771a [file] [log] [blame]
anthony805a2d42011-09-25 08:25:12 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
anthony8b10b462012-02-08 12:32:44 +00006% 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 %
anthony805a2d42011-09-25 08:25:12 +000011% %
12% %
anthony8b10b462012-02-08 12:32:44 +000013% CLI Magick Option Methods %
anthony805a2d42011-09-25 08:25:12 +000014% %
anthony8b10b462012-02-08 12:32:44 +000015% Dragon Computing %
cristy9e58efd2012-01-30 14:27:34 +000016% Anthony Thyssen %
cristy0a0ca4f2011-09-28 01:15:28 +000017% September 2011 %
anthony805a2d42011-09-25 08:25:12 +000018% %
19% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
anthony805a2d42011-09-25 08:25:12 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36% Apply the given options (settings, and simple, or sequence operations) to
anthony8b10b462012-02-08 12:32:44 +000037% the given image(s) according to the current "image_info", "draw_info", and
38% "quantize_info" settings, stored in a special CLI Image Wand.
anthony805a2d42011-09-25 08:25:12 +000039%
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%
anthony8b10b462012-02-08 12:32:44 +000044% Anthony Thyssen, September 2011
anthony805a2d42011-09-25 08:25:12 +000045*/
46
47/*
48 Include declarations.
49*/
50#include "MagickWand/studio.h"
51#include "MagickWand/MagickWand.h"
anthony72feaa62012-01-17 06:46:23 +000052#include "MagickWand/magick-wand-private.h"
anthonyfd706f92012-01-19 04:22:02 +000053#include "MagickWand/operation.h"
anthony2052d272012-02-28 12:48:29 +000054#include "MagickWand/operation-private.h"
anthony43f425d2012-02-26 12:58:58 +000055#include "MagickWand/wand.h"
anthony805a2d42011-09-25 08:25:12 +000056#include "MagickCore/monitor-private.h"
57#include "MagickCore/thread-private.h"
58#include "MagickCore/string-private.h"
59
60/*
61 Define declarations.
62*/
63#define UndefinedCompressionQuality 0UL
64/*
65 Constant declaration. (temporary exports)
66*/
67static const char
68 BackgroundColor[] = "#fff", /* white */
anthony72feaa62012-01-17 06:46:23 +000069 BorderColor[] = "#dfdfdf", /* sRGB gray */
70 MatteColor[] = "#bdbdbd"; /* slightly darker gray */
anthony805a2d42011-09-25 08:25:12 +000071
72/*
73** Function to report on the progress of image operations
74*/
75static MagickBooleanType MonitorProgress(const char *text,
76 const MagickOffsetType offset,const MagickSizeType extent,
anthony43f425d2012-02-26 12:58:58 +000077 void *wand_unused(cli_wandent_data))
anthony805a2d42011-09-25 08:25:12 +000078{
79 char
80 message[MaxTextExtent],
81 tag[MaxTextExtent];
82
83 const char
84 *locale_message;
85
86 register char
87 *p;
88
89 if (extent < 2)
90 return(MagickTrue);
91 (void) CopyMagickMemory(tag,text,MaxTextExtent);
92 p=strrchr(tag,'/');
93 if (p != (char *) NULL)
94 *p='\0';
95 (void) FormatLocaleString(message,MaxTextExtent,"Monitor/%s",tag);
96 locale_message=GetLocaleMessage(message);
97 if (locale_message == message)
98 locale_message=tag;
99 if (p == (char *) NULL)
100 (void) FormatLocaleFile(stderr,"%s: %ld of %lu, %02ld%% complete\r",
101 locale_message,(long) offset,(unsigned long) extent,(long)
102 (100L*offset/(extent-1)));
103 else
104 (void) FormatLocaleFile(stderr,"%s[%s]: %ld of %lu, %02ld%% complete\r",
105 locale_message,p+1,(long) offset,(unsigned long) extent,(long)
106 (100L*offset/(extent-1)));
107 if (offset == (MagickOffsetType) (extent-1))
108 (void) FormatLocaleFile(stderr,"\n");
109 (void) fflush(stderr);
110 return(MagickTrue);
111}
112
113/*
114** GetImageCache() will read an image into a image cache if not already
115** present then return the image that is in the cache under that filename.
116*/
117static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
118 ExceptionInfo *exception)
119{
120 char
121 key[MaxTextExtent];
122
123 ExceptionInfo
124 *sans_exception;
125
126 Image
127 *image;
128
129 ImageInfo
130 *read_info;
131
132 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",path);
133 sans_exception=AcquireExceptionInfo();
134 image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
135 sans_exception=DestroyExceptionInfo(sans_exception);
136 if (image != (Image *) NULL)
137 return(image);
138 read_info=CloneImageInfo(image_info);
139 (void) CopyMagickString(read_info->filename,path,MaxTextExtent);
140 image=ReadImage(read_info,exception);
141 read_info=DestroyImageInfo(read_info);
142 if (image != (Image *) NULL)
143 (void) SetImageRegistry(ImageRegistryType,key,image,exception);
144 return(image);
145}
146
147/*
anthonya89dd172011-10-04 13:29:35 +0000148 SparseColorOption() parse the complex -sparse-color argument into an
149 an array of floating point values than call SparseColorImage().
150 Argument is a complex mix of floating-point pixel coodinates, and color
151 specifications (or direct floating point numbers). The number of floats
152 needed to represent a color varies depending on teh current channel
153 setting.
anthony43f425d2012-02-26 12:58:58 +0000154
155 This really should be in MagickCore, so that other API's can make use of it.
anthony805a2d42011-09-25 08:25:12 +0000156*/
157static Image *SparseColorOption(const Image *image,
158 const SparseColorMethod method,const char *arguments,
anthony31f1bf72012-01-30 12:37:22 +0000159 ExceptionInfo *exception)
anthony805a2d42011-09-25 08:25:12 +0000160{
161 char
162 token[MaxTextExtent];
163
164 const char
165 *p;
166
167 double
168 *sparse_arguments;
169
170 Image
171 *sparse_image;
172
173 PixelInfo
174 color;
175
176 MagickBooleanType
177 error;
178
179 register size_t
180 x;
181
182 size_t
183 number_arguments,
184 number_colors;
185
186 assert(image != (Image *) NULL);
187 assert(image->signature == MagickSignature);
188 if (image->debug != MagickFalse)
189 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
190 assert(exception != (ExceptionInfo *) NULL);
191 assert(exception->signature == MagickSignature);
192 /*
193 Limit channels according to image - and add up number of color channel.
194 */
195 number_colors=0;
196 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
197 number_colors++;
198 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
199 number_colors++;
200 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
201 number_colors++;
202 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
203 (image->colorspace == CMYKColorspace))
204 number_colors++;
205 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
206 (image->matte != MagickFalse))
207 number_colors++;
208
209 /*
210 Read string, to determine number of arguments needed,
211 */
212 p=arguments;
213 x=0;
214 while( *p != '\0' )
215 {
216 GetMagickToken(p,&p,token);
217 if ( token[0] == ',' ) continue;
anthony31f1bf72012-01-30 12:37:22 +0000218 if ( isalpha((int) token[0]) || token[0] == '#' )
219 x += number_colors; /* color argument found */
anthony805a2d42011-09-25 08:25:12 +0000220 else {
221 x++; /* floating point argument */
222 }
223 }
224 error=MagickTrue;
anthony31f1bf72012-01-30 12:37:22 +0000225 /* control points and color values */
226 error = ( x % (2+number_colors) != 0 ) ? MagickTrue : MagickFalse;
227 number_arguments=x;
anthony805a2d42011-09-25 08:25:12 +0000228 if ( error ) {
229 (void) ThrowMagickException(exception,GetMagickModule(),
anthony43f425d2012-02-26 12:58:58 +0000230 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
anthony805a2d42011-09-25 08:25:12 +0000231 "Invalid number of Arguments");
232 return( (Image *)NULL);
233 }
234
235 /* Allocate and fill in the floating point arguments */
236 sparse_arguments=(double *) AcquireQuantumMemory(number_arguments,
237 sizeof(*sparse_arguments));
238 if (sparse_arguments == (double *) NULL) {
239 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
240 "MemoryAllocationFailed","%s","SparseColorOption");
241 return( (Image *)NULL);
242 }
243 (void) ResetMagickMemory(sparse_arguments,0,number_arguments*
244 sizeof(*sparse_arguments));
245 p=arguments;
246 x=0;
247 while( *p != '\0' && x < number_arguments ) {
248 /* X coordinate */
249 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
250 if ( token[0] == '\0' ) break;
251 if ( isalpha((int) token[0]) || token[0] == '#' ) {
252 (void) ThrowMagickException(exception,GetMagickModule(),
anthony43f425d2012-02-26 12:58:58 +0000253 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
anthony805a2d42011-09-25 08:25:12 +0000254 "Color found, instead of X-coord");
255 error = MagickTrue;
256 break;
257 }
cristydbdd0e32011-11-04 23:29:40 +0000258 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +0000259 /* Y coordinate */
260 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
261 if ( token[0] == '\0' ) break;
262 if ( isalpha((int) token[0]) || token[0] == '#' ) {
263 (void) ThrowMagickException(exception,GetMagickModule(),
anthony43f425d2012-02-26 12:58:58 +0000264 OptionError, "InvalidArgument", "'%s': %s", "sparse-color",
anthony805a2d42011-09-25 08:25:12 +0000265 "Color found, instead of Y-coord");
266 error = MagickTrue;
267 break;
268 }
cristydbdd0e32011-11-04 23:29:40 +0000269 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
anthony31f1bf72012-01-30 12:37:22 +0000270 /* color name or function given in string argument */
271 token[0]=','; while ( token[0] == ',' ) GetMagickToken(p,&p,token);
272 if ( token[0] == '\0' ) break;
273 if ( isalpha((int) token[0]) || token[0] == '#' ) {
274 /* Color string given */
275 (void) QueryColorCompliance(token,AllCompliance,&color,
276 exception);
277 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
278 sparse_arguments[x++] = QuantumScale*color.red;
279 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
280 sparse_arguments[x++] = QuantumScale*color.green;
281 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
282 sparse_arguments[x++] = QuantumScale*color.blue;
283 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
284 (image->colorspace == CMYKColorspace))
285 sparse_arguments[x++] = QuantumScale*color.black;
286 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
287 (image->matte != MagickFalse))
288 sparse_arguments[x++] = QuantumScale*color.alpha;
anthony805a2d42011-09-25 08:25:12 +0000289 }
anthony31f1bf72012-01-30 12:37:22 +0000290 else {
291 /* Colors given as a set of floating point values - experimental */
292 /* NB: token contains the first floating point value to use! */
293 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
294 {
295 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
296 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
297 break;
298 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
299 token[0] = ','; /* used this token - get another */
anthony805a2d42011-09-25 08:25:12 +0000300 }
anthony31f1bf72012-01-30 12:37:22 +0000301 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
302 {
303 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
304 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
305 break;
306 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
307 token[0] = ','; /* used this token - get another */
308 }
309 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
310 {
311 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
312 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
313 break;
314 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
315 token[0] = ','; /* used this token - get another */
316 }
317 if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
318 (image->colorspace == CMYKColorspace))
319 {
320 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
321 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
322 break;
323 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
324 token[0] = ','; /* used this token - get another */
325 }
326 if (((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0) &&
327 (image->matte != MagickFalse))
328 {
329 while ( token[0] == ',' ) GetMagickToken(p,&p,token);
330 if ( token[0] == '\0' || isalpha((int)token[0]) || token[0] == '#' )
331 break;
332 sparse_arguments[x++]=StringToDouble(token,(char **) NULL);
333 token[0] = ','; /* used this token - get another */
anthony805a2d42011-09-25 08:25:12 +0000334 }
335 }
336 }
337 if ( number_arguments != x && !error ) {
338 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
anthony43f425d2012-02-26 12:58:58 +0000339 "InvalidArgument","'%s': %s","sparse-color","Argument Parsing Error");
anthony805a2d42011-09-25 08:25:12 +0000340 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
341 return( (Image *)NULL);
342 }
343 if ( error )
344 return( (Image *)NULL);
345
anthony31f1bf72012-01-30 12:37:22 +0000346 /* Call the Sparse Color Interpolation function with the parsed arguments */
anthony805a2d42011-09-25 08:25:12 +0000347 sparse_image=SparseColorImage(image,method,number_arguments,sparse_arguments,
348 exception);
349 sparse_arguments=(double *) RelinquishMagickMemory(sparse_arguments);
350 return( sparse_image );
351}
352
353/*
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355% %
356% %
357% %
anthony43f425d2012-02-26 12:58:58 +0000358+ A c q u i r e W a n d C L I %
anthony805a2d42011-09-25 08:25:12 +0000359% %
360% %
361% %
362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363%
anthony43f425d2012-02-26 12:58:58 +0000364% AcquireMagickCLI() creates a new CLI wand (an expanded form of Magick
365% Wand). The given image_info and exception is included as is if provided.
anthony805a2d42011-09-25 08:25:12 +0000366%
anthony43f425d2012-02-26 12:58:58 +0000367% Use DestroyMagickCLI() to dispose of the CLI wand when it is no longer
368% needed.
369%
370% The format of the NewMagickWand method is:
371%
372% MagickCLI *AcquireMagickCLI(ImageInfo *image_info,
373% ExceptionInfo *exception)
374%
375*/
376WandExport MagickCLI *AcquireMagickCLI(ImageInfo *image_info,
377 ExceptionInfo *exception)
378{
379 MagickCLI
380 *cli_wand;
381
382 /* precaution - as per NewMagickWand() */
383 {
384 size_t depth = MAGICKCORE_QUANTUM_DEPTH;
385 const char *quantum = GetMagickQuantumDepth(&depth);
386 if (depth != MAGICKCORE_QUANTUM_DEPTH)
387 ThrowWandFatalException(WandError,"QuantumDepthMismatch",quantum);
388 }
389
390 /* allocate memory for MgaickCLI */
391 cli_wand=(MagickCLI *) AcquireMagickMemory(sizeof(*cli_wand));
392 if (cli_wand == (MagickCLI *) NULL)
393 {
394 ThrowWandFatalException(ResourceLimitFatalError,"MemoryAllocationFailed",
395 GetExceptionMessage(errno));
396 return((MagickCLI *)NULL);
397 }
398
399 /* Initialize Wand Part of MagickCLI
400 FUTURE: this is a repeat of code from NewMagickWand()
401 However some parts may be given fro man external source!
402 */
403 cli_wand->wand.id=AcquireWandId();
404 (void) FormatLocaleString(cli_wand->wand.name,MaxTextExtent,
405 "%s-%.20g","MagickWandCLI", (double) cli_wand->wand.id);
406 cli_wand->wand.images=NewImageList();
407 if ( image_info == (ImageInfo *)NULL)
408 cli_wand->wand.image_info=AcquireImageInfo();
409 else
410 cli_wand->wand.image_info=image_info;
411 if ( exception == (ExceptionInfo *)NULL)
412 cli_wand->wand.exception=AcquireExceptionInfo();
413 else
414 cli_wand->wand.exception=exception;
415 cli_wand->wand.debug=IsEventLogging();
416 cli_wand->wand.signature=WandSignature;
417
418 /* Initialize CLI Part of MagickCLI */
419 cli_wand->draw_info=CloneDrawInfo(cli_wand->wand.image_info,(DrawInfo *) NULL);
420 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
421 cli_wand->image_list_stack=(Stack *)NULL;
422 cli_wand->image_info_stack=(Stack *)NULL;
423 cli_wand->signature=WandSignature;
424
425 if (cli_wand->wand.debug != MagickFalse)
426 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
427 return(cli_wand);
428}
429
430/*
431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432% %
433% %
434% %
435+ D e s t r o y W a n d C L I %
436% %
437% %
438% %
439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440%
441% DestroyMagickCLI() destorys everything in a CLI wand, including image_info
442% and any exceptions, if still present in the wand.
443%
444% The format of the NewMagickWand method is:
445%
446% MagickWand *DestroyMagickCLI()
447% Exception *exception)
448%
449*/
450WandExport MagickCLI *DestroyMagickCLI(MagickCLI *cli_wand)
451{
452 Stack
453 *node;
454
455 assert(cli_wand != (MagickCLI *) NULL);
456 assert(cli_wand->signature == WandSignature);
457 assert(cli_wand->wand.signature == WandSignature);
458 if (cli_wand->wand.debug != MagickFalse)
459 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
460
461 /* Destroy CLI part of MagickCLI */
462 if (cli_wand->draw_info != (DrawInfo *) NULL )
463 cli_wand->draw_info=DestroyDrawInfo(cli_wand->draw_info);
464 if (cli_wand->quantize_info != (QuantizeInfo *) NULL )
465 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
466 while(cli_wand->image_list_stack != (Stack *)NULL)
467 {
468 node=cli_wand->image_list_stack;
469 cli_wand->image_list_stack=node->next;
470 (void) DestroyImageList((Image *)node->data);
471 (void) RelinquishMagickMemory(node);
472 }
473 while(cli_wand->image_info_stack != (Stack *)NULL)
474 {
475 node=cli_wand->image_info_stack;
476 cli_wand->image_info_stack=node->next;
477 (void) DestroyImageInfo((ImageInfo *)node->data);
478 (void) RelinquishMagickMemory(node);
479 }
480 cli_wand->signature=(~WandSignature);
481
482 /* Destroy Wand part MagickCLI */
483 cli_wand->wand.images=DestroyImageList(cli_wand->wand.images);
484 if (cli_wand->wand.image_info != (ImageInfo *) NULL )
485 cli_wand->wand.image_info=DestroyImageInfo(cli_wand->wand.image_info);
486 if (cli_wand->wand.exception != (ExceptionInfo *) NULL )
487 cli_wand->wand.exception=DestroyExceptionInfo(cli_wand->wand.exception);
488 RelinquishWandId(cli_wand->wand.id);
489 cli_wand->wand.signature=(~WandSignature);
490
491 return((MagickCLI *)NULL);
492}
493
494/*
495%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496% %
497% %
498% %
anthony2052d272012-02-28 12:48:29 +0000499+ C L I C a t c h E x c e p t i o n %
500% %
501% %
502% %
503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504%
505% CLICatchException() will report exceptions, either just non-fatal warnings
506% only, or all errors, according to 'all_execeptions' boolean argument.
507%
508% The function returns true is errors are fatal, in which case the caller
509% should abort and re-call with an 'all_exceptions' argument of true before
510% quitting.
511%
512% The cut-off level between fatal and non-fatal may be controlled by options
513% (FUTURE), but defaults to 'Error' exceptions.
514%
515% The format of the CLICatchException method is:
516%
517% MagickBooleanType CLICatchException(MagickCLI *cli_wand,
518% const MagickBooleanType all_exceptions );
519%
520*/
521WandExport MagickBooleanType CLICatchException(MagickCLI *cli_wand,
522 const MagickBooleanType all_exceptions )
523{
524 MagickBooleanType
525 status;
526 assert(cli_wand != (MagickCLI *) NULL);
527 assert(cli_wand->signature == WandSignature);
528 assert(cli_wand->wand.signature == WandSignature);
529 if (cli_wand->wand.debug != MagickFalse)
530 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
531
532 // FUTURE: '-regard_warning' should make this more sensitive.
533 // Note pipelined options may like more control over this level
534
535 status = MagickFalse;
536 if (cli_wand->wand.exception->severity > ErrorException)
537 status = MagickTrue;
538
539 if ( status == MagickFalse || all_exceptions != MagickFalse )
540 CatchException(cli_wand->wand.exception); /* output and clear exceptions */
541
542 return(status);
543}
544
545/*
546%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547% %
548% %
549% %
anthony43f425d2012-02-26 12:58:58 +0000550+ C L I S e t t i n g O p t i o n I n f o %
551% %
552% %
553% %
554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555%
556% CLISettingOptionInfo() applies a single settings option into a CLI wand
557% holding the image_info, draw_info, quantize_info structures that will be
558% used when processing the images.
559%
560% These options do no require images to be present in the CLI wand for them
561% to be able to be set, in which case they will generally be applied to image
562% that are read in later
anthony80c37752012-01-16 01:03:11 +0000563%
564% Options handled by this function are listed in CommandOptions[] of
anthonyfd706f92012-01-19 04:22:02 +0000565% "option.c" that is one of "SettingOptionFlags" option flags.
anthony805a2d42011-09-25 08:25:12 +0000566%
anthony2052d272012-02-28 12:48:29 +0000567% The format of the CLISettingOptionInfo method is:
anthony1afdc7a2011-10-05 11:54:28 +0000568%
anthony43f425d2012-02-26 12:58:58 +0000569% void CLISettingOptionInfo(MagickCLI *cli_wand,const char *option,
anthony31f1bf72012-01-30 12:37:22 +0000570% const char *arg)
anthony805a2d42011-09-25 08:25:12 +0000571%
572% A description of each parameter follows:
573%
anthony43f425d2012-02-26 12:58:58 +0000574% o cli_wand: structure holding settings to be applied
anthony805a2d42011-09-25 08:25:12 +0000575%
anthonydcf510d2011-10-30 13:51:40 +0000576% o option: The option string to be set
anthony805a2d42011-09-25 08:25:12 +0000577%
anthony72feaa62012-01-17 06:46:23 +0000578% o arg: The single argument used to set this option.
579% If NULL the setting is reset to its default value.
anthony31f1bf72012-01-30 12:37:22 +0000580% For boolean (no argument) settings false=NULL, true=any_string
anthonydcf510d2011-10-30 13:51:40 +0000581%
anthony72feaa62012-01-17 06:46:23 +0000582% Example usage...
583%
anthony2052d272012-02-28 12:48:29 +0000584% CLISettingOptionInfo(cli_wand, "background", "Red");
anthony43f425d2012-02-26 12:58:58 +0000585% CLISettingOptionInfo(cli_wand, "adjoin", "true");
586% CLISettingOptionInfo(cli_wand, "adjoin", NULL);
anthony72feaa62012-01-17 06:46:23 +0000587%
588% Or for handling command line arguments EG: +/-option ["arg"]
anthonydcf510d2011-10-30 13:51:40 +0000589%
590% argc,argv
591% i=index in argv
592%
anthony2052d272012-02-28 12:48:29 +0000593% option_info = GetCommandOptionInfo(argv[i]);
594% count=option_info->type;
595% option_type=option_info->flags;
596%
597% if ( (option_type & SettingOperatorOptionFlags) != 0 )
anthony43f425d2012-02-26 12:58:58 +0000598% CLISettingOptionInfo(cli_wand, argv[i]+1,
anthonyfd706f92012-01-19 04:22:02 +0000599% (((*argv[i])!='-') ? (char *)NULL
600% : (count>0) ? argv[i+1] : "true") );
anthonydcf510d2011-10-30 13:51:40 +0000601% i += count+1;
602%
anthony805a2d42011-09-25 08:25:12 +0000603*/
anthony43f425d2012-02-26 12:58:58 +0000604WandExport void CLISettingOptionInfo(MagickCLI *cli_wand,const char *option,
anthony31f1bf72012-01-30 12:37:22 +0000605 const char *arg)
anthony805a2d42011-09-25 08:25:12 +0000606{
anthony43f425d2012-02-26 12:58:58 +0000607 assert(cli_wand != (MagickCLI *) NULL);
608 assert(cli_wand->signature == WandSignature);
609 assert(cli_wand->wand.signature == WandSignature);
610 if (cli_wand->wand.debug != MagickFalse)
611 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthony1afdc7a2011-10-05 11:54:28 +0000612
anthony43f425d2012-02-26 12:58:58 +0000613#define image_info (cli_wand->wand.image_info)
614#define exception (cli_wand->wand.exception)
615#define draw_info (cli_wand->draw_info)
616#define quantize_info (cli_wand->quantize_info)
anthony72feaa62012-01-17 06:46:23 +0000617#define IfSetOption (arg!=(char *)NULL)
618#define ArgOption(def) (IfSetOption?arg:(const char *)(def))
619#define ArgBoolean (IfSetOption?MagickTrue:MagickFalse)
anthony74b1cfc2011-10-06 12:44:16 +0000620
621 switch (*option)
anthony805a2d42011-09-25 08:25:12 +0000622 {
623 case 'a':
624 {
anthony74b1cfc2011-10-06 12:44:16 +0000625 if (LocaleCompare("adjoin",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000626 {
anthony72feaa62012-01-17 06:46:23 +0000627 image_info->adjoin = ArgBoolean;
anthony805a2d42011-09-25 08:25:12 +0000628 break;
629 }
anthony74b1cfc2011-10-06 12:44:16 +0000630 if (LocaleCompare("affine",option) == 0)
anthony1afdc7a2011-10-05 11:54:28 +0000631 {
anthony31f1bf72012-01-30 12:37:22 +0000632 /* DEPRECIATED: draw_info setting only: for -draw and -transform */
anthony74b1cfc2011-10-06 12:44:16 +0000633 if (IfSetOption)
anthony72feaa62012-01-17 06:46:23 +0000634 (void) ParseAffineGeometry(arg,&draw_info->affine,exception);
anthony74b1cfc2011-10-06 12:44:16 +0000635 else
anthony72feaa62012-01-17 06:46:23 +0000636 GetAffineMatrix(&draw_info->affine);
anthony1afdc7a2011-10-05 11:54:28 +0000637 break;
638 }
anthony74b1cfc2011-10-06 12:44:16 +0000639 if (LocaleCompare("antialias",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000640 {
anthony1afdc7a2011-10-05 11:54:28 +0000641 image_info->antialias =
anthony72feaa62012-01-17 06:46:23 +0000642 draw_info->stroke_antialias =
643 draw_info->text_antialias = ArgBoolean;
anthony805a2d42011-09-25 08:25:12 +0000644 break;
645 }
anthony31f1bf72012-01-30 12:37:22 +0000646 if (LocaleCompare("attenuate",option+1) == 0)
647 {
648 (void) SetImageOption(image_info,option,ArgOption(NULL));
649 break;
650 }
anthony74b1cfc2011-10-06 12:44:16 +0000651 if (LocaleCompare("authenticate",option) == 0)
anthonydcf510d2011-10-30 13:51:40 +0000652 {
anthony72feaa62012-01-17 06:46:23 +0000653 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +0000654 break;
655 }
656 break;
657 }
658 case 'b':
659 {
anthony74b1cfc2011-10-06 12:44:16 +0000660 if (LocaleCompare("background",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000661 {
anthony74b1cfc2011-10-06 12:44:16 +0000662 /* FUTURE: both image_info attribute & ImageOption in use!
anthony72feaa62012-01-17 06:46:23 +0000663 image_info only used directly for generating new images.
664 SyncImageSettings() used to set per-image attribute.
665
666 FUTURE: if image_info->background_color is not set then
667 we should fall back to image
668 Note that +background, means fall-back to image background
669 and only if not set fall back to BackgroundColor const.
anthony74b1cfc2011-10-06 12:44:16 +0000670 */
anthony72feaa62012-01-17 06:46:23 +0000671 (void) SetImageOption(image_info,option,ArgOption(NULL));
672 (void) QueryColorCompliance(ArgOption(BackgroundColor),AllCompliance,
673 &image_info->background_color,exception);
anthony805a2d42011-09-25 08:25:12 +0000674 break;
675 }
anthony74b1cfc2011-10-06 12:44:16 +0000676 if (LocaleCompare("bias",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000677 {
anthony74b1cfc2011-10-06 12:44:16 +0000678 /* FUTURE: bias OBSOLETED, replaced by "convolve:bias"
anthony31f1bf72012-01-30 12:37:22 +0000679 as it is actually rarely used except in direct convolve operations
680 Usage outside a direct convolve operation is actally non-sensible!
anthony72feaa62012-01-17 06:46:23 +0000681
682 SyncImageSettings() used to set per-image attribute.
anthony74b1cfc2011-10-06 12:44:16 +0000683 */
anthony72feaa62012-01-17 06:46:23 +0000684 (void) SetImageOption(image_info,option,ArgOption("0"));
anthony805a2d42011-09-25 08:25:12 +0000685 break;
686 }
anthony74b1cfc2011-10-06 12:44:16 +0000687 if (LocaleCompare("black-point-compensation",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000688 {
anthony72feaa62012-01-17 06:46:23 +0000689 /* Used as a image chromaticity setting
690 SyncImageSettings() used to set per-image attribute.
691 */
anthony74b1cfc2011-10-06 12:44:16 +0000692 (void) SetImageOption(image_info,option,
693 IfSetOption ? "true" : "false" );
anthony805a2d42011-09-25 08:25:12 +0000694 break;
695 }
anthony74b1cfc2011-10-06 12:44:16 +0000696 if (LocaleCompare("blue-primary",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000697 {
anthonyafbaed72011-10-26 12:05:04 +0000698 /* Image chromaticity X,Y NB: Y=X if Y not defined
699 Used by many coders including PNG
anthony72feaa62012-01-17 06:46:23 +0000700 SyncImageSettings() used to set per-image attribute.
anthonyafbaed72011-10-26 12:05:04 +0000701 */
anthony72feaa62012-01-17 06:46:23 +0000702 (void) SetImageOption(image_info,option,ArgOption("0.0"));
anthony805a2d42011-09-25 08:25:12 +0000703 break;
704 }
anthony74b1cfc2011-10-06 12:44:16 +0000705 if (LocaleCompare("bordercolor",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000706 {
anthony72feaa62012-01-17 06:46:23 +0000707 /* FUTURE: both image_info attribute & ImageOption in use!
708 SyncImageSettings() used to set per-image attribute.
709 */
anthony74b1cfc2011-10-06 12:44:16 +0000710 if (IfSetOption)
anthony805a2d42011-09-25 08:25:12 +0000711 {
anthonydcf510d2011-10-30 13:51:40 +0000712 (void) SetImageOption(image_info,option,arg);
anthony72feaa62012-01-17 06:46:23 +0000713 (void) QueryColorCompliance(arg,AllCompliance,
anthony74b1cfc2011-10-06 12:44:16 +0000714 &image_info->border_color,exception);
anthonydcf510d2011-10-30 13:51:40 +0000715 (void) QueryColorCompliance(arg,AllCompliance,
anthony74b1cfc2011-10-06 12:44:16 +0000716 &draw_info->border_color,exception);
anthony805a2d42011-09-25 08:25:12 +0000717 break;
718 }
anthony74b1cfc2011-10-06 12:44:16 +0000719 (void) DeleteImageOption(image_info,option);
720 (void) QueryColorCompliance(BorderColor,AllCompliance,
721 &image_info->border_color,exception);
722 (void) QueryColorCompliance(BorderColor,AllCompliance,
723 &draw_info->border_color,exception);
anthony805a2d42011-09-25 08:25:12 +0000724 break;
725 }
anthony74b1cfc2011-10-06 12:44:16 +0000726 if (LocaleCompare("box",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000727 {
anthonyfd706f92012-01-19 04:22:02 +0000728 /* DEPRECIATED - now "undercolor" */
anthony43f425d2012-02-26 12:58:58 +0000729 CLISettingOptionInfo(cli_wand,"undercolor",arg);
anthonyfd706f92012-01-19 04:22:02 +0000730 break;
anthony805a2d42011-09-25 08:25:12 +0000731 }
732 break;
733 }
734 case 'c':
735 {
anthony74b1cfc2011-10-06 12:44:16 +0000736 if (LocaleCompare("cache",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000737 {
738 MagickSizeType
739 limit;
740
741 limit=MagickResourceInfinity;
anthonydcf510d2011-10-30 13:51:40 +0000742 if (LocaleCompare("unlimited",arg) != 0)
cristy9b34e302011-11-05 02:15:45 +0000743 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg,100.0);
anthony805a2d42011-09-25 08:25:12 +0000744 (void) SetMagickResourceLimit(MemoryResource,limit);
745 (void) SetMagickResourceLimit(MapResource,2*limit);
746 break;
747 }
anthony74b1cfc2011-10-06 12:44:16 +0000748 if (LocaleCompare("caption",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000749 {
anthony72feaa62012-01-17 06:46:23 +0000750 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +0000751 break;
752 }
anthony74b1cfc2011-10-06 12:44:16 +0000753 if (LocaleCompare("channel",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000754 {
anthony43f425d2012-02-26 12:58:58 +0000755 /* FUTURE: -channel mask {vaules}
756 This is applied to images in SimpleImageOperator!!!
757 Move it to SyncImageSettings() - or alternative
anthony31f1bf72012-01-30 12:37:22 +0000758 */
anthony74b1cfc2011-10-06 12:44:16 +0000759 image_info->channel=(ChannelType) (
anthonydcf510d2011-10-30 13:51:40 +0000760 IfSetOption ? ParseChannelOption(arg) : DefaultChannels );
anthony805a2d42011-09-25 08:25:12 +0000761 break;
762 }
anthony74b1cfc2011-10-06 12:44:16 +0000763 if (LocaleCompare("colorspace",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000764 {
anthonyafbaed72011-10-26 12:05:04 +0000765 /* Setting used for new images via AquireImage()
766 But also used as a SimpleImageOperator
767 Undefined colorspace means don't modify images on
768 read or as a operation */
anthony72feaa62012-01-17 06:46:23 +0000769 image_info->colorspace=(ColorspaceType) ParseCommandOption(
770 MagickColorspaceOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000771 break;
772 }
anthony74b1cfc2011-10-06 12:44:16 +0000773 if (LocaleCompare("comment",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000774 {
anthony72feaa62012-01-17 06:46:23 +0000775 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +0000776 break;
777 }
anthony74b1cfc2011-10-06 12:44:16 +0000778 if (LocaleCompare("compose",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000779 {
anthony72feaa62012-01-17 06:46:23 +0000780 /* FUTURE: image_info should be used,
781 SyncImageSettings() used to set per-image attribute. - REMOVE
782
anthonyafbaed72011-10-26 12:05:04 +0000783 This setting should NOT be used to set image 'compose'
anthony72feaa62012-01-17 06:46:23 +0000784 "-layer" operators shoud use image_info if defined otherwise
785 they should use a per-image compose setting.
anthony965524b2011-10-07 12:34:14 +0000786 */
anthony72feaa62012-01-17 06:46:23 +0000787 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony965524b2011-10-07 12:34:14 +0000788 image_info->compose=(CompositeOperator) ParseCommandOption(
anthony72feaa62012-01-17 06:46:23 +0000789 MagickComposeOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000790 break;
791 }
anthony74b1cfc2011-10-06 12:44:16 +0000792 if (LocaleCompare("compress",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000793 {
anthony5f867ae2011-10-09 10:28:34 +0000794 /* FUTURE: What should be used? image_info or ImageOption ???
795 The former is more efficent, but Crisy prefers the latter!
anthony72feaa62012-01-17 06:46:23 +0000796 SyncImageSettings() used to set per-image attribute.
anthony5f867ae2011-10-09 10:28:34 +0000797
798 The coders appears to use image_info, not Image_Option
799 however the image attribute (for save) is set from the
800 ImageOption!
anthony72feaa62012-01-17 06:46:23 +0000801
802 Note that "undefined" is a different setting to "none".
anthony5f867ae2011-10-09 10:28:34 +0000803 */
anthony72feaa62012-01-17 06:46:23 +0000804 (void) SetImageOption(image_info,option,ArgOption(NULL));
805 image_info->compression=(CompressionType) ParseCommandOption(
806 MagickCompressOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000807 break;
808 }
809 break;
810 }
811 case 'd':
812 {
anthony74b1cfc2011-10-06 12:44:16 +0000813 if (LocaleCompare("debug",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000814 {
anthony72feaa62012-01-17 06:46:23 +0000815 /* SyncImageSettings() used to set per-image attribute. */
816 (void) SetLogEventMask(ArgOption("none"));
anthony5f867ae2011-10-09 10:28:34 +0000817 image_info->debug=IsEventLogging(); /* extract logging*/
anthony43f425d2012-02-26 12:58:58 +0000818 cli_wand->wand.debug=IsEventLogging();
anthony805a2d42011-09-25 08:25:12 +0000819 break;
820 }
anthony74b1cfc2011-10-06 12:44:16 +0000821 if (LocaleCompare("define",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000822 {
anthony72feaa62012-01-17 06:46:23 +0000823 /* DefineImageOption() equals SetImageOption() but with '='
824 It does not however set individual image options.
825 -set will set individual image options as well!
anthony5f867ae2011-10-09 10:28:34 +0000826 */
anthonydcf510d2011-10-30 13:51:40 +0000827 if (LocaleNCompare(arg,"registry:",9) == 0)
anthony805a2d42011-09-25 08:25:12 +0000828 {
anthony5f867ae2011-10-09 10:28:34 +0000829 if (IfSetOption)
anthonydcf510d2011-10-30 13:51:40 +0000830 (void) DefineImageRegistry(StringRegistryType,arg+9,
anthony5f867ae2011-10-09 10:28:34 +0000831 exception);
832 else
anthony72feaa62012-01-17 06:46:23 +0000833 (void) DeleteImageRegistry(arg+9);
anthony805a2d42011-09-25 08:25:12 +0000834 break;
835 }
anthony5f867ae2011-10-09 10:28:34 +0000836 if (IfSetOption)
anthony72feaa62012-01-17 06:46:23 +0000837 (void) DefineImageOption(image_info,arg);
anthony5f867ae2011-10-09 10:28:34 +0000838 else
anthony72feaa62012-01-17 06:46:23 +0000839 (void) DeleteImageOption(image_info,arg);
anthony805a2d42011-09-25 08:25:12 +0000840 break;
841 }
anthony74b1cfc2011-10-06 12:44:16 +0000842 if (LocaleCompare("delay",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000843 {
anthonyafbaed72011-10-26 12:05:04 +0000844 /* Only used for new images via AcquireImage()
845 FUTURE: Option should also be used for "-morph" (color morphing)
anthony5f867ae2011-10-09 10:28:34 +0000846 */
anthony72feaa62012-01-17 06:46:23 +0000847 (void) SetImageOption(image_info,option,ArgOption("0"));
anthony805a2d42011-09-25 08:25:12 +0000848 break;
849 }
anthony74b1cfc2011-10-06 12:44:16 +0000850 if (LocaleCompare("density",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000851 {
anthony72feaa62012-01-17 06:46:23 +0000852 /* FUTURE: strings used in image_info attr and draw_info!
853 Basically as density can be in a XxY form!
854
855 SyncImageSettings() used to set per-image attribute.
856 */
857 (void) SetImageOption(image_info,option,ArgOption(NULL));
858 (void) CloneString(&image_info->density,ArgOption(NULL));
859 (void) CloneString(&draw_info->density,image_info->density);
anthony805a2d42011-09-25 08:25:12 +0000860 break;
861 }
anthony74b1cfc2011-10-06 12:44:16 +0000862 if (LocaleCompare("depth",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000863 {
anthony72feaa62012-01-17 06:46:23 +0000864 /* This is also a SimpleImageOperator! for 8->16 vaule trunc !!!!
865 SyncImageSettings() used to set per-image attribute.
866 */
anthonydcf510d2011-10-30 13:51:40 +0000867 image_info->depth=IfSetOption?StringToUnsignedLong(arg)
anthony5f867ae2011-10-09 10:28:34 +0000868 :MAGICKCORE_QUANTUM_DEPTH;
anthony805a2d42011-09-25 08:25:12 +0000869 break;
870 }
anthony74b1cfc2011-10-06 12:44:16 +0000871 if (LocaleCompare("direction",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000872 {
anthony6dc09cd2011-10-12 08:56:49 +0000873 /* Image Option is only used to set draw_info */
anthony72feaa62012-01-17 06:46:23 +0000874 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony5f867ae2011-10-09 10:28:34 +0000875 draw_info->direction=(DirectionType) ParseCommandOption(
876 MagickDirectionOptions,MagickFalse,
anthony72feaa62012-01-17 06:46:23 +0000877 ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000878 break;
879 }
anthony74b1cfc2011-10-06 12:44:16 +0000880 if (LocaleCompare("display",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000881 {
anthony72feaa62012-01-17 06:46:23 +0000882 (void) CloneString(&image_info->server_name,ArgOption(NULL));
883 (void) CloneString(&draw_info->server_name,image_info->server_name);
anthony805a2d42011-09-25 08:25:12 +0000884 break;
885 }
anthony74b1cfc2011-10-06 12:44:16 +0000886 if (LocaleCompare("dispose",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000887 {
anthony72feaa62012-01-17 06:46:23 +0000888 /* only used in setting new images */
889 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000890 break;
891 }
anthony74b1cfc2011-10-06 12:44:16 +0000892 if (LocaleCompare("dither",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000893 {
anthony72feaa62012-01-17 06:46:23 +0000894 /* image_info attr (on/off), quantize_info attr (on/off)
895 but also ImageInfo and quantize_info method!
896 FUTURE: merge the duality of the dithering options
897 */
898 image_info->dither = quantize_info->dither = ArgBoolean;
899 (void) SetImageOption(image_info,option,ArgOption("none"));
anthony5f867ae2011-10-09 10:28:34 +0000900 quantize_info->dither_method=(DitherMethod) ParseCommandOption(
anthony72feaa62012-01-17 06:46:23 +0000901 MagickDitherOptions,MagickFalse,ArgOption("none"));
anthony5f867ae2011-10-09 10:28:34 +0000902 if (quantize_info->dither_method == NoDitherMethod)
anthony72feaa62012-01-17 06:46:23 +0000903 image_info->dither = quantize_info->dither = MagickFalse;
anthony805a2d42011-09-25 08:25:12 +0000904 break;
905 }
906 break;
907 }
908 case 'e':
909 {
anthony74b1cfc2011-10-06 12:44:16 +0000910 if (LocaleCompare("encoding",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000911 {
anthony72feaa62012-01-17 06:46:23 +0000912 (void) CloneString(&draw_info->encoding,ArgOption("undefined"));
913 (void) SetImageOption(image_info,option,draw_info->encoding);
anthony805a2d42011-09-25 08:25:12 +0000914 break;
915 }
anthony74b1cfc2011-10-06 12:44:16 +0000916 if (LocaleCompare("endian",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000917 {
anthony72feaa62012-01-17 06:46:23 +0000918 /* Both image_info attr and ImageInfo */
919 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000920 image_info->endian=(EndianType) ParseCommandOption(
anthony72feaa62012-01-17 06:46:23 +0000921 MagickEndianOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000922 break;
923 }
anthony74b1cfc2011-10-06 12:44:16 +0000924 if (LocaleCompare("extract",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000925 {
anthony72feaa62012-01-17 06:46:23 +0000926 (void) CloneString(&image_info->extract,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +0000927 break;
928 }
929 break;
930 }
931 case 'f':
932 {
anthony72feaa62012-01-17 06:46:23 +0000933 if (LocaleCompare("family",option) == 0)
anthony6dc09cd2011-10-12 08:56:49 +0000934 {
anthony72feaa62012-01-17 06:46:23 +0000935 (void) CloneString(&draw_info->family,ArgOption(NULL));
anthony6dc09cd2011-10-12 08:56:49 +0000936 break;
937 }
anthony74b1cfc2011-10-06 12:44:16 +0000938 if (LocaleCompare("fill",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000939 {
anthonyfd706f92012-01-19 04:22:02 +0000940 /* Set "fill" OR "fill-pattern" in draw_info
941 The original fill color is preserved if a fill-pattern is given.
942 That way it does not effect other operations that directly using
943 the fill color and, can be retored using "+tile".
anthonyafbaed72011-10-26 12:05:04 +0000944 */
anthony6dc09cd2011-10-12 08:56:49 +0000945 const char
anthony72feaa62012-01-17 06:46:23 +0000946 *value;
947
948 MagickBooleanType
949 status;
anthony6dc09cd2011-10-12 08:56:49 +0000950
951 ExceptionInfo
952 *sans;
953
anthonyfd706f92012-01-19 04:22:02 +0000954 PixelInfo
955 color;
956
anthony72feaa62012-01-17 06:46:23 +0000957 value = ArgOption("none");
anthony6dc09cd2011-10-12 08:56:49 +0000958 (void) SetImageOption(image_info,option,value);
anthony6dc09cd2011-10-12 08:56:49 +0000959 if (draw_info->fill_pattern != (Image *) NULL)
960 draw_info->fill_pattern=DestroyImage(draw_info->fill_pattern);
anthony72feaa62012-01-17 06:46:23 +0000961
962 /* is it a color or a image? -- ignore exceptions */
963 sans=AcquireExceptionInfo();
anthonyfd706f92012-01-19 04:22:02 +0000964 status=QueryColorCompliance(value,AllCompliance,&color,sans);
anthony72feaa62012-01-17 06:46:23 +0000965 sans=DestroyExceptionInfo(sans);
anthonyfd706f92012-01-19 04:22:02 +0000966
anthony6dc09cd2011-10-12 08:56:49 +0000967 if (status == MagickFalse)
anthony72feaa62012-01-17 06:46:23 +0000968 draw_info->fill_pattern=GetImageCache(image_info,value,exception);
anthonyfd706f92012-01-19 04:22:02 +0000969 else
970 draw_info->fill=color;
anthony805a2d42011-09-25 08:25:12 +0000971 break;
972 }
anthony74b1cfc2011-10-06 12:44:16 +0000973 if (LocaleCompare("filter",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000974 {
anthony72feaa62012-01-17 06:46:23 +0000975 /* SyncImageSettings() used to set per-image attribute. */
976 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +0000977 break;
978 }
anthonydcf510d2011-10-30 13:51:40 +0000979 if (LocaleCompare("font",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000980 {
anthony72feaa62012-01-17 06:46:23 +0000981 (void) CloneString(&draw_info->font,ArgOption(NULL));
anthony6dc09cd2011-10-12 08:56:49 +0000982 (void) CloneString(&image_info->font,draw_info->font);
anthony805a2d42011-09-25 08:25:12 +0000983 break;
984 }
anthony74b1cfc2011-10-06 12:44:16 +0000985 if (LocaleCompare("format",option) == 0)
anthony805a2d42011-09-25 08:25:12 +0000986 {
anthonydcf510d2011-10-30 13:51:40 +0000987 /* FUTURE: why the ping test, you could set ping after this! */
988 /*
anthony805a2d42011-09-25 08:25:12 +0000989 register const char
990 *q;
991
anthonydcf510d2011-10-30 13:51:40 +0000992 for (q=strchr(arg,'%'); q != (char *) NULL; q=strchr(q+1,'%'))
anthony805a2d42011-09-25 08:25:12 +0000993 if (strchr("Agkrz@[#",*(q+1)) != (char *) NULL)
994 image_info->ping=MagickFalse;
anthonydcf510d2011-10-30 13:51:40 +0000995 */
anthony72feaa62012-01-17 06:46:23 +0000996 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +0000997 break;
998 }
anthony74b1cfc2011-10-06 12:44:16 +0000999 if (LocaleCompare("fuzz",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001000 {
anthony72feaa62012-01-17 06:46:23 +00001001 /* Option used to set image fuzz! unless blank canvas (from color)
anthonydcf510d2011-10-30 13:51:40 +00001002 Image attribute used for color compare operations
anthony72feaa62012-01-17 06:46:23 +00001003 SyncImageSettings() used to set per-image attribute.
1004
1005 Can't find anything else using image_info->fuzz directly!
anthony6613bf32011-10-15 07:24:44 +00001006 */
1007 if (IfSetOption)
cristy947cb4c2011-10-20 18:41:46 +00001008 {
anthony80c37752012-01-16 01:03:11 +00001009 image_info->fuzz=StringToDoubleInterval(arg,(double)
1010 QuantumRange+1.0);
anthonydcf510d2011-10-30 13:51:40 +00001011 (void) SetImageOption(image_info,option,arg);
cristy947cb4c2011-10-20 18:41:46 +00001012 break;
1013 }
1014 image_info->fuzz=0.0;
1015 (void) SetImageOption(image_info,option,"0");
anthony805a2d42011-09-25 08:25:12 +00001016 break;
1017 }
1018 break;
1019 }
1020 case 'g':
1021 {
anthony74b1cfc2011-10-06 12:44:16 +00001022 if (LocaleCompare("gravity",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001023 {
anthony72feaa62012-01-17 06:46:23 +00001024 /* SyncImageSettings() used to set per-image attribute. */
1025 (void) SetImageOption(image_info,option,ArgOption("none"));
anthony6dc09cd2011-10-12 08:56:49 +00001026 draw_info->gravity=(GravityType) ParseCommandOption(
anthony72feaa62012-01-17 06:46:23 +00001027 MagickGravityOptions,MagickFalse,ArgOption("none"));
anthony805a2d42011-09-25 08:25:12 +00001028 break;
1029 }
anthony74b1cfc2011-10-06 12:44:16 +00001030 if (LocaleCompare("green-primary",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001031 {
anthonydcf510d2011-10-30 13:51:40 +00001032 /* Image chromaticity X,Y NB: Y=X if Y not defined
anthony72feaa62012-01-17 06:46:23 +00001033 SyncImageSettings() used to set per-image attribute.
1034 Used directly by many coders
anthonydcf510d2011-10-30 13:51:40 +00001035 */
anthony72feaa62012-01-17 06:46:23 +00001036 (void) SetImageOption(image_info,option,ArgOption("0.0"));
anthony805a2d42011-09-25 08:25:12 +00001037 break;
1038 }
1039 break;
1040 }
1041 case 'i':
1042 {
anthony74b1cfc2011-10-06 12:44:16 +00001043 if (LocaleCompare("intent",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001044 {
anthony72feaa62012-01-17 06:46:23 +00001045 /* Only used by coders: MIFF, MPC, BMP, PNG
anthonydcf510d2011-10-30 13:51:40 +00001046 and for image profile call to AcquireTransformThreadSet()
anthony72feaa62012-01-17 06:46:23 +00001047 SyncImageSettings() used to set per-image attribute.
anthonydcf510d2011-10-30 13:51:40 +00001048 */
anthony72feaa62012-01-17 06:46:23 +00001049 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001050 break;
1051 }
anthony74b1cfc2011-10-06 12:44:16 +00001052 if (LocaleCompare("interlace",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001053 {
anthony72feaa62012-01-17 06:46:23 +00001054 /* image_info is directly used by coders (so why an image setting?)
1055 SyncImageSettings() used to set per-image attribute.
anthonydcf510d2011-10-30 13:51:40 +00001056 */
anthony72feaa62012-01-17 06:46:23 +00001057 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001058 image_info->interlace=(InterlaceType) ParseCommandOption(
anthony72feaa62012-01-17 06:46:23 +00001059 MagickInterlaceOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001060 break;
1061 }
anthony74b1cfc2011-10-06 12:44:16 +00001062 if (LocaleCompare("interline-spacing",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001063 {
anthony72feaa62012-01-17 06:46:23 +00001064 (void) SetImageOption(image_info,option, ArgOption(NULL));
1065 draw_info->interline_spacing=StringToDouble(ArgOption("0"),
1066 (char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00001067 break;
1068 }
anthony74b1cfc2011-10-06 12:44:16 +00001069 if (LocaleCompare("interpolate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001070 {
anthonyfd706f92012-01-19 04:22:02 +00001071 /* SyncImageSettings() used to set per-image attribute. */
anthony72feaa62012-01-17 06:46:23 +00001072 (void) SetImageOption(image_info,option,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001073 break;
1074 }
cristy947cb4c2011-10-20 18:41:46 +00001075 if (LocaleCompare("interword-spacing",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001076 {
anthony72feaa62012-01-17 06:46:23 +00001077 (void) SetImageOption(image_info,option, ArgOption(NULL));
1078 draw_info->interword_spacing=StringToDouble(ArgOption("0"),(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00001079 break;
1080 }
1081 break;
1082 }
1083 case 'k':
1084 {
anthony74b1cfc2011-10-06 12:44:16 +00001085 if (LocaleCompare("kerning",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001086 {
anthony72feaa62012-01-17 06:46:23 +00001087 (void) SetImageOption(image_info,option,ArgOption(NULL));
1088 draw_info->kerning=StringToDouble(ArgOption("0"),(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00001089 break;
1090 }
1091 break;
1092 }
1093 case 'l':
1094 {
anthony74b1cfc2011-10-06 12:44:16 +00001095 if (LocaleCompare("label",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001096 {
anthony72feaa62012-01-17 06:46:23 +00001097 /* only used for new images - not in SyncImageOptions() */
1098 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +00001099 break;
1100 }
anthony74b1cfc2011-10-06 12:44:16 +00001101 if (LocaleCompare("log",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001102 {
anthonydcf510d2011-10-30 13:51:40 +00001103 if (IfSetOption)
1104 (void) SetLogFormat(arg);
anthony805a2d42011-09-25 08:25:12 +00001105 break;
1106 }
anthony74b1cfc2011-10-06 12:44:16 +00001107 if (LocaleCompare("loop",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001108 {
anthony72feaa62012-01-17 06:46:23 +00001109 /* SyncImageSettings() used to set per-image attribute. */
1110 (void) SetImageOption(image_info,option,ArgOption("0"));
anthony805a2d42011-09-25 08:25:12 +00001111 break;
1112 }
1113 break;
1114 }
1115 case 'm':
1116 {
anthony74b1cfc2011-10-06 12:44:16 +00001117 if (LocaleCompare("mattecolor",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001118 {
anthony72feaa62012-01-17 06:46:23 +00001119 /* SyncImageSettings() used to set per-image attribute. */
1120 (void) SetImageOption(image_info,option,ArgOption(NULL));
1121 (void) QueryColorCompliance(ArgOption(MatteColor),AllCompliance,
1122 &image_info->matte_color,exception);
anthony805a2d42011-09-25 08:25:12 +00001123 break;
1124 }
anthony74b1cfc2011-10-06 12:44:16 +00001125 if (LocaleCompare("monitor",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001126 {
anthony31f1bf72012-01-30 12:37:22 +00001127 (void) SetImageInfoProgressMonitor(image_info, IfSetOption?
1128 MonitorProgress: (MagickProgressMonitor) NULL, (void *) NULL);
anthony805a2d42011-09-25 08:25:12 +00001129 break;
1130 }
anthony74b1cfc2011-10-06 12:44:16 +00001131 if (LocaleCompare("monochrome",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001132 {
anthony72feaa62012-01-17 06:46:23 +00001133 /* Setting (for some input coders)
1134 But also a special 'type' operator
1135 */
1136 image_info->monochrome= ArgBoolean;
anthony805a2d42011-09-25 08:25:12 +00001137 break;
1138 }
1139 break;
1140 }
1141 case 'o':
1142 {
anthony74b1cfc2011-10-06 12:44:16 +00001143 if (LocaleCompare("orient",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001144 {
anthony72feaa62012-01-17 06:46:23 +00001145 /* Is not used when defining for new images.
anthonydcf510d2011-10-30 13:51:40 +00001146 This makes it more of a 'operation' than a setting
anthony72feaa62012-01-17 06:46:23 +00001147 FUTURE: make set meta-data operator instead.
1148 SyncImageSettings() used to set per-image attribute.
anthonydcf510d2011-10-30 13:51:40 +00001149 */
anthony72feaa62012-01-17 06:46:23 +00001150 (void) SetImageOption(image_info,option, ArgOption(NULL));
anthonydcf510d2011-10-30 13:51:40 +00001151 image_info->orientation=(InterlaceType) ParseCommandOption(
anthony72feaa62012-01-17 06:46:23 +00001152 MagickOrientationOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001153 break;
1154 }
1155 }
1156 case 'p':
1157 {
anthony74b1cfc2011-10-06 12:44:16 +00001158 if (LocaleCompare("page",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001159 {
anthony72feaa62012-01-17 06:46:23 +00001160 /* Only used for new images and image generators
1161 SyncImageSettings() used to set per-image attribute. ?????
1162 That last is WRONG!!!!
1163 */
anthony805a2d42011-09-25 08:25:12 +00001164 char
1165 *canonical_page,
1166 page[MaxTextExtent];
1167
1168 const char
1169 *image_option;
1170
1171 MagickStatusType
1172 flags;
1173
1174 RectangleInfo
1175 geometry;
1176
anthonydcf510d2011-10-30 13:51:40 +00001177 if (!IfSetOption)
anthony805a2d42011-09-25 08:25:12 +00001178 {
anthony74b1cfc2011-10-06 12:44:16 +00001179 (void) DeleteImageOption(image_info,option);
anthony805a2d42011-09-25 08:25:12 +00001180 (void) CloneString(&image_info->page,(char *) NULL);
1181 break;
1182 }
1183 (void) ResetMagickMemory(&geometry,0,sizeof(geometry));
1184 image_option=GetImageOption(image_info,"page");
1185 if (image_option != (const char *) NULL)
1186 flags=ParseAbsoluteGeometry(image_option,&geometry);
anthonydcf510d2011-10-30 13:51:40 +00001187 canonical_page=GetPageGeometry(arg);
anthony805a2d42011-09-25 08:25:12 +00001188 flags=ParseAbsoluteGeometry(canonical_page,&geometry);
1189 canonical_page=DestroyString(canonical_page);
1190 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu",
1191 (unsigned long) geometry.width,(unsigned long) geometry.height);
1192 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
1193 (void) FormatLocaleString(page,MaxTextExtent,"%lux%lu%+ld%+ld",
1194 (unsigned long) geometry.width,(unsigned long) geometry.height,
1195 (long) geometry.x,(long) geometry.y);
anthony74b1cfc2011-10-06 12:44:16 +00001196 (void) SetImageOption(image_info,option,page);
anthony805a2d42011-09-25 08:25:12 +00001197 (void) CloneString(&image_info->page,page);
1198 break;
1199 }
anthony74b1cfc2011-10-06 12:44:16 +00001200 if (LocaleCompare("ping",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001201 {
anthony72feaa62012-01-17 06:46:23 +00001202 image_info->ping = ArgBoolean;
anthony805a2d42011-09-25 08:25:12 +00001203 break;
1204 }
anthony74b1cfc2011-10-06 12:44:16 +00001205 if (LocaleCompare("pointsize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001206 {
anthony72feaa62012-01-17 06:46:23 +00001207 image_info->pointsize=draw_info->pointsize=
1208 StringToDouble(ArgOption("12"),(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00001209 break;
1210 }
anthony74b1cfc2011-10-06 12:44:16 +00001211 if (LocaleCompare("precision",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001212 {
anthony72feaa62012-01-17 06:46:23 +00001213 (void) SetMagickPrecision(StringToInteger(ArgOption("-1")));
anthony805a2d42011-09-25 08:25:12 +00001214 break;
1215 }
anthonydcf510d2011-10-30 13:51:40 +00001216 /* FUTURE: Only the 'preview' coder appears to use this
1217 * Depreciate the coder? Leaving only the 'preview' operator.
anthony74b1cfc2011-10-06 12:44:16 +00001218 if (LocaleCompare("preview",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001219 {
anthonydcf510d2011-10-30 13:51:40 +00001220 image_info->preview_type=UndefinedPreview;
1221 if (IfSetOption)
1222 image_info->preview_type=(PreviewType) ParseCommandOption(
1223 MagickPreviewOptions,MagickFalse,arg);
anthony805a2d42011-09-25 08:25:12 +00001224 break;
1225 }
anthonydcf510d2011-10-30 13:51:40 +00001226 */
anthony805a2d42011-09-25 08:25:12 +00001227 break;
1228 }
1229 case 'q':
1230 {
anthony74b1cfc2011-10-06 12:44:16 +00001231 if (LocaleCompare("quality",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001232 {
anthony72feaa62012-01-17 06:46:23 +00001233 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthonydcf510d2011-10-30 13:51:40 +00001234 image_info->quality=UndefinedCompressionQuality;
anthony72feaa62012-01-17 06:46:23 +00001235 if (IfSetOption)
1236 image_info->quality=StringToUnsignedLong(arg);
anthony805a2d42011-09-25 08:25:12 +00001237 break;
1238 }
anthonyafbaed72011-10-26 12:05:04 +00001239 if (LocaleCompare("quantize",option) == 0)
1240 {
anthony72feaa62012-01-17 06:46:23 +00001241 /* Just a set direct in quantize_info */
anthonyafbaed72011-10-26 12:05:04 +00001242 quantize_info->colorspace=UndefinedColorspace;
1243 if (IfSetOption)
1244 quantize_info->colorspace=(ColorspaceType) ParseCommandOption(
anthonydcf510d2011-10-30 13:51:40 +00001245 MagickColorspaceOptions,MagickFalse,arg);
anthonyafbaed72011-10-26 12:05:04 +00001246 break;
1247 }
anthony74b1cfc2011-10-06 12:44:16 +00001248 if (LocaleCompare("quiet",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001249 {
anthonydcf510d2011-10-30 13:51:40 +00001250 /* FUTURE: if two -quiet is performed you can not do +quiet! */
anthony805a2d42011-09-25 08:25:12 +00001251 static WarningHandler
1252 warning_handler = (WarningHandler) NULL;
anthony72feaa62012-01-17 06:46:23 +00001253
anthonyafbaed72011-10-26 12:05:04 +00001254 WarningHandler
1255 tmp = SetWarningHandler((WarningHandler) NULL);
anthony805a2d42011-09-25 08:25:12 +00001256
anthonyafbaed72011-10-26 12:05:04 +00001257 if ( tmp != (WarningHandler) NULL)
1258 warning_handler = tmp; /* remember the old handler */
1259 if (!IfSetOption) /* set the old handler */
1260 warning_handler=SetWarningHandler(warning_handler);
anthony805a2d42011-09-25 08:25:12 +00001261 break;
1262 }
1263 break;
1264 }
1265 case 'r':
1266 {
anthony74b1cfc2011-10-06 12:44:16 +00001267 if (LocaleCompare("red-primary",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001268 {
anthonydcf510d2011-10-30 13:51:40 +00001269 /* Image chromaticity X,Y NB: Y=X if Y not defined
1270 Used by many coders
anthony72feaa62012-01-17 06:46:23 +00001271 SyncImageSettings() used to set per-image attribute.
anthonydcf510d2011-10-30 13:51:40 +00001272 */
anthony72feaa62012-01-17 06:46:23 +00001273 (void) SetImageOption(image_info,option,ArgOption("0.0"));
anthony805a2d42011-09-25 08:25:12 +00001274 break;
1275 }
anthonyafbaed72011-10-26 12:05:04 +00001276 if (LocaleCompare("render",option) == 0)
1277 {
1278 /* draw_info only setting */
1279 draw_info->render= IfSetOption ? MagickFalse : MagickTrue;
1280 break;
1281 }
anthony43f425d2012-02-26 12:58:58 +00001282 if (LocaleCompare("respect-parenthesis",option) == 0)
1283 {
1284 (void) SetImageOption(image_info,option,ArgOption(NULL));
1285 break;
1286 }
anthony805a2d42011-09-25 08:25:12 +00001287 break;
1288 }
1289 case 's':
1290 {
anthony74b1cfc2011-10-06 12:44:16 +00001291 if (LocaleCompare("sampling-factor",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001292 {
anthonyafbaed72011-10-26 12:05:04 +00001293 /* FUTURE: should be converted to jpeg:sampling_factor */
anthony72feaa62012-01-17 06:46:23 +00001294 (void) CloneString(&image_info->sampling_factor,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +00001295 break;
1296 }
anthony74b1cfc2011-10-06 12:44:16 +00001297 if (LocaleCompare("scene",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001298 {
anthony72feaa62012-01-17 06:46:23 +00001299 /* SyncImageSettings() used to set per-image attribute.
1300 What ??? Why ????
1301 */
1302 (void) SetImageOption(image_info,option,ArgOption(NULL));
1303 image_info->scene=StringToUnsignedLong(ArgOption("0"));
anthony805a2d42011-09-25 08:25:12 +00001304 break;
1305 }
anthony74b1cfc2011-10-06 12:44:16 +00001306 if (LocaleCompare("seed",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001307 {
anthonyafbaed72011-10-26 12:05:04 +00001308 SeedPseudoRandomGenerator(
anthonydcf510d2011-10-30 13:51:40 +00001309 IfSetOption ? (size_t) StringToUnsignedLong(arg)
anthonyafbaed72011-10-26 12:05:04 +00001310 : (size_t) time((time_t *) NULL) );
anthony805a2d42011-09-25 08:25:12 +00001311 break;
1312 }
anthony74b1cfc2011-10-06 12:44:16 +00001313 if (LocaleCompare("size",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001314 {
anthonyafbaed72011-10-26 12:05:04 +00001315 /* FUTURE: string in image_info -- convert to Option ???
1316 Look at the special handling for "size" in SetImageOption()
anthony74b1cfc2011-10-06 12:44:16 +00001317 */
anthony72feaa62012-01-17 06:46:23 +00001318 (void) CloneString(&image_info->size,ArgOption(NULL));
anthonyafbaed72011-10-26 12:05:04 +00001319 break;
1320 }
1321 if (LocaleCompare("stretch",option) == 0)
1322 {
anthony72feaa62012-01-17 06:46:23 +00001323 draw_info->stretch=(StretchType) ParseCommandOption(
1324 MagickStretchOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001325 break;
1326 }
anthony74b1cfc2011-10-06 12:44:16 +00001327 if (LocaleCompare("stroke",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001328 {
anthonyafbaed72011-10-26 12:05:04 +00001329 /* set stroke color OR stroke-pattern
anthonyfd706f92012-01-19 04:22:02 +00001330 UPDATE: ensure stroke color is not destroyed is a pattern
1331 is given. Just in case the color is also used for other purposes.
anthonyafbaed72011-10-26 12:05:04 +00001332 */
1333 const char
anthony72feaa62012-01-17 06:46:23 +00001334 *value;
1335
1336 MagickBooleanType
1337 status;
anthonyafbaed72011-10-26 12:05:04 +00001338
1339 ExceptionInfo
1340 *sans;
1341
anthonyfd706f92012-01-19 04:22:02 +00001342 PixelInfo
1343 color;
1344
anthony72feaa62012-01-17 06:46:23 +00001345 value = ArgOption("none");
anthonyafbaed72011-10-26 12:05:04 +00001346 (void) SetImageOption(image_info,option,value);
anthony72feaa62012-01-17 06:46:23 +00001347 if (draw_info->stroke_pattern != (Image *) NULL)
1348 draw_info->stroke_pattern=DestroyImage(draw_info->stroke_pattern);
1349
1350 /* is it a color or a image? -- ignore exceptions */
anthonyafbaed72011-10-26 12:05:04 +00001351 sans=AcquireExceptionInfo();
anthonyfd706f92012-01-19 04:22:02 +00001352 status=QueryColorCompliance(value,AllCompliance,&color,sans);
anthonyafbaed72011-10-26 12:05:04 +00001353 sans=DestroyExceptionInfo(sans);
anthonyfd706f92012-01-19 04:22:02 +00001354
anthonyafbaed72011-10-26 12:05:04 +00001355 if (status == MagickFalse)
anthonyfd706f92012-01-19 04:22:02 +00001356 draw_info->stroke_pattern=GetImageCache(image_info,value,exception);
1357 else
1358 draw_info->stroke=color;
anthony805a2d42011-09-25 08:25:12 +00001359 break;
1360 }
anthony74b1cfc2011-10-06 12:44:16 +00001361 if (LocaleCompare("strokewidth",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001362 {
anthony72feaa62012-01-17 06:46:23 +00001363 (void) SetImageOption(image_info,option,ArgOption(NULL));
1364 draw_info->stroke_width=StringToDouble(ArgOption("1.0"),
1365 (char **) NULL);
anthonyafbaed72011-10-26 12:05:04 +00001366 break;
1367 }
1368 if (LocaleCompare("style",option) == 0)
1369 {
anthony72feaa62012-01-17 06:46:23 +00001370 draw_info->style=(StyleType) ParseCommandOption(MagickStyleOptions,
1371 MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001372 break;
1373 }
anthony74b1cfc2011-10-06 12:44:16 +00001374 if (LocaleCompare("synchronize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001375 {
anthony72feaa62012-01-17 06:46:23 +00001376 image_info->synchronize = ArgBoolean;
anthony805a2d42011-09-25 08:25:12 +00001377 break;
1378 }
1379 break;
1380 }
1381 case 't':
1382 {
anthony74b1cfc2011-10-06 12:44:16 +00001383 if (LocaleCompare("taint",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001384 {
anthony72feaa62012-01-17 06:46:23 +00001385 /* SyncImageSettings() used to set per-image attribute. */
anthonyafbaed72011-10-26 12:05:04 +00001386 (void) SetImageOption(image_info,option,
1387 IfSetOption ? "true" : "false");
anthony805a2d42011-09-25 08:25:12 +00001388 break;
1389 }
anthony74b1cfc2011-10-06 12:44:16 +00001390 if (LocaleCompare("texture",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001391 {
anthonyafbaed72011-10-26 12:05:04 +00001392 /* FUTURE: move image_info string to option splay-tree */
anthony72feaa62012-01-17 06:46:23 +00001393 (void) CloneString(&image_info->texture,ArgOption(NULL));
anthonyafbaed72011-10-26 12:05:04 +00001394 break;
1395 }
1396 if (LocaleCompare("tile",option) == 0)
1397 {
anthony72feaa62012-01-17 06:46:23 +00001398 draw_info->fill_pattern=IfSetOption
1399 ?GetImageCache(image_info,arg,exception)
1400 :DestroyImage(draw_info->fill_pattern);
anthony805a2d42011-09-25 08:25:12 +00001401 break;
1402 }
anthony74b1cfc2011-10-06 12:44:16 +00001403 if (LocaleCompare("tile-offset",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001404 {
anthony72feaa62012-01-17 06:46:23 +00001405 /* SyncImageSettings() used to set per-image attribute. ??? */
1406 (void) SetImageOption(image_info,option,ArgOption("0"));
anthony805a2d42011-09-25 08:25:12 +00001407 break;
1408 }
anthony74b1cfc2011-10-06 12:44:16 +00001409 if (LocaleCompare("transparent-color",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001410 {
anthonyafbaed72011-10-26 12:05:04 +00001411 /* FUTURE: both image_info attribute & ImageOption in use!
1412 image_info only used for generating new images.
anthony72feaa62012-01-17 06:46:23 +00001413 SyncImageSettings() used to set per-image attribute.
1414
anthonyafbaed72011-10-26 12:05:04 +00001415 Note that +transparent-color, means fall-back to image
1416 attribute so ImageOption is deleted, not set to a default.
1417 */
anthony72feaa62012-01-17 06:46:23 +00001418 (void) SetImageOption(image_info,option,ArgOption(NULL));
1419 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1420 &image_info->transparent_color,exception);
anthony805a2d42011-09-25 08:25:12 +00001421 break;
1422 }
anthony31f1bf72012-01-30 12:37:22 +00001423 if (LocaleCompare("treedepth",option) == 0)
1424 {
1425 (void) SetImageOption(image_info,option,ArgOption(NULL));
1426 quantize_info->tree_depth=StringToUnsignedLong(ArgOption("0"));
1427 break;
1428 }
anthony74b1cfc2011-10-06 12:44:16 +00001429 if (LocaleCompare("type",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001430 {
anthony72feaa62012-01-17 06:46:23 +00001431 /* SyncImageSettings() used to set per-image attribute. */
1432 (void) SetImageOption(image_info,option,ArgOption(NULL));
1433 image_info->type=(ImageType) ParseCommandOption(MagickTypeOptions,
1434 MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001435 break;
1436 }
1437 break;
1438 }
1439 case 'u':
1440 {
anthony74b1cfc2011-10-06 12:44:16 +00001441 if (LocaleCompare("undercolor",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001442 {
anthony72feaa62012-01-17 06:46:23 +00001443 (void) SetImageOption(image_info,option,ArgOption(NULL));
1444 (void) QueryColorCompliance(ArgOption("none"),AllCompliance,
1445 &draw_info->undercolor,exception);
anthony805a2d42011-09-25 08:25:12 +00001446 break;
1447 }
anthony74b1cfc2011-10-06 12:44:16 +00001448 if (LocaleCompare("units",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001449 {
anthony72feaa62012-01-17 06:46:23 +00001450 /* SyncImageSettings() used to set per-image attribute.
1451 Should this effect draw_info X and Y resolution?
1452 FUTURE: this probably should be part of the density setting
1453 */
1454 (void) SetImageOption(image_info,option,ArgOption(NULL));
1455 image_info->units=(ResolutionType) ParseCommandOption(
1456 MagickResolutionOptions,MagickFalse,ArgOption("undefined"));
anthony805a2d42011-09-25 08:25:12 +00001457 break;
1458 }
1459 break;
1460 }
1461 case 'v':
1462 {
anthony74b1cfc2011-10-06 12:44:16 +00001463 if (LocaleCompare("verbose",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001464 {
anthonyab3a50c2011-10-27 11:48:57 +00001465 /* FUTURE: Also an image artifact, set in Simple Operators.
1466 But artifact is only used in verbose output.
1467 */
anthony31f1bf72012-01-30 12:37:22 +00001468 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony72feaa62012-01-17 06:46:23 +00001469 image_info->verbose= ArgBoolean;
anthonyab3a50c2011-10-27 11:48:57 +00001470 image_info->ping=MagickFalse; /* verbose can't be a ping */
anthony805a2d42011-09-25 08:25:12 +00001471 break;
1472 }
anthony74b1cfc2011-10-06 12:44:16 +00001473 if (LocaleCompare("view",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001474 {
anthony72feaa62012-01-17 06:46:23 +00001475 /* FUTURE: Convert from image_info to ImageOption
anthonyab3a50c2011-10-27 11:48:57 +00001476 Only used by coder FPX
1477 */
anthony72feaa62012-01-17 06:46:23 +00001478 (void) CloneString(&image_info->view,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +00001479 break;
1480 }
anthony74b1cfc2011-10-06 12:44:16 +00001481 if (LocaleCompare("virtual-pixel",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001482 {
anthonyfd706f92012-01-19 04:22:02 +00001483 /* SyncImageSettings() used to set per-image attribute.
1484 This is VERY deep in the image caching structure.
1485 */
anthony72feaa62012-01-17 06:46:23 +00001486 (void) SetImageOption(image_info,option,ArgOption(NULL));
anthony805a2d42011-09-25 08:25:12 +00001487 break;
1488 }
1489 break;
1490 }
1491 case 'w':
1492 {
anthonydcf510d2011-10-30 13:51:40 +00001493 if (LocaleCompare("weight",option) == 0)
anthonyab3a50c2011-10-27 11:48:57 +00001494 {
anthony72feaa62012-01-17 06:46:23 +00001495 /* Just what does using a font 'weight' do ???
anthonydcf510d2011-10-30 13:51:40 +00001496 There is no "-list weight" output (reference manual says there is)
anthonyab3a50c2011-10-27 11:48:57 +00001497 */
anthony72feaa62012-01-17 06:46:23 +00001498 if (!IfSetOption)
1499 break;
anthonydcf510d2011-10-30 13:51:40 +00001500 draw_info->weight=StringToUnsignedLong(arg);
1501 if (LocaleCompare(arg,"all") == 0)
anthonyab3a50c2011-10-27 11:48:57 +00001502 draw_info->weight=0;
anthonydcf510d2011-10-30 13:51:40 +00001503 if (LocaleCompare(arg,"bold") == 0)
anthonyab3a50c2011-10-27 11:48:57 +00001504 draw_info->weight=700;
anthonydcf510d2011-10-30 13:51:40 +00001505 if (LocaleCompare(arg,"bolder") == 0)
anthonyab3a50c2011-10-27 11:48:57 +00001506 if (draw_info->weight <= 800)
1507 draw_info->weight+=100;
anthonydcf510d2011-10-30 13:51:40 +00001508 if (LocaleCompare(arg,"lighter") == 0)
anthonyab3a50c2011-10-27 11:48:57 +00001509 if (draw_info->weight >= 100)
1510 draw_info->weight-=100;
anthonydcf510d2011-10-30 13:51:40 +00001511 if (LocaleCompare(arg,"normal") == 0)
anthonyab3a50c2011-10-27 11:48:57 +00001512 draw_info->weight=400;
1513 break;
1514 }
anthony74b1cfc2011-10-06 12:44:16 +00001515 if (LocaleCompare("white-point",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001516 {
anthony72feaa62012-01-17 06:46:23 +00001517 /* Used as a image chromaticity setting
1518 SyncImageSettings() used to set per-image attribute.
1519 */
1520 (void) SetImageOption(image_info,option,ArgOption("0.0"));
anthony805a2d42011-09-25 08:25:12 +00001521 break;
1522 }
1523 break;
1524 }
1525 default:
1526 break;
1527 }
anthonyfd706f92012-01-19 04:22:02 +00001528#undef image_info
anthony43f425d2012-02-26 12:58:58 +00001529#undef exception
anthonyfd706f92012-01-19 04:22:02 +00001530#undef draw_info
1531#undef quantize_info
anthonyfd706f92012-01-19 04:22:02 +00001532#undef IfSetOption
1533#undef ArgOption
1534#undef ArgBoolean
1535
anthony31f1bf72012-01-30 12:37:22 +00001536 return;
anthony805a2d42011-09-25 08:25:12 +00001537}
1538
1539/*
1540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541% %
1542% %
1543% %
anthony43f425d2012-02-26 12:58:58 +00001544+ C L I S i m p l e O p e r a t o r I m a g e s %
anthony805a2d42011-09-25 08:25:12 +00001545% %
1546% %
1547% %
1548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549%
anthony31f1bf72012-01-30 12:37:22 +00001550% WandSimpleOperatorImages() applys one simple image operation given to all
anthony43f425d2012-02-26 12:58:58 +00001551% the images in the CLI wand, with the settings that was previously saved in
1552% the CLI wand.
anthonydcf510d2011-10-30 13:51:40 +00001553%
1554% It is assumed that any per-image settings are up-to-date with respect to
anthony43f425d2012-02-26 12:58:58 +00001555% extra settings that were already saved in the wand.
anthony805a2d42011-09-25 08:25:12 +00001556%
anthonyd1447672012-01-19 05:33:53 +00001557% The format of the WandSimpleOperatorImage method is:
anthony805a2d42011-09-25 08:25:12 +00001558%
anthony43f425d2012-02-26 12:58:58 +00001559% void CLISimpleOperatorImages(MagickCLI *cli_wand,
anthonyfd706f92012-01-19 04:22:02 +00001560% const MagickBooleanType plus_alt_op, const char *option,
1561% const char *arg1, const char *arg2)
anthony805a2d42011-09-25 08:25:12 +00001562%
1563% A description of each parameter follows:
1564%
anthony43f425d2012-02-26 12:58:58 +00001565% o cli_wand: structure holding settings and images to be operated on
anthony805a2d42011-09-25 08:25:12 +00001566%
anthonyfd706f92012-01-19 04:22:02 +00001567% o plus_alt_op: request the 'plus' or alturnative form of the operation
anthony805a2d42011-09-25 08:25:12 +00001568%
anthonyfd706f92012-01-19 04:22:02 +00001569% o option: The option string for the operation
anthonydcf510d2011-10-30 13:51:40 +00001570%
anthonyfd706f92012-01-19 04:22:02 +00001571% o arg1, arg2: optional argument strings to the operation
anthony805a2d42011-09-25 08:25:12 +00001572%
anthony31f1bf72012-01-30 12:37:22 +00001573% Any problems will be added to the 'exception' entry of the given wand.
anthony805a2d42011-09-25 08:25:12 +00001574%
anthony31f1bf72012-01-30 12:37:22 +00001575% Example usage...
anthonydcf510d2011-10-30 13:51:40 +00001576%
anthony43f425d2012-02-26 12:58:58 +00001577% CLISimpleOperatorImages(cli_wand, MagickFalse,"crop","100x100+20+30",NULL);
1578% CLISimpleOperatorImages(cli_wand, MagickTrue, "repage",NULL,NULL);
1579% CLISimpleOperatorImages(cli_wand, MagickTrue, "distort","SRT","45");
1580% if ( cli_wand->wand.exception->severity != UndefinedException ) {
anthony31f1bf72012-01-30 12:37:22 +00001581% CatchException(exception);
1582% exit(1);
1583% }
anthonyfd706f92012-01-19 04:22:02 +00001584%
1585% Or for handling command line arguments EG: +/-option ["arg"]
anthonydcf510d2011-10-30 13:51:40 +00001586%
anthony43f425d2012-02-26 12:58:58 +00001587% cli_wand
anthonydcf510d2011-10-30 13:51:40 +00001588% argc,argv
1589% i=index in argv
1590%
anthony2052d272012-02-28 12:48:29 +00001591% option_info = GetCommandOptionInfo(argv[i]);
1592% count=option_info->type;
1593% option_type=option_info->flags;
1594%
1595% if ( (option_type & SimpleOperatorOptionFlag) != 0 )
anthony43f425d2012-02-26 12:58:58 +00001596% CLISimpleOperatorImages(cli_wand,
anthony36a8c2c2012-02-10 00:08:44 +00001597% ((*argv[i])=='+')?MagickTrue:MagickFalse,argv[i]+1,
anthonyfd706f92012-01-19 04:22:02 +00001598% count>=1 ? argv[i+1] : (char *)NULL,
1599% count>=2 ? argv[i+2] : (char *)NULL );
anthonydcf510d2011-10-30 13:51:40 +00001600% i += count+1;
1601%
anthony805a2d42011-09-25 08:25:12 +00001602*/
anthony31f1bf72012-01-30 12:37:22 +00001603
1604/*
1605 Internal subrountine to apply one simple image operation to the current
anthony43f425d2012-02-26 12:58:58 +00001606 image pointed to by the CLI wand.
anthony31f1bf72012-01-30 12:37:22 +00001607
1608 The image in the list may be modified in three different ways...
1609 * directly modified (EG: -negate, -gamma, -level, -annotate, -draw),
1610 * replaced by a new image (EG: -spread, -resize, -rotate, -morphology)
1611 * one image replace by a list of images (-separate and -crop only!)
1612
1613 In each case the result replaces the original image in the list, as well as
1614 the pointer to the modified image (last image added if replaced by a list
1615 of images) is returned.
1616
1617 As the image pointed to may be replaced, the first image in the list may
1618 also change. GetFirstImageInList() should be used by caller if they wish
1619 return the Image pointer to the first image in list.
1620*/
anthony43f425d2012-02-26 12:58:58 +00001621static void CLISimpleOperatorImage(MagickCLI *cli_wand,
anthony36a8c2c2012-02-10 00:08:44 +00001622 const MagickBooleanType plus_alt_op, const char *option,
1623 const char *arg1, const char *arg2)
anthony805a2d42011-09-25 08:25:12 +00001624{
1625 Image *
1626 new_image;
1627
anthony805a2d42011-09-25 08:25:12 +00001628 GeometryInfo
1629 geometry_info;
1630
1631 RectangleInfo
1632 geometry;
1633
1634 MagickStatusType
anthony805a2d42011-09-25 08:25:12 +00001635 flags;
1636
anthony43f425d2012-02-26 12:58:58 +00001637#define image_info (cli_wand->wand.image_info)
1638#define image (cli_wand->wand.images)
1639#define exception (cli_wand->wand.exception)
1640#define draw_info (cli_wand->draw_info)
1641#define quantize_info (cli_wand->quantize_info)
anthony31f1bf72012-01-30 12:37:22 +00001642#define normal_op (plus_alt_op?MagickFalse:MagickTrue)
anthonyfd706f92012-01-19 04:22:02 +00001643
anthony43f425d2012-02-26 12:58:58 +00001644 assert(cli_wand != (MagickCLI *) NULL);
1645 assert(cli_wand->signature == WandSignature);
1646 assert(cli_wand->wand.signature == WandSignature);
1647 assert(image != (Image *) NULL); /* an image must be present */
1648 if (cli_wand->wand.debug != MagickFalse)
1649 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthonydcf510d2011-10-30 13:51:40 +00001650
anthony805a2d42011-09-25 08:25:12 +00001651 SetGeometryInfo(&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001652
anthonydcf510d2011-10-30 13:51:40 +00001653 new_image = (Image *)NULL; /* the replacement image, if not null at end */
anthony805a2d42011-09-25 08:25:12 +00001654
anthonyfd706f92012-01-19 04:22:02 +00001655 /* FUTURE: We may need somthing a little more optimized than this!
1656 Perhaps, do the 'sync' if 'settings tainted' before next operator.
1657 */
anthony31f1bf72012-01-30 12:37:22 +00001658 (void) SyncImageSettings(image_info,image,exception);
anthonydcf510d2011-10-30 13:51:40 +00001659
1660 switch (*option)
anthony805a2d42011-09-25 08:25:12 +00001661 {
1662 case 'a':
1663 {
anthonydcf510d2011-10-30 13:51:40 +00001664 if (LocaleCompare("adaptive-blur",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001665 {
anthonyfd706f92012-01-19 04:22:02 +00001666 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001667 if ((flags & SigmaValue) == 0)
1668 geometry_info.sigma=1.0;
1669 if ((flags & XiValue) == 0)
1670 geometry_info.xi=0.0;
anthony31f1bf72012-01-30 12:37:22 +00001671 new_image=AdaptiveBlurImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00001672 geometry_info.sigma,geometry_info.xi,exception);
1673 break;
1674 }
anthonydcf510d2011-10-30 13:51:40 +00001675 if (LocaleCompare("adaptive-resize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001676 {
anthony31f1bf72012-01-30 12:37:22 +00001677 (void) ParseRegionGeometry(image,arg1,&geometry,exception);
1678 new_image=AdaptiveResizeImage(image,geometry.width,geometry.height,
anthonyfd706f92012-01-19 04:22:02 +00001679 exception);
anthony805a2d42011-09-25 08:25:12 +00001680 break;
1681 }
anthonydcf510d2011-10-30 13:51:40 +00001682 if (LocaleCompare("adaptive-sharpen",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001683 {
anthonyfd706f92012-01-19 04:22:02 +00001684 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001685 if ((flags & SigmaValue) == 0)
1686 geometry_info.sigma=1.0;
1687 if ((flags & XiValue) == 0)
1688 geometry_info.xi=0.0;
anthony31f1bf72012-01-30 12:37:22 +00001689 new_image=AdaptiveSharpenImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00001690 geometry_info.sigma,geometry_info.xi,exception);
1691 break;
1692 }
anthonydcf510d2011-10-30 13:51:40 +00001693 if (LocaleCompare("alpha",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001694 {
1695 AlphaChannelType
1696 alpha_type;
1697
anthony805a2d42011-09-25 08:25:12 +00001698 alpha_type=(AlphaChannelType) ParseCommandOption(MagickAlphaOptions,
anthonyfd706f92012-01-19 04:22:02 +00001699 MagickFalse,arg1);
anthony31f1bf72012-01-30 12:37:22 +00001700 (void) SetImageAlphaChannel(image,alpha_type,exception);
anthony805a2d42011-09-25 08:25:12 +00001701 break;
1702 }
anthonydcf510d2011-10-30 13:51:40 +00001703 if (LocaleCompare("annotate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001704 {
1705 char
1706 *text,
1707 geometry[MaxTextExtent];
1708
anthony805a2d42011-09-25 08:25:12 +00001709 SetGeometryInfo(&geometry_info);
anthonyfd706f92012-01-19 04:22:02 +00001710 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001711 if ((flags & SigmaValue) == 0)
1712 geometry_info.sigma=geometry_info.rho;
anthony31f1bf72012-01-30 12:37:22 +00001713 text=InterpretImageProperties(image_info,image,arg2,
anthony805a2d42011-09-25 08:25:12 +00001714 exception);
1715 if (text == (char *) NULL)
1716 break;
1717 (void) CloneString(&draw_info->text,text);
1718 text=DestroyString(text);
1719 (void) FormatLocaleString(geometry,MaxTextExtent,"%+f%+f",
1720 geometry_info.xi,geometry_info.psi);
1721 (void) CloneString(&draw_info->geometry,geometry);
1722 draw_info->affine.sx=cos(DegreesToRadians(
1723 fmod(geometry_info.rho,360.0)));
1724 draw_info->affine.rx=sin(DegreesToRadians(
1725 fmod(geometry_info.rho,360.0)));
1726 draw_info->affine.ry=(-sin(DegreesToRadians(
1727 fmod(geometry_info.sigma,360.0))));
1728 draw_info->affine.sy=cos(DegreesToRadians(
1729 fmod(geometry_info.sigma,360.0)));
anthony31f1bf72012-01-30 12:37:22 +00001730 (void) AnnotateImage(image,draw_info,exception);
anthonyfd706f92012-01-19 04:22:02 +00001731 GetAffineMatrix(&draw_info->affine);
anthony805a2d42011-09-25 08:25:12 +00001732 break;
1733 }
anthonydcf510d2011-10-30 13:51:40 +00001734 if (LocaleCompare("auto-gamma",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001735 {
anthony31f1bf72012-01-30 12:37:22 +00001736 (void) AutoGammaImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001737 break;
1738 }
anthonydcf510d2011-10-30 13:51:40 +00001739 if (LocaleCompare("auto-level",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001740 {
anthony31f1bf72012-01-30 12:37:22 +00001741 (void) AutoLevelImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001742 break;
1743 }
anthonydcf510d2011-10-30 13:51:40 +00001744 if (LocaleCompare("auto-orient",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001745 {
anthony31f1bf72012-01-30 12:37:22 +00001746 switch (image->orientation)
anthony805a2d42011-09-25 08:25:12 +00001747 {
1748 case TopRightOrientation:
1749 {
anthony31f1bf72012-01-30 12:37:22 +00001750 new_image=FlopImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001751 break;
1752 }
1753 case BottomRightOrientation:
1754 {
anthony31f1bf72012-01-30 12:37:22 +00001755 new_image=RotateImage(image,180.0,exception);
anthony805a2d42011-09-25 08:25:12 +00001756 break;
1757 }
1758 case BottomLeftOrientation:
1759 {
anthony31f1bf72012-01-30 12:37:22 +00001760 new_image=FlipImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001761 break;
1762 }
1763 case LeftTopOrientation:
1764 {
anthony31f1bf72012-01-30 12:37:22 +00001765 new_image=TransposeImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001766 break;
1767 }
1768 case RightTopOrientation:
1769 {
anthony31f1bf72012-01-30 12:37:22 +00001770 new_image=RotateImage(image,90.0,exception);
anthony805a2d42011-09-25 08:25:12 +00001771 break;
1772 }
1773 case RightBottomOrientation:
1774 {
anthony31f1bf72012-01-30 12:37:22 +00001775 new_image=TransverseImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001776 break;
1777 }
1778 case LeftBottomOrientation:
1779 {
anthony31f1bf72012-01-30 12:37:22 +00001780 new_image=RotateImage(image,270.0,exception);
anthony805a2d42011-09-25 08:25:12 +00001781 break;
1782 }
1783 default:
1784 break;
1785 }
1786 if (new_image != (Image *) NULL)
1787 new_image->orientation=TopLeftOrientation;
1788 break;
1789 }
1790 break;
1791 }
1792 case 'b':
1793 {
anthonydcf510d2011-10-30 13:51:40 +00001794 if (LocaleCompare("black-threshold",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001795 {
anthony31f1bf72012-01-30 12:37:22 +00001796 (void) BlackThresholdImage(image,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00001797 break;
1798 }
anthonydcf510d2011-10-30 13:51:40 +00001799 if (LocaleCompare("blue-shift",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001800 {
anthony805a2d42011-09-25 08:25:12 +00001801 geometry_info.rho=1.5;
anthonyfd706f92012-01-19 04:22:02 +00001802 if (plus_alt_op == MagickFalse)
1803 flags=ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00001804 new_image=BlueShiftImage(image,geometry_info.rho,exception);
anthony805a2d42011-09-25 08:25:12 +00001805 break;
1806 }
anthonydcf510d2011-10-30 13:51:40 +00001807 if (LocaleCompare("blur",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001808 {
anthony74b1cfc2011-10-06 12:44:16 +00001809 /* FUTURE: use of "bias" in a blur is non-sensible */
anthonyfd706f92012-01-19 04:22:02 +00001810 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001811 if ((flags & SigmaValue) == 0)
1812 geometry_info.sigma=1.0;
1813 if ((flags & XiValue) == 0)
1814 geometry_info.xi=0.0;
anthony31f1bf72012-01-30 12:37:22 +00001815 new_image=BlurImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00001816 geometry_info.sigma,geometry_info.xi,exception);
1817 break;
1818 }
anthonydcf510d2011-10-30 13:51:40 +00001819 if (LocaleCompare("border",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001820 {
anthony31f1bf72012-01-30 12:37:22 +00001821 CompositeOperator
anthony5f867ae2011-10-09 10:28:34 +00001822 compose;
1823
1824 const char*
anthony5f867ae2011-10-09 10:28:34 +00001825 value;
1826
1827 value=GetImageOption(image_info,"compose");
1828 if (value != (const char *) NULL)
1829 compose=(CompositeOperator) ParseCommandOption(
1830 MagickComposeOptions,MagickFalse,value);
1831 else
1832 compose=OverCompositeOp; /* use Over not image->compose */
1833
anthony31f1bf72012-01-30 12:37:22 +00001834 flags=ParsePageGeometry(image,arg1,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00001835 if ((flags & SigmaValue) == 0)
1836 geometry.height=geometry.width;
anthony31f1bf72012-01-30 12:37:22 +00001837 new_image=BorderImage(image,&geometry,compose,exception);
anthony805a2d42011-09-25 08:25:12 +00001838 break;
1839 }
anthonydcf510d2011-10-30 13:51:40 +00001840 if (LocaleCompare("brightness-contrast",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001841 {
1842 double
1843 brightness,
1844 contrast;
1845
1846 GeometryInfo
1847 geometry_info;
1848
1849 MagickStatusType
1850 flags;
1851
anthonyfd706f92012-01-19 04:22:02 +00001852 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001853 brightness=geometry_info.rho;
1854 contrast=0.0;
1855 if ((flags & SigmaValue) != 0)
1856 contrast=geometry_info.sigma;
anthony31f1bf72012-01-30 12:37:22 +00001857 (void) BrightnessContrastImage(image,brightness,contrast,
anthony805a2d42011-09-25 08:25:12 +00001858 exception);
anthony805a2d42011-09-25 08:25:12 +00001859 break;
1860 }
1861 break;
1862 }
1863 case 'c':
1864 {
anthonydcf510d2011-10-30 13:51:40 +00001865 if (LocaleCompare("cdl",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001866 {
1867 char
1868 *color_correction_collection;
1869
1870 /*
1871 Color correct with a color decision list.
1872 */
anthonyfd706f92012-01-19 04:22:02 +00001873 color_correction_collection=FileToString(arg1,~0,exception);
anthony805a2d42011-09-25 08:25:12 +00001874 if (color_correction_collection == (char *) NULL)
1875 break;
anthony31f1bf72012-01-30 12:37:22 +00001876 (void) ColorDecisionListImage(image,color_correction_collection,
anthony805a2d42011-09-25 08:25:12 +00001877 exception);
anthony805a2d42011-09-25 08:25:12 +00001878 break;
1879 }
anthonydcf510d2011-10-30 13:51:40 +00001880 if (LocaleCompare("channel",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001881 {
anthonyfd706f92012-01-19 04:22:02 +00001882 /* The "channel" setting has already been set
anthonyd1447672012-01-19 05:33:53 +00001883 FUTURE: This probably should be part of WandSettingOptionInfo()
anthonyfd706f92012-01-19 04:22:02 +00001884 or SyncImageSettings().
1885 */
anthony31f1bf72012-01-30 12:37:22 +00001886 SetPixelChannelMapMask(image,image_info->channel);
anthony805a2d42011-09-25 08:25:12 +00001887 break;
1888 }
cristy87c02f42012-02-24 00:19:10 +00001889 if (LocaleCompare("channel-extract",option) == 0)
1890 {
1891 puts("stand by...");
1892 break;
1893 }
1894 if (LocaleCompare("channel-swap",option) == 0)
1895 {
1896 puts("stand by...");
1897 break;
1898 }
anthonydcf510d2011-10-30 13:51:40 +00001899 if (LocaleCompare("charcoal",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001900 {
anthonyfd706f92012-01-19 04:22:02 +00001901 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00001902 if ((flags & SigmaValue) == 0)
1903 geometry_info.sigma=1.0;
1904 if ((flags & XiValue) == 0)
1905 geometry_info.xi=1.0;
anthony31f1bf72012-01-30 12:37:22 +00001906 new_image=CharcoalImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00001907 geometry_info.sigma,geometry_info.xi,exception);
1908 break;
1909 }
anthonydcf510d2011-10-30 13:51:40 +00001910 if (LocaleCompare("chop",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001911 {
anthony31f1bf72012-01-30 12:37:22 +00001912 (void) ParseGravityGeometry(image,arg1,&geometry,exception);
1913 new_image=ChopImage(image,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00001914 break;
1915 }
anthonydcf510d2011-10-30 13:51:40 +00001916 if (LocaleCompare("clamp",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001917 {
anthony31f1bf72012-01-30 12:37:22 +00001918 (void) ClampImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00001919 break;
1920 }
anthony43f425d2012-02-26 12:58:58 +00001921 if (LocaleCompare("cli_wandp",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001922 {
anthonyfd706f92012-01-19 04:22:02 +00001923 if (plus_alt_op == MagickFalse)
anthony31f1bf72012-01-30 12:37:22 +00001924 (void) ClipImage(image,exception);
anthony43f425d2012-02-26 12:58:58 +00001925 else /* "+mask" remove the write mask */
anthony31f1bf72012-01-30 12:37:22 +00001926 (void) SetImageMask(image,(Image *) NULL,exception);
anthony805a2d42011-09-25 08:25:12 +00001927 break;
1928 }
anthony43f425d2012-02-26 12:58:58 +00001929 if (LocaleCompare("cli_wandp-mask",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001930 {
1931 CacheView
1932 *mask_view;
1933
1934 Image
1935 *mask_image;
1936
1937 register Quantum
1938 *restrict q;
1939
1940 register ssize_t
1941 x;
1942
1943 ssize_t
1944 y;
1945
anthonyfd706f92012-01-19 04:22:02 +00001946 if (plus_alt_op != MagickFalse)
anthony43f425d2012-02-26 12:58:58 +00001947 { /* "+cli_wandp-mask" Remove the write mask */
anthony31f1bf72012-01-30 12:37:22 +00001948 (void) SetImageMask(image,(Image *) NULL,exception);
anthony805a2d42011-09-25 08:25:12 +00001949 break;
1950 }
anthonyfd706f92012-01-19 04:22:02 +00001951 mask_image=GetImageCache(image_info,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00001952 if (mask_image == (Image *) NULL)
1953 break;
anthonyfd706f92012-01-19 04:22:02 +00001954 if (SetImageStorageClass(mask_image,DirectClass,exception)
1955 == MagickFalse)
anthony31f1bf72012-01-30 12:37:22 +00001956 break;
anthony43f425d2012-02-26 12:58:58 +00001957 /* Create a write mask from cli_wandp-mask image */
anthonyfd706f92012-01-19 04:22:02 +00001958 /* FUTURE: use Alpha operations instead and create a Grey Image */
anthony805a2d42011-09-25 08:25:12 +00001959 mask_view=AcquireCacheView(mask_image);
1960 for (y=0; y < (ssize_t) mask_image->rows; y++)
1961 {
1962 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1963 exception);
1964 if (q == (Quantum *) NULL)
1965 break;
1966 for (x=0; x < (ssize_t) mask_image->columns; x++)
1967 {
1968 if (mask_image->matte == MagickFalse)
1969 SetPixelAlpha(mask_image,GetPixelIntensity(mask_image,q),q);
1970 SetPixelRed(mask_image,GetPixelAlpha(mask_image,q),q);
1971 SetPixelGreen(mask_image,GetPixelAlpha(mask_image,q),q);
1972 SetPixelBlue(mask_image,GetPixelAlpha(mask_image,q),q);
1973 q+=GetPixelChannels(mask_image);
1974 }
1975 if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1976 break;
1977 }
anthonyfd706f92012-01-19 04:22:02 +00001978 /* clean up and set the write mask */
anthony805a2d42011-09-25 08:25:12 +00001979 mask_view=DestroyCacheView(mask_view);
1980 mask_image->matte=MagickTrue;
anthony31f1bf72012-01-30 12:37:22 +00001981 (void) SetImageMask(image,mask_image,exception);
anthony805a2d42011-09-25 08:25:12 +00001982 mask_image=DestroyImage(mask_image);
anthony805a2d42011-09-25 08:25:12 +00001983 break;
1984 }
anthony43f425d2012-02-26 12:58:58 +00001985 if (LocaleCompare("cli_wandp-path",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001986 {
anthony31f1bf72012-01-30 12:37:22 +00001987 (void) ClipImagePath(image,arg1,
anthonyfd706f92012-01-19 04:22:02 +00001988 (MagickBooleanType)(!(int)plus_alt_op),exception);
anthony805a2d42011-09-25 08:25:12 +00001989 break;
1990 }
anthonydcf510d2011-10-30 13:51:40 +00001991 if (LocaleCompare("colorize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001992 {
anthony31f1bf72012-01-30 12:37:22 +00001993 new_image=ColorizeImage(image,arg1,&draw_info->fill,exception);
anthony805a2d42011-09-25 08:25:12 +00001994 break;
1995 }
anthonydcf510d2011-10-30 13:51:40 +00001996 if (LocaleCompare("color-matrix",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00001997 {
1998 KernelInfo
1999 *kernel;
2000
anthonyfd706f92012-01-19 04:22:02 +00002001 kernel=AcquireKernelInfo(arg1);
anthony805a2d42011-09-25 08:25:12 +00002002 if (kernel == (KernelInfo *) NULL)
2003 break;
anthony31f1bf72012-01-30 12:37:22 +00002004 new_image=ColorMatrixImage(image,kernel,exception);
anthony805a2d42011-09-25 08:25:12 +00002005 kernel=DestroyKernelInfo(kernel);
2006 break;
2007 }
anthonydcf510d2011-10-30 13:51:40 +00002008 if (LocaleCompare("colors",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002009 {
anthonyfd706f92012-01-19 04:22:02 +00002010 /* Reduce the number of colors in the image.
2011 FUTURE: also provide 'plus version with image 'color counts'
2012 */
2013 quantize_info->number_colors=StringToUnsignedLong(arg1);
anthony805a2d42011-09-25 08:25:12 +00002014 if (quantize_info->number_colors == 0)
2015 break;
anthony31f1bf72012-01-30 12:37:22 +00002016 if ((image->storage_class == DirectClass) ||
2017 image->colors > quantize_info->number_colors)
2018 (void) QuantizeImage(quantize_info,image,exception);
anthony805a2d42011-09-25 08:25:12 +00002019 else
anthony31f1bf72012-01-30 12:37:22 +00002020 (void) CompressImageColormap(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002021 break;
2022 }
anthonydcf510d2011-10-30 13:51:40 +00002023 if (LocaleCompare("colorspace",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002024 {
anthony31f1bf72012-01-30 12:37:22 +00002025 /* WARNING: this is both a image_info setting (already done)
2026 and a operator to change image colorspace.
2027
2028 FUTURE: default colorspace should be sRGB!
anthonyd2cdc862011-10-07 14:07:17 +00002029 Unless some type of 'linear colorspace' mode is set.
anthony31f1bf72012-01-30 12:37:22 +00002030
anthonyd2cdc862011-10-07 14:07:17 +00002031 Note that +colorspace sets "undefined" or no effect on
2032 new images, but forces images already in memory back to RGB!
anthony31f1bf72012-01-30 12:37:22 +00002033 That seems to be a little strange!
anthonyd2cdc862011-10-07 14:07:17 +00002034 */
anthony31f1bf72012-01-30 12:37:22 +00002035 (void) TransformImageColorspace(image,
2036 plus_alt_op ? RGBColorspace : image_info->colorspace,
anthony6613bf32011-10-15 07:24:44 +00002037 exception);
anthony805a2d42011-09-25 08:25:12 +00002038 break;
2039 }
anthonydcf510d2011-10-30 13:51:40 +00002040 if (LocaleCompare("contrast",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002041 {
anthony31f1bf72012-01-30 12:37:22 +00002042 (void) ContrastImage(image,
anthonyfd706f92012-01-19 04:22:02 +00002043 (MagickBooleanType)(!(int)plus_alt_op),exception);
anthony805a2d42011-09-25 08:25:12 +00002044 break;
2045 }
anthonydcf510d2011-10-30 13:51:40 +00002046 if (LocaleCompare("contrast-stretch",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002047 {
2048 double
2049 black_point,
2050 white_point;
2051
2052 MagickStatusType
2053 flags;
2054
anthonyfd706f92012-01-19 04:22:02 +00002055 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002056 black_point=geometry_info.rho;
2057 white_point=(flags & SigmaValue) != 0 ? geometry_info.sigma :
2058 black_point;
2059 if ((flags & PercentValue) != 0)
2060 {
anthony31f1bf72012-01-30 12:37:22 +00002061 black_point*=(double) image->columns*image->rows/100.0;
2062 white_point*=(double) image->columns*image->rows/100.0;
anthony805a2d42011-09-25 08:25:12 +00002063 }
anthony31f1bf72012-01-30 12:37:22 +00002064 white_point=(MagickRealType) image->columns*image->rows-
anthony805a2d42011-09-25 08:25:12 +00002065 white_point;
anthony31f1bf72012-01-30 12:37:22 +00002066 (void) ContrastStretchImage(image,black_point,white_point,
anthony805a2d42011-09-25 08:25:12 +00002067 exception);
anthony805a2d42011-09-25 08:25:12 +00002068 break;
2069 }
anthonydcf510d2011-10-30 13:51:40 +00002070 if (LocaleCompare("convolve",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002071 {
2072 KernelInfo
2073 *kernel_info;
2074
anthonyfd706f92012-01-19 04:22:02 +00002075 kernel_info=AcquireKernelInfo(arg1);
anthony805a2d42011-09-25 08:25:12 +00002076 if (kernel_info == (KernelInfo *) NULL)
2077 break;
anthony31f1bf72012-01-30 12:37:22 +00002078 kernel_info->bias=image->bias;
2079 new_image=ConvolveImage(image,kernel_info,exception);
anthony805a2d42011-09-25 08:25:12 +00002080 kernel_info=DestroyKernelInfo(kernel_info);
2081 break;
2082 }
anthonydcf510d2011-10-30 13:51:40 +00002083 if (LocaleCompare("crop",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002084 {
anthony31f1bf72012-01-30 12:37:22 +00002085 /* WARNING: This can generate multiple images! */
2086 new_image=CropImageToTiles(image,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002087 break;
2088 }
anthonydcf510d2011-10-30 13:51:40 +00002089 if (LocaleCompare("cycle",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002090 {
anthony31f1bf72012-01-30 12:37:22 +00002091 (void) CycleColormapImage(image,(ssize_t) StringToLong(arg1),
anthony805a2d42011-09-25 08:25:12 +00002092 exception);
2093 break;
2094 }
2095 break;
2096 }
2097 case 'd':
2098 {
anthonydcf510d2011-10-30 13:51:40 +00002099 if (LocaleCompare("decipher",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002100 {
2101 StringInfo
2102 *passkey;
2103
anthonyfd706f92012-01-19 04:22:02 +00002104 passkey=FileToStringInfo(arg1,~0,exception);
anthony805a2d42011-09-25 08:25:12 +00002105 if (passkey != (StringInfo *) NULL)
2106 {
anthony31f1bf72012-01-30 12:37:22 +00002107 (void) PasskeyDecipherImage(image,passkey,exception);
anthony805a2d42011-09-25 08:25:12 +00002108 passkey=DestroyStringInfo(passkey);
2109 }
2110 break;
2111 }
anthonydcf510d2011-10-30 13:51:40 +00002112 if (LocaleCompare("depth",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002113 {
anthonydcf510d2011-10-30 13:51:40 +00002114 /* The image_info->depth setting has already been set
2115 We just need to apply it to all images in current sequence
anthony31f1bf72012-01-30 12:37:22 +00002116
anthonydcf510d2011-10-30 13:51:40 +00002117 WARNING: Depth from 8 to 16 causes 'quantum rounding to images!
2118 That is it really is an operation, not a setting! Arrgghhh
anthony31f1bf72012-01-30 12:37:22 +00002119
anthonyfd706f92012-01-19 04:22:02 +00002120 FUTURE: this should not be an operator!!!
anthonydcf510d2011-10-30 13:51:40 +00002121 */
anthony31f1bf72012-01-30 12:37:22 +00002122 (void) SetImageDepth(image,image_info->depth,exception);
anthony805a2d42011-09-25 08:25:12 +00002123 break;
2124 }
anthonydcf510d2011-10-30 13:51:40 +00002125 if (LocaleCompare("deskew",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002126 {
2127 double
2128 threshold;
2129
anthonyfd706f92012-01-19 04:22:02 +00002130 if (plus_alt_op != MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00002131 threshold=40.0*QuantumRange/100.0;
2132 else
anthonyfd706f92012-01-19 04:22:02 +00002133 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
anthony31f1bf72012-01-30 12:37:22 +00002134 new_image=DeskewImage(image,threshold,exception);
anthony805a2d42011-09-25 08:25:12 +00002135 break;
2136 }
anthonydcf510d2011-10-30 13:51:40 +00002137 if (LocaleCompare("despeckle",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002138 {
anthony31f1bf72012-01-30 12:37:22 +00002139 new_image=DespeckleImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002140 break;
2141 }
anthonydcf510d2011-10-30 13:51:40 +00002142 if (LocaleCompare("distort",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002143 {
2144 char
2145 *args,
2146 token[MaxTextExtent];
2147
2148 const char
2149 *p;
2150
2151 DistortImageMethod
2152 method;
2153
2154 double
2155 *arguments;
2156
2157 register ssize_t
2158 x;
2159
2160 size_t
2161 number_arguments;
2162
anthony805a2d42011-09-25 08:25:12 +00002163 method=(DistortImageMethod) ParseCommandOption(MagickDistortOptions,
anthonyfd706f92012-01-19 04:22:02 +00002164 MagickFalse,arg1);
anthony80c37752012-01-16 01:03:11 +00002165 if (method == ResizeDistortion)
anthony805a2d42011-09-25 08:25:12 +00002166 {
anthony80c37752012-01-16 01:03:11 +00002167 double
2168 resize_args[2];
anthony805a2d42011-09-25 08:25:12 +00002169 /* Special Case - Argument is actually a resize geometry!
2170 ** Convert that to an appropriate distortion argument array.
anthonyfd706f92012-01-19 04:22:02 +00002171 ** FUTURE: make a separate special resize operator
anthony805a2d42011-09-25 08:25:12 +00002172 */
anthony31f1bf72012-01-30 12:37:22 +00002173 (void) ParseRegionGeometry(image,arg2,&geometry,
anthony80c37752012-01-16 01:03:11 +00002174 exception);
2175 resize_args[0]=(double) geometry.width;
2176 resize_args[1]=(double) geometry.height;
anthony31f1bf72012-01-30 12:37:22 +00002177 new_image=DistortImage(image,method,(size_t)2,
anthony80c37752012-01-16 01:03:11 +00002178 resize_args,MagickTrue,exception);
anthony805a2d42011-09-25 08:25:12 +00002179 break;
2180 }
anthonyfd706f92012-01-19 04:22:02 +00002181 /* handle percent arguments */
anthony31f1bf72012-01-30 12:37:22 +00002182 args=InterpretImageProperties(image_info,image,arg2,
anthony805a2d42011-09-25 08:25:12 +00002183 exception);
2184 if (args == (char *) NULL)
2185 break;
anthonyfd706f92012-01-19 04:22:02 +00002186 /* convert arguments into an array of doubles
2187 FUTURE: make this a separate function.
2188 Also make use of new 'sentinal' feature to avoid need for
2189 tokenization.
2190 */
anthony805a2d42011-09-25 08:25:12 +00002191 p=(char *) args;
2192 for (x=0; *p != '\0'; x++)
2193 {
2194 GetMagickToken(p,&p,token);
2195 if (*token == ',')
2196 GetMagickToken(p,&p,token);
2197 }
2198 number_arguments=(size_t) x;
2199 arguments=(double *) AcquireQuantumMemory(number_arguments,
2200 sizeof(*arguments));
2201 if (arguments == (double *) NULL)
2202 ThrowWandFatalException(ResourceLimitFatalError,
anthony31f1bf72012-01-30 12:37:22 +00002203 "MemoryAllocationFailed",image->filename);
anthony805a2d42011-09-25 08:25:12 +00002204 (void) ResetMagickMemory(arguments,0,number_arguments*
2205 sizeof(*arguments));
2206 p=(char *) args;
2207 for (x=0; (x < (ssize_t) number_arguments) && (*p != '\0'); x++)
2208 {
2209 GetMagickToken(p,&p,token);
2210 if (*token == ',')
2211 GetMagickToken(p,&p,token);
cristydbdd0e32011-11-04 23:29:40 +00002212 arguments[x]=StringToDouble(token,(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00002213 }
2214 args=DestroyString(args);
anthony31f1bf72012-01-30 12:37:22 +00002215 new_image=DistortImage(image,method,number_arguments,arguments,
anthonyfd706f92012-01-19 04:22:02 +00002216 plus_alt_op,exception);
anthony805a2d42011-09-25 08:25:12 +00002217 arguments=(double *) RelinquishMagickMemory(arguments);
2218 break;
2219 }
anthonydcf510d2011-10-30 13:51:40 +00002220 if (LocaleCompare("draw",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002221 {
anthonyfd706f92012-01-19 04:22:02 +00002222 (void) CloneString(&draw_info->primitive,arg1);
anthony31f1bf72012-01-30 12:37:22 +00002223 (void) DrawImage(image,draw_info,exception);
anthonyfd706f92012-01-19 04:22:02 +00002224 (void) CloneString(&draw_info->primitive,(char *)NULL);
anthony805a2d42011-09-25 08:25:12 +00002225 break;
2226 }
2227 break;
2228 }
2229 case 'e':
2230 {
anthonydcf510d2011-10-30 13:51:40 +00002231 if (LocaleCompare("edge",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002232 {
anthonyfd706f92012-01-19 04:22:02 +00002233 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002234 if ((flags & SigmaValue) == 0)
2235 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00002236 new_image=EdgeImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00002237 geometry_info.sigma,exception);
2238 break;
2239 }
anthonydcf510d2011-10-30 13:51:40 +00002240 if (LocaleCompare("emboss",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002241 {
anthonyfd706f92012-01-19 04:22:02 +00002242 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002243 if ((flags & SigmaValue) == 0)
2244 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00002245 new_image=EmbossImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00002246 geometry_info.sigma,exception);
2247 break;
2248 }
anthonydcf510d2011-10-30 13:51:40 +00002249 if (LocaleCompare("encipher",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002250 {
2251 StringInfo
2252 *passkey;
2253
anthonyfd706f92012-01-19 04:22:02 +00002254 passkey=FileToStringInfo(arg1,~0,exception);
anthony805a2d42011-09-25 08:25:12 +00002255 if (passkey != (StringInfo *) NULL)
2256 {
anthony31f1bf72012-01-30 12:37:22 +00002257 (void) PasskeyEncipherImage(image,passkey,exception);
anthony805a2d42011-09-25 08:25:12 +00002258 passkey=DestroyStringInfo(passkey);
2259 }
2260 break;
2261 }
anthonydcf510d2011-10-30 13:51:40 +00002262 if (LocaleCompare("enhance",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002263 {
anthony31f1bf72012-01-30 12:37:22 +00002264 new_image=EnhanceImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002265 break;
2266 }
anthonydcf510d2011-10-30 13:51:40 +00002267 if (LocaleCompare("equalize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002268 {
anthony31f1bf72012-01-30 12:37:22 +00002269 (void) EqualizeImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002270 break;
2271 }
anthonydcf510d2011-10-30 13:51:40 +00002272 if (LocaleCompare("evaluate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002273 {
2274 double
2275 constant;
2276
2277 MagickEvaluateOperator
2278 op;
2279
anthony805a2d42011-09-25 08:25:12 +00002280 op=(MagickEvaluateOperator) ParseCommandOption(
anthonyfd706f92012-01-19 04:22:02 +00002281 MagickEvaluateOptions,MagickFalse,arg1);
2282 constant=StringToDoubleInterval(arg2,(double) QuantumRange+1.0);
anthony31f1bf72012-01-30 12:37:22 +00002283 (void) EvaluateImage(image,op,constant,exception);
anthony805a2d42011-09-25 08:25:12 +00002284 break;
2285 }
anthonydcf510d2011-10-30 13:51:40 +00002286 if (LocaleCompare("extent",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002287 {
anthony31f1bf72012-01-30 12:37:22 +00002288 flags=ParseGravityGeometry(image,arg1,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00002289 if (geometry.width == 0)
anthony31f1bf72012-01-30 12:37:22 +00002290 geometry.width=image->columns;
anthony805a2d42011-09-25 08:25:12 +00002291 if (geometry.height == 0)
anthony31f1bf72012-01-30 12:37:22 +00002292 geometry.height=image->rows;
2293 new_image=ExtentImage(image,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00002294 break;
2295 }
2296 break;
2297 }
2298 case 'f':
2299 {
anthonydcf510d2011-10-30 13:51:40 +00002300 if (LocaleCompare("features",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002301 {
anthony31f1bf72012-01-30 12:37:22 +00002302 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
2303 if (plus_alt_op != MagickFalse)
2304 {
2305 (void) DeleteImageArtifact(image,"identify:features");
2306 break;
2307 }
2308 (void) SetImageArtifact(image,"identify:features","true");
2309 (void) SetImageArtifact(image,"verbose","true");
anthony805a2d42011-09-25 08:25:12 +00002310 break;
2311 }
anthonydcf510d2011-10-30 13:51:40 +00002312 if (LocaleCompare("flip",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002313 {
anthony31f1bf72012-01-30 12:37:22 +00002314 new_image=FlipImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002315 break;
2316 }
anthonydcf510d2011-10-30 13:51:40 +00002317 if (LocaleCompare("flop",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002318 {
anthony31f1bf72012-01-30 12:37:22 +00002319 new_image=FlopImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002320 break;
2321 }
anthonydcf510d2011-10-30 13:51:40 +00002322 if (LocaleCompare("floodfill",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002323 {
2324 PixelInfo
2325 target;
2326
anthony31f1bf72012-01-30 12:37:22 +00002327 (void) ParsePageGeometry(image,arg1,&geometry,exception);
anthonyfd706f92012-01-19 04:22:02 +00002328 (void) QueryColorCompliance(arg2,AllCompliance,&target,exception);
anthony31f1bf72012-01-30 12:37:22 +00002329 (void) FloodfillPaintImage(image,draw_info,&target,geometry.x,
anthonyfd706f92012-01-19 04:22:02 +00002330 geometry.y,plus_alt_op,exception);
anthony805a2d42011-09-25 08:25:12 +00002331 break;
2332 }
anthonydcf510d2011-10-30 13:51:40 +00002333 if (LocaleCompare("frame",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002334 {
2335 FrameInfo
2336 frame_info;
2337
anthony31f1bf72012-01-30 12:37:22 +00002338 CompositeOperator
anthonyfd706f92012-01-19 04:22:02 +00002339 compose;
2340
2341 const char*
2342 value;
2343
2344 value=GetImageOption(image_info,"compose");
2345 if (value != (const char *) NULL)
2346 compose=(CompositeOperator) ParseCommandOption(
2347 MagickComposeOptions,MagickFalse,value);
2348 else
2349 compose=OverCompositeOp; /* use Over not image->compose */
2350
anthony31f1bf72012-01-30 12:37:22 +00002351 flags=ParsePageGeometry(image,arg1,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00002352 frame_info.width=geometry.width;
2353 frame_info.height=geometry.height;
2354 if ((flags & HeightValue) == 0)
2355 frame_info.height=geometry.width;
2356 frame_info.outer_bevel=geometry.x;
2357 frame_info.inner_bevel=geometry.y;
2358 frame_info.x=(ssize_t) frame_info.width;
2359 frame_info.y=(ssize_t) frame_info.height;
anthony31f1bf72012-01-30 12:37:22 +00002360 frame_info.width=image->columns+2*frame_info.width;
2361 frame_info.height=image->rows+2*frame_info.height;
2362 new_image=FrameImage(image,&frame_info,compose,exception);
anthony805a2d42011-09-25 08:25:12 +00002363 break;
2364 }
anthonydcf510d2011-10-30 13:51:40 +00002365 if (LocaleCompare("function",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002366 {
2367 char
2368 *arguments,
2369 token[MaxTextExtent];
2370
2371 const char
2372 *p;
2373
2374 double
2375 *parameters;
2376
2377 MagickFunction
2378 function;
2379
2380 register ssize_t
2381 x;
2382
2383 size_t
2384 number_parameters;
2385
cristy947cb4c2011-10-20 18:41:46 +00002386 /*
2387 Function Modify Image Values
anthonyfd706f92012-01-19 04:22:02 +00002388 FUTURE: code should be almost a duplicate of that is "distort"
cristy947cb4c2011-10-20 18:41:46 +00002389 */
anthony805a2d42011-09-25 08:25:12 +00002390 function=(MagickFunction) ParseCommandOption(MagickFunctionOptions,
anthonyfd706f92012-01-19 04:22:02 +00002391 MagickFalse,arg1);
anthony31f1bf72012-01-30 12:37:22 +00002392 arguments=InterpretImageProperties(image_info,image,arg2,
anthony805a2d42011-09-25 08:25:12 +00002393 exception);
2394 if (arguments == (char *) NULL)
2395 break;
2396 p=(char *) arguments;
2397 for (x=0; *p != '\0'; x++)
2398 {
2399 GetMagickToken(p,&p,token);
2400 if (*token == ',')
2401 GetMagickToken(p,&p,token);
2402 }
2403 number_parameters=(size_t) x;
2404 parameters=(double *) AcquireQuantumMemory(number_parameters,
2405 sizeof(*parameters));
2406 if (parameters == (double *) NULL)
2407 ThrowWandFatalException(ResourceLimitFatalError,
anthony31f1bf72012-01-30 12:37:22 +00002408 "MemoryAllocationFailed",image->filename);
anthony805a2d42011-09-25 08:25:12 +00002409 (void) ResetMagickMemory(parameters,0,number_parameters*
2410 sizeof(*parameters));
2411 p=(char *) arguments;
2412 for (x=0; (x < (ssize_t) number_parameters) && (*p != '\0'); x++)
2413 {
2414 GetMagickToken(p,&p,token);
2415 if (*token == ',')
2416 GetMagickToken(p,&p,token);
cristydbdd0e32011-11-04 23:29:40 +00002417 parameters[x]=StringToDouble(token,(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00002418 }
2419 arguments=DestroyString(arguments);
anthony31f1bf72012-01-30 12:37:22 +00002420 (void) FunctionImage(image,function,number_parameters,parameters,
anthony805a2d42011-09-25 08:25:12 +00002421 exception);
2422 parameters=(double *) RelinquishMagickMemory(parameters);
2423 break;
2424 }
2425 break;
2426 }
2427 case 'g':
2428 {
anthonydcf510d2011-10-30 13:51:40 +00002429 if (LocaleCompare("gamma",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002430 {
anthony31f1bf72012-01-30 12:37:22 +00002431 if (plus_alt_op != MagickFalse)
2432 image->gamma=StringToDouble(arg1,(char **) NULL);
anthony805a2d42011-09-25 08:25:12 +00002433 else
anthony31f1bf72012-01-30 12:37:22 +00002434 (void) GammaImage(image,StringToDouble(arg1,(char **) NULL),
anthonyfd706f92012-01-19 04:22:02 +00002435 exception);
anthony805a2d42011-09-25 08:25:12 +00002436 break;
2437 }
anthonydcf510d2011-10-30 13:51:40 +00002438 if ((LocaleCompare("gaussian-blur",option) == 0) ||
2439 (LocaleCompare("gaussian",option) == 0))
anthony805a2d42011-09-25 08:25:12 +00002440 {
anthonyfd706f92012-01-19 04:22:02 +00002441 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002442 if ((flags & SigmaValue) == 0)
2443 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00002444 new_image=GaussianBlurImage(image,geometry_info.rho,
cristyd89705a2012-01-20 02:52:24 +00002445 geometry_info.sigma,exception);
anthony805a2d42011-09-25 08:25:12 +00002446 break;
2447 }
anthonydcf510d2011-10-30 13:51:40 +00002448 if (LocaleCompare("geometry",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002449 {
anthonyfd706f92012-01-19 04:22:02 +00002450 /*
anthony31f1bf72012-01-30 12:37:22 +00002451 Record Image offset for composition. (A Setting)
2452 Resize last image. (ListOperator)
2453 FUTURE: Why if no 'offset' does this resize ALL images?
2454 Also why is the setting recorded in the IMAGE non-sense!
anthonyfd706f92012-01-19 04:22:02 +00002455 */
anthony31f1bf72012-01-30 12:37:22 +00002456 if (plus_alt_op != MagickFalse)
anthonyfd706f92012-01-19 04:22:02 +00002457 { /* remove the previous composition geometry offset! */
anthony31f1bf72012-01-30 12:37:22 +00002458 if (image->geometry != (char *) NULL)
2459 image->geometry=DestroyString(image->geometry);
anthony805a2d42011-09-25 08:25:12 +00002460 break;
2461 }
anthony31f1bf72012-01-30 12:37:22 +00002462 flags=ParseRegionGeometry(image,arg1,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00002463 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
anthony31f1bf72012-01-30 12:37:22 +00002464 (void) CloneString(&image->geometry,arg1);
anthony805a2d42011-09-25 08:25:12 +00002465 else
anthony31f1bf72012-01-30 12:37:22 +00002466 new_image=ResizeImage(image,geometry.width,geometry.height,
2467 image->filter,image->blur,exception);
anthony805a2d42011-09-25 08:25:12 +00002468 break;
2469 }
anthony805a2d42011-09-25 08:25:12 +00002470 break;
2471 }
2472 case 'h':
2473 {
anthonydcf510d2011-10-30 13:51:40 +00002474 if (LocaleCompare("highlight-color",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002475 {
anthony31f1bf72012-01-30 12:37:22 +00002476 (void) SetImageArtifact(image,option,arg1);
anthony805a2d42011-09-25 08:25:12 +00002477 break;
2478 }
2479 break;
2480 }
2481 case 'i':
2482 {
anthonydcf510d2011-10-30 13:51:40 +00002483 if (LocaleCompare("identify",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002484 {
anthony31f1bf72012-01-30 12:37:22 +00002485 const char
2486 *format,
anthony805a2d42011-09-25 08:25:12 +00002487 *text;
2488
anthony31f1bf72012-01-30 12:37:22 +00002489 format=GetImageOption(image_info,"format");
anthony805a2d42011-09-25 08:25:12 +00002490 if (format == (char *) NULL)
2491 {
anthony31f1bf72012-01-30 12:37:22 +00002492 (void) IdentifyImage(image,stdout,image_info->verbose,
anthony805a2d42011-09-25 08:25:12 +00002493 exception);
2494 break;
2495 }
anthony31f1bf72012-01-30 12:37:22 +00002496 text=InterpretImageProperties(image_info,image,format,exception);
anthony805a2d42011-09-25 08:25:12 +00002497 if (text == (char *) NULL)
2498 break;
2499 (void) fputs(text,stdout);
2500 (void) fputc('\n',stdout);
anthony31f1bf72012-01-30 12:37:22 +00002501 text=DestroyString((char *)text);
anthony805a2d42011-09-25 08:25:12 +00002502 break;
2503 }
anthonydcf510d2011-10-30 13:51:40 +00002504 if (LocaleCompare("implode",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002505 {
anthonyfd706f92012-01-19 04:22:02 +00002506 (void) ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00002507 new_image=ImplodeImage(image,geometry_info.rho,
2508 image->interpolate,exception);
anthony805a2d42011-09-25 08:25:12 +00002509 break;
2510 }
anthonyfd706f92012-01-19 04:22:02 +00002511 if (LocaleCompare("interpolative-resize",option) == 0)
cristy947cb4c2011-10-20 18:41:46 +00002512 {
anthony31f1bf72012-01-30 12:37:22 +00002513 (void) ParseRegionGeometry(image,arg1,&geometry,exception);
2514 new_image=InterpolativeResizeImage(image,geometry.width,
2515 geometry.height,image->interpolate,exception);
cristy947cb4c2011-10-20 18:41:46 +00002516 break;
2517 }
anthony805a2d42011-09-25 08:25:12 +00002518 break;
2519 }
2520 case 'l':
2521 {
anthonydcf510d2011-10-30 13:51:40 +00002522 if (LocaleCompare("lat",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002523 {
anthonyfd706f92012-01-19 04:22:02 +00002524 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002525 if ((flags & PercentValue) != 0)
2526 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
anthony31f1bf72012-01-30 12:37:22 +00002527 new_image=AdaptiveThresholdImage(image,(size_t) geometry_info.rho,
2528 (size_t) geometry_info.sigma,(double) geometry_info.xi,
2529 exception);
anthony805a2d42011-09-25 08:25:12 +00002530 break;
2531 }
anthonydcf510d2011-10-30 13:51:40 +00002532 if (LocaleCompare("level",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002533 {
2534 MagickRealType
2535 black_point,
2536 gamma,
2537 white_point;
2538
2539 MagickStatusType
2540 flags;
2541
anthonyfd706f92012-01-19 04:22:02 +00002542 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002543 black_point=geometry_info.rho;
2544 white_point=(MagickRealType) QuantumRange;
2545 if ((flags & SigmaValue) != 0)
2546 white_point=geometry_info.sigma;
2547 gamma=1.0;
2548 if ((flags & XiValue) != 0)
2549 gamma=geometry_info.xi;
2550 if ((flags & PercentValue) != 0)
2551 {
2552 black_point*=(MagickRealType) (QuantumRange/100.0);
2553 white_point*=(MagickRealType) (QuantumRange/100.0);
2554 }
2555 if ((flags & SigmaValue) == 0)
2556 white_point=(MagickRealType) QuantumRange-black_point;
anthony31f1bf72012-01-30 12:37:22 +00002557 if (plus_alt_op || ((flags & AspectValue) != 0))
2558 (void) LevelizeImage(image,black_point,white_point,gamma,
anthony805a2d42011-09-25 08:25:12 +00002559 exception);
2560 else
anthony31f1bf72012-01-30 12:37:22 +00002561 (void) LevelImage(image,black_point,white_point,gamma,
anthony805a2d42011-09-25 08:25:12 +00002562 exception);
anthony805a2d42011-09-25 08:25:12 +00002563 break;
2564 }
anthonydcf510d2011-10-30 13:51:40 +00002565 if (LocaleCompare("level-colors",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002566 {
2567 char
2568 token[MaxTextExtent];
2569
2570 const char
2571 *p;
2572
2573 PixelInfo
2574 black_point,
2575 white_point;
2576
anthonyfd706f92012-01-19 04:22:02 +00002577 p=(const char *) arg1;
anthony805a2d42011-09-25 08:25:12 +00002578 GetMagickToken(p,&p,token); /* get black point color */
2579 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
cristy269c9412011-10-13 23:41:15 +00002580 (void) QueryColorCompliance(token,AllCompliance,
anthonya89dd172011-10-04 13:29:35 +00002581 &black_point,exception);
anthony805a2d42011-09-25 08:25:12 +00002582 else
cristy269c9412011-10-13 23:41:15 +00002583 (void) QueryColorCompliance("#000000",AllCompliance,
anthonya89dd172011-10-04 13:29:35 +00002584 &black_point,exception);
anthony805a2d42011-09-25 08:25:12 +00002585 if (isalpha((int) token[0]) || (token[0] == '#'))
2586 GetMagickToken(p,&p,token);
2587 if (*token == '\0')
2588 white_point=black_point; /* set everything to that color */
2589 else
2590 {
2591 if ((isalpha((int) *token) == 0) && ((*token == '#') == 0))
2592 GetMagickToken(p,&p,token); /* Get white point color. */
2593 if ((isalpha((int) *token) != 0) || ((*token == '#') != 0))
cristy269c9412011-10-13 23:41:15 +00002594 (void) QueryColorCompliance(token,AllCompliance,
anthonya89dd172011-10-04 13:29:35 +00002595 &white_point,exception);
anthony805a2d42011-09-25 08:25:12 +00002596 else
cristy269c9412011-10-13 23:41:15 +00002597 (void) QueryColorCompliance("#ffffff",AllCompliance,
anthonya89dd172011-10-04 13:29:35 +00002598 &white_point,exception);
anthony805a2d42011-09-25 08:25:12 +00002599 }
anthony31f1bf72012-01-30 12:37:22 +00002600 (void) LevelImageColors(image,&black_point,&white_point,
2601 plus_alt_op,exception);
anthony805a2d42011-09-25 08:25:12 +00002602 break;
2603 }
anthonydcf510d2011-10-30 13:51:40 +00002604 if (LocaleCompare("linear-stretch",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002605 {
2606 double
2607 black_point,
2608 white_point;
2609
2610 MagickStatusType
2611 flags;
2612
anthonyfd706f92012-01-19 04:22:02 +00002613 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002614 black_point=geometry_info.rho;
anthony31f1bf72012-01-30 12:37:22 +00002615 white_point=(MagickRealType) image->columns*image->rows;
anthony805a2d42011-09-25 08:25:12 +00002616 if ((flags & SigmaValue) != 0)
2617 white_point=geometry_info.sigma;
2618 if ((flags & PercentValue) != 0)
2619 {
anthony31f1bf72012-01-30 12:37:22 +00002620 black_point*=(double) image->columns*image->rows/100.0;
2621 white_point*=(double) image->columns*image->rows/100.0;
anthony805a2d42011-09-25 08:25:12 +00002622 }
2623 if ((flags & SigmaValue) == 0)
anthony31f1bf72012-01-30 12:37:22 +00002624 white_point=(MagickRealType) image->columns*image->rows-
anthony805a2d42011-09-25 08:25:12 +00002625 black_point;
anthony31f1bf72012-01-30 12:37:22 +00002626 (void) LinearStretchImage(image,black_point,white_point,exception);
anthony805a2d42011-09-25 08:25:12 +00002627 break;
2628 }
anthonydcf510d2011-10-30 13:51:40 +00002629 if (LocaleCompare("liquid-rescale",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002630 {
anthony31f1bf72012-01-30 12:37:22 +00002631 flags=ParseRegionGeometry(image,arg1,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00002632 if ((flags & XValue) == 0)
2633 geometry.x=1;
2634 if ((flags & YValue) == 0)
2635 geometry.y=0;
anthony31f1bf72012-01-30 12:37:22 +00002636 new_image=LiquidRescaleImage(image,geometry.width,
anthony805a2d42011-09-25 08:25:12 +00002637 geometry.height,1.0*geometry.x,1.0*geometry.y,exception);
2638 break;
2639 }
anthonydcf510d2011-10-30 13:51:40 +00002640 if (LocaleCompare("lowlight-color",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002641 {
anthony31f1bf72012-01-30 12:37:22 +00002642 (void) SetImageArtifact(image,option,arg1);
anthony805a2d42011-09-25 08:25:12 +00002643 break;
2644 }
2645 break;
2646 }
2647 case 'm':
2648 {
anthonydcf510d2011-10-30 13:51:40 +00002649 if (LocaleCompare("map",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002650 {
2651 Image
2652 *remap_image;
2653
anthony31f1bf72012-01-30 12:37:22 +00002654 /* DEPRECIATED use -remap */
anthonyfd706f92012-01-19 04:22:02 +00002655 remap_image=GetImageCache(image_info,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002656 if (remap_image == (Image *) NULL)
2657 break;
anthony31f1bf72012-01-30 12:37:22 +00002658 (void) RemapImage(quantize_info,image,remap_image,exception);
anthony805a2d42011-09-25 08:25:12 +00002659 remap_image=DestroyImage(remap_image);
2660 break;
2661 }
anthonydcf510d2011-10-30 13:51:40 +00002662 if (LocaleCompare("mask",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002663 {
2664 Image
2665 *mask;
2666
anthony31f1bf72012-01-30 12:37:22 +00002667 if (plus_alt_op != MagickFalse)
2668 { /* Remove a mask. */
2669 (void) SetImageMask(image,(Image *) NULL,exception);
anthony805a2d42011-09-25 08:25:12 +00002670 break;
2671 }
anthony31f1bf72012-01-30 12:37:22 +00002672 /* Set the image mask. */
anthonyfd706f92012-01-19 04:22:02 +00002673 mask=GetImageCache(image_info,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002674 if (mask == (Image *) NULL)
2675 break;
anthony31f1bf72012-01-30 12:37:22 +00002676 (void) SetImageMask(image,mask,exception);
anthony805a2d42011-09-25 08:25:12 +00002677 mask=DestroyImage(mask);
2678 break;
2679 }
anthonydcf510d2011-10-30 13:51:40 +00002680 if (LocaleCompare("matte",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002681 {
anthony31f1bf72012-01-30 12:37:22 +00002682 /* DEPRECIATED */
2683 (void) SetImageAlphaChannel(image,plus_alt_op ?
2684 DeactivateAlphaChannel:SetAlphaChannel ,exception);
anthony805a2d42011-09-25 08:25:12 +00002685 break;
2686 }
anthonydcf510d2011-10-30 13:51:40 +00002687 if (LocaleCompare("mode",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002688 {
anthonyfd706f92012-01-19 04:22:02 +00002689 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002690 if ((flags & SigmaValue) == 0)
2691 geometry_info.sigma=geometry_info.rho;
anthony31f1bf72012-01-30 12:37:22 +00002692 new_image=StatisticImage(image,ModeStatistic,(size_t)
anthony805a2d42011-09-25 08:25:12 +00002693 geometry_info.rho,(size_t) geometry_info.sigma,exception);
2694 break;
2695 }
anthonydcf510d2011-10-30 13:51:40 +00002696 if (LocaleCompare("modulate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002697 {
anthony31f1bf72012-01-30 12:37:22 +00002698 (void) ModulateImage(image,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002699 break;
2700 }
anthonydcf510d2011-10-30 13:51:40 +00002701 if (LocaleCompare("monitor",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002702 {
anthony31f1bf72012-01-30 12:37:22 +00002703 (void) SetImageProgressMonitor(image, plus_alt_op?
2704 (MagickProgressMonitor) NULL:MonitorProgress,(void *) NULL);
anthony805a2d42011-09-25 08:25:12 +00002705 break;
2706 }
anthonydcf510d2011-10-30 13:51:40 +00002707 if (LocaleCompare("monochrome",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002708 {
anthony31f1bf72012-01-30 12:37:22 +00002709 (void) SetImageType(image,BilevelType,exception);
anthony805a2d42011-09-25 08:25:12 +00002710 break;
2711 }
anthonydcf510d2011-10-30 13:51:40 +00002712 if (LocaleCompare("morphology",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002713 {
2714 char
2715 token[MaxTextExtent];
2716
2717 const char
2718 *p;
2719
2720 KernelInfo
2721 *kernel;
2722
2723 MorphologyMethod
2724 method;
2725
2726 ssize_t
2727 iterations;
2728
anthonyfd706f92012-01-19 04:22:02 +00002729 p=arg1;
anthony805a2d42011-09-25 08:25:12 +00002730 GetMagickToken(p,&p,token);
2731 method=(MorphologyMethod) ParseCommandOption(
2732 MagickMorphologyOptions,MagickFalse,token);
2733 iterations=1L;
2734 GetMagickToken(p,&p,token);
2735 if ((*p == ':') || (*p == ','))
2736 GetMagickToken(p,&p,token);
2737 if ((*p != '\0'))
2738 iterations=(ssize_t) StringToLong(p);
anthonyfd706f92012-01-19 04:22:02 +00002739 kernel=AcquireKernelInfo(arg2);
anthony805a2d42011-09-25 08:25:12 +00002740 if (kernel == (KernelInfo *) NULL)
2741 {
2742 (void) ThrowMagickException(exception,GetMagickModule(),
anthony31f1bf72012-01-30 12:37:22 +00002743 OptionError,"UnabletoParseKernel","morphology");
anthony805a2d42011-09-25 08:25:12 +00002744 break;
2745 }
anthony31f1bf72012-01-30 12:37:22 +00002746 new_image=MorphologyImage(image,method,iterations,kernel,exception);
anthony805a2d42011-09-25 08:25:12 +00002747 kernel=DestroyKernelInfo(kernel);
2748 break;
2749 }
anthonydcf510d2011-10-30 13:51:40 +00002750 if (LocaleCompare("motion-blur",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002751 {
anthonyfd706f92012-01-19 04:22:02 +00002752 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002753 if ((flags & SigmaValue) == 0)
2754 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00002755 new_image=MotionBlurImage(image,geometry_info.rho,
2756 geometry_info.sigma,geometry_info.xi,geometry_info.psi,
2757 exception);
anthony805a2d42011-09-25 08:25:12 +00002758 break;
2759 }
2760 break;
2761 }
2762 case 'n':
2763 {
anthonydcf510d2011-10-30 13:51:40 +00002764 if (LocaleCompare("negate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002765 {
anthony31f1bf72012-01-30 12:37:22 +00002766 (void) NegateImage(image, plus_alt_op, exception);
anthony805a2d42011-09-25 08:25:12 +00002767 break;
2768 }
anthonydcf510d2011-10-30 13:51:40 +00002769 if (LocaleCompare("noise",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002770 {
anthony31f1bf72012-01-30 12:37:22 +00002771 if (plus_alt_op == MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00002772 {
anthonyfd706f92012-01-19 04:22:02 +00002773 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002774 if ((flags & SigmaValue) == 0)
2775 geometry_info.sigma=geometry_info.rho;
anthony31f1bf72012-01-30 12:37:22 +00002776 new_image=StatisticImage(image,NonpeakStatistic,(size_t)
anthony805a2d42011-09-25 08:25:12 +00002777 geometry_info.rho,(size_t) geometry_info.sigma,exception);
2778 }
2779 else
2780 {
2781 NoiseType
2782 noise;
2783
anthony31f1bf72012-01-30 12:37:22 +00002784 double
2785 attenuate;
2786
2787 const char*
2788 value;
2789
anthony805a2d42011-09-25 08:25:12 +00002790 noise=(NoiseType) ParseCommandOption(MagickNoiseOptions,
anthony31f1bf72012-01-30 12:37:22 +00002791 MagickFalse,arg1),
2792
2793 value=GetImageOption(image_info,"attenuate");
2794 if (value != (const char *) NULL)
2795 attenuate=StringToDouble(value,(char **) NULL);
2796 else
2797 attenuate=1.0;
2798
2799 new_image=AddNoiseImage(image,noise,attenuate,exception);
anthony805a2d42011-09-25 08:25:12 +00002800 }
2801 break;
2802 }
anthonydcf510d2011-10-30 13:51:40 +00002803 if (LocaleCompare("normalize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002804 {
anthony31f1bf72012-01-30 12:37:22 +00002805 (void) NormalizeImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00002806 break;
2807 }
2808 break;
2809 }
2810 case 'o':
2811 {
anthonydcf510d2011-10-30 13:51:40 +00002812 if (LocaleCompare("opaque",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002813 {
2814 PixelInfo
2815 target;
2816
anthony31f1bf72012-01-30 12:37:22 +00002817 (void) QueryColorCompliance(arg1,AllCompliance,&target,exception);
2818 (void) OpaquePaintImage(image,&target,&draw_info->fill,plus_alt_op,
2819 exception);
anthony805a2d42011-09-25 08:25:12 +00002820 break;
2821 }
anthonydcf510d2011-10-30 13:51:40 +00002822 if (LocaleCompare("ordered-dither",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002823 {
anthony31f1bf72012-01-30 12:37:22 +00002824 (void) OrderedPosterizeImage(image,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002825 break;
2826 }
2827 break;
2828 }
2829 case 'p':
2830 {
anthonydcf510d2011-10-30 13:51:40 +00002831 if (LocaleCompare("paint",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002832 {
anthonyfd706f92012-01-19 04:22:02 +00002833 (void) ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00002834 new_image=OilPaintImage(image,geometry_info.rho,geometry_info.sigma,
2835 exception);
anthony805a2d42011-09-25 08:25:12 +00002836 break;
2837 }
anthonydcf510d2011-10-30 13:51:40 +00002838 if (LocaleCompare("polaroid",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002839 {
cristye9e3d382011-12-14 01:50:13 +00002840 const char
2841 *caption;
2842
anthony805a2d42011-09-25 08:25:12 +00002843 double
2844 angle;
2845
anthony31f1bf72012-01-30 12:37:22 +00002846 if (plus_alt_op != MagickFalse)
2847 {
2848 RandomInfo
2849 *random_info;
anthony805a2d42011-09-25 08:25:12 +00002850
anthony31f1bf72012-01-30 12:37:22 +00002851 random_info=AcquireRandomInfo();
2852 angle=22.5*(GetPseudoRandomValue(random_info)-0.5);
2853 random_info=DestroyRandomInfo(random_info);
2854 }
2855 else
anthony805a2d42011-09-25 08:25:12 +00002856 {
2857 SetGeometryInfo(&geometry_info);
anthonyfd706f92012-01-19 04:22:02 +00002858 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002859 angle=geometry_info.rho;
2860 }
anthony31f1bf72012-01-30 12:37:22 +00002861 caption=GetImageProperty(image,"caption",exception);
2862 new_image=PolaroidImage(image,draw_info,caption,angle,
2863 image->interpolate,exception);
anthony805a2d42011-09-25 08:25:12 +00002864 break;
2865 }
anthonydcf510d2011-10-30 13:51:40 +00002866 if (LocaleCompare("posterize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002867 {
anthony31f1bf72012-01-30 12:37:22 +00002868 (void) ParseGeometry(arg1,&geometry_info);
2869 (void) PosterizeImage(image,(size_t) geometry_info.rho,
2870 quantize_info->dither,exception);
anthony805a2d42011-09-25 08:25:12 +00002871 break;
2872 }
anthonydcf510d2011-10-30 13:51:40 +00002873 if (LocaleCompare("preview",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002874 {
2875 PreviewType
cristy947cb4c2011-10-20 18:41:46 +00002876 preview_type;
anthony170fce92011-10-20 11:50:23 +00002877
anthony31f1bf72012-01-30 12:37:22 +00002878 /* FUTURE: should be a 'Genesis' option?
2879 Option however is also in WandSettingOptionInfo()
cristy947cb4c2011-10-20 18:41:46 +00002880 */
anthony31f1bf72012-01-30 12:37:22 +00002881 preview_type=UndefinedPreview;
2882 if (plus_alt_op == MagickFalse)
2883 preview_type=(PreviewType) ParseCommandOption(MagickPreviewOptions,
2884 MagickFalse,arg1);
2885 new_image=PreviewImage(image,preview_type,exception);
anthony805a2d42011-09-25 08:25:12 +00002886 break;
2887 }
anthonydcf510d2011-10-30 13:51:40 +00002888 if (LocaleCompare("profile",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002889 {
2890 const char
2891 *name;
2892
2893 const StringInfo
2894 *profile;
2895
2896 Image
2897 *profile_image;
2898
2899 ImageInfo
2900 *profile_info;
2901
anthony31f1bf72012-01-30 12:37:22 +00002902 if (plus_alt_op != MagickFalse)
2903 { /* Remove a profile from the image. */
2904 (void) ProfileImage(image,arg1,(const unsigned char *)
cristy092d71c2011-10-14 18:01:29 +00002905 NULL,0,exception);
anthony805a2d42011-09-25 08:25:12 +00002906 break;
2907 }
anthony31f1bf72012-01-30 12:37:22 +00002908 /* Associate a profile with the image. */
anthony805a2d42011-09-25 08:25:12 +00002909 profile_info=CloneImageInfo(image_info);
anthony31f1bf72012-01-30 12:37:22 +00002910 profile=GetImageProfile(image,"iptc");
anthony805a2d42011-09-25 08:25:12 +00002911 if (profile != (StringInfo *) NULL)
2912 profile_info->profile=(void *) CloneStringInfo(profile);
anthonyfd706f92012-01-19 04:22:02 +00002913 profile_image=GetImageCache(profile_info,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002914 profile_info=DestroyImageInfo(profile_info);
2915 if (profile_image == (Image *) NULL)
2916 {
2917 StringInfo
2918 *profile;
2919
2920 profile_info=CloneImageInfo(image_info);
anthonyfd706f92012-01-19 04:22:02 +00002921 (void) CopyMagickString(profile_info->filename,arg1,
anthony805a2d42011-09-25 08:25:12 +00002922 MaxTextExtent);
2923 profile=FileToStringInfo(profile_info->filename,~0UL,exception);
2924 if (profile != (StringInfo *) NULL)
2925 {
anthony31f1bf72012-01-30 12:37:22 +00002926 (void) ProfileImage(image,profile_info->magick,
anthony805a2d42011-09-25 08:25:12 +00002927 GetStringInfoDatum(profile),(size_t)
cristy092d71c2011-10-14 18:01:29 +00002928 GetStringInfoLength(profile),exception);
anthony805a2d42011-09-25 08:25:12 +00002929 profile=DestroyStringInfo(profile);
2930 }
2931 profile_info=DestroyImageInfo(profile_info);
2932 break;
2933 }
2934 ResetImageProfileIterator(profile_image);
2935 name=GetNextImageProfile(profile_image);
2936 while (name != (const char *) NULL)
2937 {
2938 profile=GetImageProfile(profile_image,name);
2939 if (profile != (StringInfo *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00002940 (void) ProfileImage(image,name,GetStringInfoDatum(profile),
cristy092d71c2011-10-14 18:01:29 +00002941 (size_t) GetStringInfoLength(profile),exception);
anthony805a2d42011-09-25 08:25:12 +00002942 name=GetNextImageProfile(profile_image);
2943 }
2944 profile_image=DestroyImage(profile_image);
2945 break;
2946 }
2947 break;
2948 }
anthony805a2d42011-09-25 08:25:12 +00002949 case 'r':
2950 {
anthonydcf510d2011-10-30 13:51:40 +00002951 if (LocaleCompare("radial-blur",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002952 {
anthonyfd706f92012-01-19 04:22:02 +00002953 flags=ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00002954 new_image=RadialBlurImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00002955 geometry_info.sigma,exception);
2956 break;
2957 }
anthonydcf510d2011-10-30 13:51:40 +00002958 if (LocaleCompare("raise",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002959 {
anthony31f1bf72012-01-30 12:37:22 +00002960 flags=ParsePageGeometry(image,arg1,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00002961 if ((flags & SigmaValue) == 0)
2962 geometry.height=geometry.width;
anthony31f1bf72012-01-30 12:37:22 +00002963 (void) RaiseImage(image,&geometry,normal_op,exception);
anthony805a2d42011-09-25 08:25:12 +00002964 break;
2965 }
anthonydcf510d2011-10-30 13:51:40 +00002966 if (LocaleCompare("random-threshold",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002967 {
anthony31f1bf72012-01-30 12:37:22 +00002968 (void) RandomThresholdImage(image,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002969 break;
2970 }
anthonydcf510d2011-10-30 13:51:40 +00002971 if (LocaleCompare("remap",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002972 {
2973 Image
2974 *remap_image;
2975
anthonyfd706f92012-01-19 04:22:02 +00002976 remap_image=GetImageCache(image_info,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00002977 if (remap_image == (Image *) NULL)
2978 break;
anthony31f1bf72012-01-30 12:37:22 +00002979 (void) RemapImage(quantize_info,image,remap_image,exception);
anthony805a2d42011-09-25 08:25:12 +00002980 remap_image=DestroyImage(remap_image);
2981 break;
2982 }
anthonydcf510d2011-10-30 13:51:40 +00002983 if (LocaleCompare("repage",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002984 {
anthony31f1bf72012-01-30 12:37:22 +00002985 if (plus_alt_op == MagickFalse)
2986 (void) ResetImagePage(image,arg1);
2987 else
2988 (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
anthony805a2d42011-09-25 08:25:12 +00002989 break;
2990 }
anthonydcf510d2011-10-30 13:51:40 +00002991 if (LocaleCompare("resample",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00002992 {
anthony31f1bf72012-01-30 12:37:22 +00002993 /* FUTURE: remove blur arguemnt - no longer used */
anthonyfd706f92012-01-19 04:22:02 +00002994 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00002995 if ((flags & SigmaValue) == 0)
2996 geometry_info.sigma=geometry_info.rho;
anthony31f1bf72012-01-30 12:37:22 +00002997 new_image=ResampleImage(image,geometry_info.rho,
2998 geometry_info.sigma,image->filter,image->blur,exception);
anthony805a2d42011-09-25 08:25:12 +00002999 break;
3000 }
anthonydcf510d2011-10-30 13:51:40 +00003001 if (LocaleCompare("resize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003002 {
anthonyafbaed72011-10-26 12:05:04 +00003003 /* FUTURE: remove blur argument - no longer used */
anthony31f1bf72012-01-30 12:37:22 +00003004 (void) ParseRegionGeometry(image,arg1,&geometry,exception);
3005 new_image=ResizeImage(image,geometry.width,geometry.height,
3006 image->filter,image->blur,exception);
anthony805a2d42011-09-25 08:25:12 +00003007 break;
3008 }
anthonydcf510d2011-10-30 13:51:40 +00003009 if (LocaleCompare("roll",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003010 {
anthony31f1bf72012-01-30 12:37:22 +00003011 (void) ParsePageGeometry(image,arg1,&geometry,exception);
3012 new_image=RollImage(image,geometry.x,geometry.y,exception);
anthony805a2d42011-09-25 08:25:12 +00003013 break;
3014 }
anthonydcf510d2011-10-30 13:51:40 +00003015 if (LocaleCompare("rotate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003016 {
anthonyfd706f92012-01-19 04:22:02 +00003017 if (strchr(arg1,'>') != (char *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00003018 if (image->columns <= image->rows)
anthony805a2d42011-09-25 08:25:12 +00003019 break;
anthonyfd706f92012-01-19 04:22:02 +00003020 if (strchr(arg1,'<') != (char *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00003021 if (image->columns >= image->rows)
anthony805a2d42011-09-25 08:25:12 +00003022 break;
anthonyafbaed72011-10-26 12:05:04 +00003023
anthonyfd706f92012-01-19 04:22:02 +00003024 (void) ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00003025 new_image=RotateImage(image,geometry_info.rho,exception);
anthony805a2d42011-09-25 08:25:12 +00003026 break;
3027 }
3028 break;
3029 }
3030 case 's':
3031 {
anthonydcf510d2011-10-30 13:51:40 +00003032 if (LocaleCompare("sample",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003033 {
anthony31f1bf72012-01-30 12:37:22 +00003034 (void) ParseRegionGeometry(image,arg1,&geometry,exception);
3035 new_image=SampleImage(image,geometry.width,geometry.height,
anthony805a2d42011-09-25 08:25:12 +00003036 exception);
3037 break;
3038 }
anthonydcf510d2011-10-30 13:51:40 +00003039 if (LocaleCompare("scale",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003040 {
anthony31f1bf72012-01-30 12:37:22 +00003041 (void) ParseRegionGeometry(image,arg1,&geometry,exception);
3042 new_image=ScaleImage(image,geometry.width,geometry.height,
anthony805a2d42011-09-25 08:25:12 +00003043 exception);
3044 break;
3045 }
anthonydcf510d2011-10-30 13:51:40 +00003046 if (LocaleCompare("selective-blur",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003047 {
anthonyfd706f92012-01-19 04:22:02 +00003048 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003049 if ((flags & PercentValue) != 0)
3050 geometry_info.xi=(double) QuantumRange*geometry_info.xi/100.0;
anthony31f1bf72012-01-30 12:37:22 +00003051 new_image=SelectiveBlurImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00003052 geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3053 break;
3054 }
anthonydcf510d2011-10-30 13:51:40 +00003055 if (LocaleCompare("separate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003056 {
anthony31f1bf72012-01-30 12:37:22 +00003057 /* WARNING: This can generate multiple images! */
anthony43f425d2012-02-26 12:58:58 +00003058 /* FUTURE - this may be replaced by a "-channel" method */
anthony31f1bf72012-01-30 12:37:22 +00003059 new_image=SeparateImages(image,exception);
anthony805a2d42011-09-25 08:25:12 +00003060 break;
3061 }
anthonydcf510d2011-10-30 13:51:40 +00003062 if (LocaleCompare("sepia-tone",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003063 {
3064 double
3065 threshold;
3066
anthonyfd706f92012-01-19 04:22:02 +00003067 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
anthony31f1bf72012-01-30 12:37:22 +00003068 new_image=SepiaToneImage(image,threshold,exception);
anthony805a2d42011-09-25 08:25:12 +00003069 break;
3070 }
anthonydcf510d2011-10-30 13:51:40 +00003071 if (LocaleCompare("segment",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003072 {
anthonyfd706f92012-01-19 04:22:02 +00003073 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003074 if ((flags & SigmaValue) == 0)
3075 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00003076 (void) SegmentImage(image,image->colorspace,
anthony805a2d42011-09-25 08:25:12 +00003077 image_info->verbose,geometry_info.rho,geometry_info.sigma,
3078 exception);
3079 break;
3080 }
anthonydcf510d2011-10-30 13:51:40 +00003081 if (LocaleCompare("set",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003082 {
3083 char
3084 *value;
3085
anthony31f1bf72012-01-30 12:37:22 +00003086 if (plus_alt_op != MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00003087 {
anthonyfd706f92012-01-19 04:22:02 +00003088 if (LocaleNCompare(arg1,"registry:",9) == 0)
3089 (void) DeleteImageRegistry(arg1+9);
anthony805a2d42011-09-25 08:25:12 +00003090 else
anthony31f1bf72012-01-30 12:37:22 +00003091 if (LocaleNCompare(arg1,"option:",7) == 0)
anthony805a2d42011-09-25 08:25:12 +00003092 {
anthonyfd706f92012-01-19 04:22:02 +00003093 (void) DeleteImageOption(image_info,arg1+7);
anthony31f1bf72012-01-30 12:37:22 +00003094 (void) DeleteImageArtifact(image,arg1+7);
anthony805a2d42011-09-25 08:25:12 +00003095 }
3096 else
anthony31f1bf72012-01-30 12:37:22 +00003097 (void) DeleteImageProperty(image,arg1);
anthony805a2d42011-09-25 08:25:12 +00003098 break;
3099 }
anthony31f1bf72012-01-30 12:37:22 +00003100 value=InterpretImageProperties(image_info,image,arg2,
anthony805a2d42011-09-25 08:25:12 +00003101 exception);
3102 if (value == (char *) NULL)
3103 break;
anthonyfd706f92012-01-19 04:22:02 +00003104 if (LocaleNCompare(arg1,"registry:",9) == 0)
3105 (void) SetImageRegistry(StringRegistryType,arg1+9,value,
anthony805a2d42011-09-25 08:25:12 +00003106 exception);
3107 else
anthonyfd706f92012-01-19 04:22:02 +00003108 if (LocaleNCompare(arg1,"option:",7) == 0)
anthony805a2d42011-09-25 08:25:12 +00003109 {
anthonyfd706f92012-01-19 04:22:02 +00003110 (void) SetImageOption(image_info,arg1+7,value);
anthony31f1bf72012-01-30 12:37:22 +00003111 (void) SetImageArtifact(image,arg1+7,value);
anthony805a2d42011-09-25 08:25:12 +00003112 }
3113 else
anthony31f1bf72012-01-30 12:37:22 +00003114 (void) SetImageProperty(image,arg1,value,exception);
anthony805a2d42011-09-25 08:25:12 +00003115 value=DestroyString(value);
3116 break;
3117 }
anthonydcf510d2011-10-30 13:51:40 +00003118 if (LocaleCompare("shade",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003119 {
anthonyfd706f92012-01-19 04:22:02 +00003120 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003121 if ((flags & SigmaValue) == 0)
3122 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00003123 new_image=ShadeImage(image,normal_op,geometry_info.rho,
3124 geometry_info.sigma,exception);
anthony805a2d42011-09-25 08:25:12 +00003125 break;
3126 }
anthonydcf510d2011-10-30 13:51:40 +00003127 if (LocaleCompare("shadow",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003128 {
anthonyfd706f92012-01-19 04:22:02 +00003129 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003130 if ((flags & SigmaValue) == 0)
3131 geometry_info.sigma=1.0;
3132 if ((flags & XiValue) == 0)
3133 geometry_info.xi=4.0;
3134 if ((flags & PsiValue) == 0)
3135 geometry_info.psi=4.0;
anthony31f1bf72012-01-30 12:37:22 +00003136 new_image=ShadowImage(image,geometry_info.rho,
3137 geometry_info.sigma,image->bias,(ssize_t)
cristyeb6e6582011-12-09 09:14:23 +00003138 ceil(geometry_info.xi-0.5),(ssize_t) ceil(geometry_info.psi-0.5),
3139 exception);
anthony805a2d42011-09-25 08:25:12 +00003140 break;
3141 }
anthonydcf510d2011-10-30 13:51:40 +00003142 if (LocaleCompare("sharpen",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003143 {
anthonyfd706f92012-01-19 04:22:02 +00003144 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003145 if ((flags & SigmaValue) == 0)
3146 geometry_info.sigma=1.0;
3147 if ((flags & XiValue) == 0)
3148 geometry_info.xi=0.0;
anthony31f1bf72012-01-30 12:37:22 +00003149 new_image=SharpenImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00003150 geometry_info.sigma,geometry_info.xi,exception);
3151 break;
3152 }
anthonydcf510d2011-10-30 13:51:40 +00003153 if (LocaleCompare("shave",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003154 {
anthony31f1bf72012-01-30 12:37:22 +00003155 flags=ParsePageGeometry(image,arg1,&geometry,exception);
3156 new_image=ShaveImage(image,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00003157 break;
3158 }
anthonydcf510d2011-10-30 13:51:40 +00003159 if (LocaleCompare("shear",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003160 {
anthonyfd706f92012-01-19 04:22:02 +00003161 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003162 if ((flags & SigmaValue) == 0)
3163 geometry_info.sigma=geometry_info.rho;
anthony31f1bf72012-01-30 12:37:22 +00003164 new_image=ShearImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00003165 geometry_info.sigma,exception);
3166 break;
3167 }
anthonydcf510d2011-10-30 13:51:40 +00003168 if (LocaleCompare("sigmoidal-contrast",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003169 {
anthonyfd706f92012-01-19 04:22:02 +00003170 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003171 if ((flags & SigmaValue) == 0)
3172 geometry_info.sigma=(double) QuantumRange/2.0;
3173 if ((flags & PercentValue) != 0)
3174 geometry_info.sigma=(double) QuantumRange*geometry_info.sigma/
3175 100.0;
anthony31f1bf72012-01-30 12:37:22 +00003176 (void) SigmoidalContrastImage(image,normal_op,geometry_info.rho,
3177 geometry_info.sigma,
anthony805a2d42011-09-25 08:25:12 +00003178 exception);
3179 break;
3180 }
anthonydcf510d2011-10-30 13:51:40 +00003181 if (LocaleCompare("sketch",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003182 {
anthonyfd706f92012-01-19 04:22:02 +00003183 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003184 if ((flags & SigmaValue) == 0)
3185 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00003186 new_image=SketchImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00003187 geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3188 break;
3189 }
anthonydcf510d2011-10-30 13:51:40 +00003190 if (LocaleCompare("solarize",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003191 {
anthony31f1bf72012-01-30 12:37:22 +00003192 (void) SolarizeImage(image,StringToDoubleInterval(arg1,(double)
3193 QuantumRange+1.0),exception);
anthony805a2d42011-09-25 08:25:12 +00003194 break;
3195 }
anthonydcf510d2011-10-30 13:51:40 +00003196 if (LocaleCompare("sparse-color",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003197 {
3198 SparseColorMethod
3199 method;
3200
3201 char
3202 *arguments;
3203
anthony805a2d42011-09-25 08:25:12 +00003204 method=(SparseColorMethod) ParseCommandOption(
anthonyfd706f92012-01-19 04:22:02 +00003205 MagickSparseColorOptions,MagickFalse,arg1);
anthony31f1bf72012-01-30 12:37:22 +00003206 arguments=InterpretImageProperties(image_info,image,arg2,exception);
anthony805a2d42011-09-25 08:25:12 +00003207 if (arguments == (char *) NULL)
3208 break;
anthony31f1bf72012-01-30 12:37:22 +00003209 new_image=SparseColorOption(image,method,arguments,exception);
anthony805a2d42011-09-25 08:25:12 +00003210 arguments=DestroyString(arguments);
3211 break;
3212 }
anthonydcf510d2011-10-30 13:51:40 +00003213 if (LocaleCompare("splice",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003214 {
anthony31f1bf72012-01-30 12:37:22 +00003215 (void) ParseGravityGeometry(image,arg1,&geometry,exception);
3216 new_image=SpliceImage(image,&geometry,exception);
anthony805a2d42011-09-25 08:25:12 +00003217 break;
3218 }
anthonydcf510d2011-10-30 13:51:40 +00003219 if (LocaleCompare("spread",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003220 {
anthonyfd706f92012-01-19 04:22:02 +00003221 (void) ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00003222 new_image=SpreadImage(image,geometry_info.rho,image->interpolate,
3223 exception);
anthony805a2d42011-09-25 08:25:12 +00003224 break;
3225 }
anthonydcf510d2011-10-30 13:51:40 +00003226 if (LocaleCompare("statistic",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003227 {
3228 StatisticType
3229 type;
3230
anthony805a2d42011-09-25 08:25:12 +00003231 type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
anthonyfd706f92012-01-19 04:22:02 +00003232 MagickFalse,arg1);
3233 (void) ParseGeometry(arg2,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00003234 new_image=StatisticImage(image,type,(size_t) geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00003235 (size_t) geometry_info.sigma,exception);
3236 break;
3237 }
anthonydcf510d2011-10-30 13:51:40 +00003238 if (LocaleCompare("strip",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003239 {
anthony31f1bf72012-01-30 12:37:22 +00003240 (void) StripImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00003241 break;
3242 }
anthonydcf510d2011-10-30 13:51:40 +00003243 if (LocaleCompare("swirl",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003244 {
anthonyfd706f92012-01-19 04:22:02 +00003245 (void) ParseGeometry(arg1,&geometry_info);
anthony31f1bf72012-01-30 12:37:22 +00003246 new_image=SwirlImage(image,geometry_info.rho,
3247 image->interpolate,exception);
anthony805a2d42011-09-25 08:25:12 +00003248 break;
3249 }
3250 break;
3251 }
3252 case 't':
3253 {
anthonydcf510d2011-10-30 13:51:40 +00003254 if (LocaleCompare("threshold",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003255 {
3256 double
3257 threshold;
3258
anthony31f1bf72012-01-30 12:37:22 +00003259 if (plus_alt_op != MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00003260 threshold=(double) QuantumRange/2;
3261 else
anthonyfd706f92012-01-19 04:22:02 +00003262 threshold=StringToDoubleInterval(arg1,(double) QuantumRange+1.0);
anthony31f1bf72012-01-30 12:37:22 +00003263 (void) BilevelImage(image,threshold,exception);
anthony805a2d42011-09-25 08:25:12 +00003264 break;
3265 }
anthonydcf510d2011-10-30 13:51:40 +00003266 if (LocaleCompare("thumbnail",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003267 {
anthony31f1bf72012-01-30 12:37:22 +00003268 (void) ParseRegionGeometry(image,arg1,&geometry,exception);
3269 new_image=ThumbnailImage(image,geometry.width,geometry.height,
anthony805a2d42011-09-25 08:25:12 +00003270 exception);
3271 break;
3272 }
anthonydcf510d2011-10-30 13:51:40 +00003273 if (LocaleCompare("tint",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003274 {
anthony31f1bf72012-01-30 12:37:22 +00003275 new_image=TintImage(image,arg1,&draw_info->fill,exception);
anthony805a2d42011-09-25 08:25:12 +00003276 break;
3277 }
anthonydcf510d2011-10-30 13:51:40 +00003278 if (LocaleCompare("transform",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003279 {
anthonyfd706f92012-01-19 04:22:02 +00003280 /* DEPRECIATED */
anthony31f1bf72012-01-30 12:37:22 +00003281 new_image=AffineTransformImage(image,&draw_info->affine,
anthony805a2d42011-09-25 08:25:12 +00003282 exception);
3283 break;
3284 }
anthonydcf510d2011-10-30 13:51:40 +00003285 if (LocaleCompare("transparent",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003286 {
3287 PixelInfo
3288 target;
3289
anthony31f1bf72012-01-30 12:37:22 +00003290 (void) QueryColorCompliance(arg1,AllCompliance,&target,exception);
3291 (void) TransparentPaintImage(image,&target,(Quantum)
3292 TransparentAlpha,plus_alt_op,exception);
anthony805a2d42011-09-25 08:25:12 +00003293 break;
3294 }
anthonydcf510d2011-10-30 13:51:40 +00003295 if (LocaleCompare("transpose",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003296 {
anthony31f1bf72012-01-30 12:37:22 +00003297 new_image=TransposeImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00003298 break;
3299 }
anthonydcf510d2011-10-30 13:51:40 +00003300 if (LocaleCompare("transverse",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003301 {
anthony31f1bf72012-01-30 12:37:22 +00003302 new_image=TransverseImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00003303 break;
3304 }
anthonydcf510d2011-10-30 13:51:40 +00003305 if (LocaleCompare("trim",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003306 {
anthony31f1bf72012-01-30 12:37:22 +00003307 new_image=TrimImage(image,exception);
anthony805a2d42011-09-25 08:25:12 +00003308 break;
3309 }
anthonydcf510d2011-10-30 13:51:40 +00003310 if (LocaleCompare("type",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003311 {
anthonyab3a50c2011-10-27 11:48:57 +00003312 /* Note that "type" setting should have already been defined */
anthony31f1bf72012-01-30 12:37:22 +00003313 (void) SetImageType(image,image_info->type,exception);
anthony805a2d42011-09-25 08:25:12 +00003314 break;
3315 }
3316 break;
3317 }
3318 case 'u':
3319 {
anthonydcf510d2011-10-30 13:51:40 +00003320 if (LocaleCompare("unique",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003321 {
anthony31f1bf72012-01-30 12:37:22 +00003322 /* FUTURE: move to SyncImageSettings() and AcqireImage()??? */
3323 if (plus_alt_op != MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00003324 {
anthony31f1bf72012-01-30 12:37:22 +00003325 (void) DeleteImageArtifact(image,"identify:unique-colors");
anthony805a2d42011-09-25 08:25:12 +00003326 break;
3327 }
anthony31f1bf72012-01-30 12:37:22 +00003328 (void) SetImageArtifact(image,"identify:unique-colors","true");
3329 (void) SetImageArtifact(image,"verbose","true");
anthony805a2d42011-09-25 08:25:12 +00003330 break;
3331 }
anthonydcf510d2011-10-30 13:51:40 +00003332 if (LocaleCompare("unique-colors",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003333 {
anthony31f1bf72012-01-30 12:37:22 +00003334 new_image=UniqueImageColors(image,exception);
anthony805a2d42011-09-25 08:25:12 +00003335 break;
3336 }
anthonydcf510d2011-10-30 13:51:40 +00003337 if (LocaleCompare("unsharp",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003338 {
anthonyfd706f92012-01-19 04:22:02 +00003339 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003340 if ((flags & SigmaValue) == 0)
3341 geometry_info.sigma=1.0;
3342 if ((flags & XiValue) == 0)
3343 geometry_info.xi=1.0;
3344 if ((flags & PsiValue) == 0)
3345 geometry_info.psi=0.05;
anthony31f1bf72012-01-30 12:37:22 +00003346 new_image=UnsharpMaskImage(image,geometry_info.rho,
anthony805a2d42011-09-25 08:25:12 +00003347 geometry_info.sigma,geometry_info.xi,geometry_info.psi,exception);
3348 break;
3349 }
3350 break;
3351 }
3352 case 'v':
3353 {
anthonydcf510d2011-10-30 13:51:40 +00003354 if (LocaleCompare("verbose",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003355 {
anthony31f1bf72012-01-30 12:37:22 +00003356 /* FUTURE: move to SyncImageSettings() and AcqireImage()???
3357 three places! ImageArtifact ImageOption image_info->verbose
3358 Some how new images also get this artifact -- how???
3359 */
3360 (void) SetImageArtifact(image,option,
3361 (plus_alt_op != MagickFalse) ? "false" : "true" );
anthony805a2d42011-09-25 08:25:12 +00003362 break;
3363 }
anthonydcf510d2011-10-30 13:51:40 +00003364 if (LocaleCompare("vignette",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003365 {
anthonyfd706f92012-01-19 04:22:02 +00003366 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003367 if ((flags & SigmaValue) == 0)
3368 geometry_info.sigma=1.0;
3369 if ((flags & XiValue) == 0)
anthony31f1bf72012-01-30 12:37:22 +00003370 geometry_info.xi=0.1*image->columns;
anthony805a2d42011-09-25 08:25:12 +00003371 if ((flags & PsiValue) == 0)
anthony31f1bf72012-01-30 12:37:22 +00003372 geometry_info.psi=0.1*image->rows;
3373 new_image=VignetteImage(image,geometry_info.rho,geometry_info.sigma,
3374 image->bias,(ssize_t) ceil(geometry_info.xi-0.5),
3375 (ssize_t) ceil(geometry_info.psi-0.5),exception);
anthony805a2d42011-09-25 08:25:12 +00003376 break;
3377 }
anthony805a2d42011-09-25 08:25:12 +00003378 break;
3379 }
3380 case 'w':
3381 {
anthonydcf510d2011-10-30 13:51:40 +00003382 if (LocaleCompare("wave",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003383 {
anthonyfd706f92012-01-19 04:22:02 +00003384 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00003385 if ((flags & SigmaValue) == 0)
3386 geometry_info.sigma=1.0;
anthony31f1bf72012-01-30 12:37:22 +00003387 new_image=WaveImage(image,geometry_info.rho,geometry_info.sigma,
3388 image->interpolate,exception);
anthony805a2d42011-09-25 08:25:12 +00003389 break;
3390 }
anthonydcf510d2011-10-30 13:51:40 +00003391 if (LocaleCompare("white-threshold",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003392 {
anthony31f1bf72012-01-30 12:37:22 +00003393 (void) WhiteThresholdImage(image,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00003394 break;
3395 }
3396 break;
3397 }
3398 default:
3399 break;
3400 }
3401 /*
3402 Replace current image with any image that was generated
anthony31f1bf72012-01-30 12:37:22 +00003403 and set image point to last image (so image->next is correct)
anthony805a2d42011-09-25 08:25:12 +00003404 */
3405 if (new_image != (Image *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00003406 ReplaceImageInListReturnLast(&image,new_image);
anthony805a2d42011-09-25 08:25:12 +00003407
anthony31f1bf72012-01-30 12:37:22 +00003408 return;
anthonyfd706f92012-01-19 04:22:02 +00003409#undef image_info
3410#undef draw_info
3411#undef quantize_info
anthony31f1bf72012-01-30 12:37:22 +00003412#undef image
anthonyfd706f92012-01-19 04:22:02 +00003413#undef exception
anthony31f1bf72012-01-30 12:37:22 +00003414#undef normal_op
3415}
anthonyfd706f92012-01-19 04:22:02 +00003416
anthony43f425d2012-02-26 12:58:58 +00003417WandExport void CLISimpleOperatorImages(MagickCLI *cli_wand,
anthony31f1bf72012-01-30 12:37:22 +00003418 const MagickBooleanType plus_alt_op, const char *option,
3419 const char *arg1, const char *arg2)
3420{
3421 size_t
anthony43f425d2012-02-26 12:58:58 +00003422 n,
anthony31f1bf72012-01-30 12:37:22 +00003423 i;
3424
anthony43f425d2012-02-26 12:58:58 +00003425 assert(cli_wand != (MagickCLI *) NULL);
3426 assert(cli_wand->signature == WandSignature);
3427 assert(cli_wand->wand.signature == WandSignature);
3428 assert(cli_wand->wand.images != (Image *) NULL); /* images must be present */
3429 if (cli_wand->wand.debug != MagickFalse)
3430 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthony31f1bf72012-01-30 12:37:22 +00003431
3432 i=0;
anthony43f425d2012-02-26 12:58:58 +00003433 n=GetImageListLength(cli_wand->wand.images);
3434 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
3435 while (1)
anthony31f1bf72012-01-30 12:37:22 +00003436 {
anthony31f1bf72012-01-30 12:37:22 +00003437 i++;
anthony43f425d2012-02-26 12:58:58 +00003438 CLISimpleOperatorImage(cli_wand, plus_alt_op, option, arg1, arg2);
3439 if ( cli_wand->wand.images->next == (Image *) NULL )
3440 break;
3441 cli_wand->wand.images=cli_wand->wand.images->next;
anthony31f1bf72012-01-30 12:37:22 +00003442 }
anthony43f425d2012-02-26 12:58:58 +00003443 assert( i == n );
3444 cli_wand->wand.images=GetFirstImageInList(cli_wand->wand.images);
anthony31f1bf72012-01-30 12:37:22 +00003445 return;
anthony805a2d42011-09-25 08:25:12 +00003446}
3447
3448/*
3449%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3450% %
3451% %
3452% %
anthony43f425d2012-02-26 12:58:58 +00003453+ C L I L i s t O p e r a t o r I m a g e s %
anthony805a2d42011-09-25 08:25:12 +00003454% %
3455% %
3456% %
3457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3458%
anthony43f425d2012-02-26 12:58:58 +00003459% CLIListOperatorImages() applies a single operation that is apply to the
anthony31f1bf72012-01-30 12:37:22 +00003460% entire image list as a whole. The result is often a complete replacment
3461% of the image list with a completely new list, or just a single image.
anthony805a2d42011-09-25 08:25:12 +00003462%
3463% The format of the MogrifyImage method is:
3464%
anthony43f425d2012-02-26 12:58:58 +00003465% void CLIListOperatorImages(MagickCLI *cli_wand,
anthony36a8c2c2012-02-10 00:08:44 +00003466% const MagickBooleanType plus_alt_op,const char *option,
anthony31f1bf72012-01-30 12:37:22 +00003467% const char *arg1, const char *arg2)
anthony805a2d42011-09-25 08:25:12 +00003468%
3469% A description of each parameter follows:
3470%
anthony43f425d2012-02-26 12:58:58 +00003471% o cli_wand: structure holding settings to be applied
anthony805a2d42011-09-25 08:25:12 +00003472%
anthony8b10b462012-02-08 12:32:44 +00003473% o plus_alt_op: request the 'plus' or alturnative form of the operation
3474%
anthony36a8c2c2012-02-10 00:08:44 +00003475% o option: The option string for the operation
3476%
anthony31f1bf72012-01-30 12:37:22 +00003477% o arg1, arg2: optional argument strings to the operation
anthony805a2d42011-09-25 08:25:12 +00003478%
anthony8b10b462012-02-08 12:32:44 +00003479% NOTE: only "limit" currently uses two arguments.
3480%
3481% Example usage...
3482%
anthony43f425d2012-02-26 12:58:58 +00003483% CLIListOperatorImages(cli_wand,MagickFalse,"duplicate", "3", NULL);
3484% CLIListOperatorImages(cli_wand,MagickTrue, "append", NULL, NULL);
3485% if ( cli_wand->wand.exception->severity != UndefinedException ) {
anthony8b10b462012-02-08 12:32:44 +00003486% CatchException(exception);
3487% exit(1);
3488% }
3489%
3490% Or for handling command line arguments EG: +/-option ["arg"]
3491%
anthony43f425d2012-02-26 12:58:58 +00003492% cli_wand
anthony8b10b462012-02-08 12:32:44 +00003493% argc,argv
3494% i=index in argv
3495%
anthony2052d272012-02-28 12:48:29 +00003496% option_info = GetCommandOptionInfo(argv[i]);
3497% count=option_info->type;
3498% option_type=option_info->flags;
3499%
3500% if ( (option_type & ListOperatorOptionFlag) != 0 )
anthony43f425d2012-02-26 12:58:58 +00003501% CLIListOperatorImages(cli_wand,
anthony36a8c2c2012-02-10 00:08:44 +00003502% ((*argv[i])=='+')?MagickTrue:MagickFalse,argv[i]+1,
anthony8b10b462012-02-08 12:32:44 +00003503% count>=1 ? argv[i+1] : (char *)NULL,
3504% count>=2 ? argv[i+2] : (char *)NULL );
3505% i += count+1;
3506%
anthony805a2d42011-09-25 08:25:12 +00003507*/
anthony43f425d2012-02-26 12:58:58 +00003508WandExport void CLIListOperatorImages(MagickCLI *cli_wand,
anthony36a8c2c2012-02-10 00:08:44 +00003509 const MagickBooleanType plus_alt_op,const char *option,
3510 const char *arg1, const char *arg2)
anthony805a2d42011-09-25 08:25:12 +00003511{
anthony31f1bf72012-01-30 12:37:22 +00003512 Image
3513 *new_images;
anthony805a2d42011-09-25 08:25:12 +00003514
anthony43f425d2012-02-26 12:58:58 +00003515#define image_info (cli_wand->wand.image_info)
3516#define images (cli_wand->wand.images)
3517#define exception (cli_wand->wand.exception)
3518#define draw_info (cli_wand->draw_info)
3519#define quantize_info (cli_wand->quantize_info)
anthony31f1bf72012-01-30 12:37:22 +00003520#define normal_op (plus_alt_op?MagickFalse:MagickTrue)
anthony805a2d42011-09-25 08:25:12 +00003521
anthony43f425d2012-02-26 12:58:58 +00003522 assert(cli_wand != (MagickCLI *) NULL);
3523 assert(cli_wand->signature == WandSignature);
3524 assert(cli_wand->wand.signature == WandSignature);
3525 assert(images != (Image *) NULL); /* images must be present */
3526 if (cli_wand->wand.debug != MagickFalse)
3527 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
anthony31f1bf72012-01-30 12:37:22 +00003528
3529 (void) SyncImagesSettings(image_info,images,exception);
3530
3531 new_images=NewImageList();
3532
3533 switch (*option)
anthony805a2d42011-09-25 08:25:12 +00003534 {
3535 case 'a':
3536 {
anthony31f1bf72012-01-30 12:37:22 +00003537 if (LocaleCompare("append",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003538 {
anthony31f1bf72012-01-30 12:37:22 +00003539 new_images=AppendImages(images,normal_op,exception);
anthony805a2d42011-09-25 08:25:12 +00003540 break;
3541 }
anthony31f1bf72012-01-30 12:37:22 +00003542 if (LocaleCompare("average",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003543 {
anthony31f1bf72012-01-30 12:37:22 +00003544 /* DEPRECIATED - use -evaluate-sequence Mean */
anthony43f425d2012-02-26 12:58:58 +00003545 CLIListOperatorImages(cli_wand,plus_alt_op,"evaluate-sequence","Mean",
anthony31f1bf72012-01-30 12:37:22 +00003546 NULL);
anthony805a2d42011-09-25 08:25:12 +00003547 break;
3548 }
3549 break;
3550 }
3551 case 'c':
3552 {
cristy87c02f42012-02-24 00:19:10 +00003553 if (LocaleCompare("channel-inject",option) == 0)
3554 {
3555 puts("stand by...");
3556 break;
3557 }
anthony31f1bf72012-01-30 12:37:22 +00003558 if (LocaleCompare("clut",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003559 {
anthony805a2d42011-09-25 08:25:12 +00003560 Image
anthony31f1bf72012-01-30 12:37:22 +00003561 *clut_image;
anthony805a2d42011-09-25 08:25:12 +00003562
cristy87c02f42012-02-24 00:19:10 +00003563 /* FUTURE - make this a compose option (and thus layers compose )
3564 or perhaps compose last image over all other images.
3565 */
anthony31f1bf72012-01-30 12:37:22 +00003566 new_images=RemoveFirstImageFromList(&images);
3567 clut_image=RemoveLastImageFromList(&images);
anthonye8f56492012-02-12 12:39:02 +00003568 /* FUTURE - produce Exception, rather than silent fail */
anthony805a2d42011-09-25 08:25:12 +00003569 if (clut_image == (Image *) NULL)
cristy87c02f42012-02-24 00:19:10 +00003570 break;
anthony31f1bf72012-01-30 12:37:22 +00003571 (void) ClutImage(new_images,clut_image,images->interpolate,exception);
anthony805a2d42011-09-25 08:25:12 +00003572 clut_image=DestroyImage(clut_image);
anthony805a2d42011-09-25 08:25:12 +00003573 break;
3574 }
anthony31f1bf72012-01-30 12:37:22 +00003575 if (LocaleCompare("coalesce",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003576 {
anthony31f1bf72012-01-30 12:37:22 +00003577 new_images=CoalesceImages(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003578 break;
3579 }
anthony31f1bf72012-01-30 12:37:22 +00003580 if (LocaleCompare("combine",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003581 {
anthony43f425d2012-02-26 12:58:58 +00003582 /* FUTURE - this may be replaced by a 'channel' method */
anthony31f1bf72012-01-30 12:37:22 +00003583 new_images=CombineImages(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003584 break;
3585 }
anthony31f1bf72012-01-30 12:37:22 +00003586 if (LocaleCompare("composite",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003587 {
3588 Image
3589 *mask_image,
anthony31f1bf72012-01-30 12:37:22 +00003590 *source_image;
anthony805a2d42011-09-25 08:25:12 +00003591
3592 RectangleInfo
3593 geometry;
3594
anthony31f1bf72012-01-30 12:37:22 +00003595 CompositeOperator
anthony5f867ae2011-10-09 10:28:34 +00003596 compose;
3597
3598 const char*
3599 value;
3600
3601 value=GetImageOption(image_info,"compose");
3602 if (value != (const char *) NULL)
3603 compose=(CompositeOperator) ParseCommandOption(
3604 MagickComposeOptions,MagickFalse,value);
3605 else
anthony31f1bf72012-01-30 12:37:22 +00003606 compose=OverCompositeOp; /* use Over not source_image->compose */
anthony5f867ae2011-10-09 10:28:34 +00003607
anthony31f1bf72012-01-30 12:37:22 +00003608 new_images=RemoveFirstImageFromList(&images);
3609 source_image=RemoveFirstImageFromList(&images);
anthonye8f56492012-02-12 12:39:02 +00003610 /* FUTURE - produce Exception, rather than silent fail */
anthony31f1bf72012-01-30 12:37:22 +00003611 if (source_image == (Image *) NULL)
3612 break;
anthonye8f56492012-02-12 12:39:02 +00003613
anthony31f1bf72012-01-30 12:37:22 +00003614 /* FUTURE - this should not be here! - should be part of -geometry */
3615 (void) TransformImage(&source_image,(char *) NULL,
3616 source_image->geometry,exception);
anthony5f867ae2011-10-09 10:28:34 +00003617
anthony31f1bf72012-01-30 12:37:22 +00003618 SetGeometry(source_image,&geometry);
3619 (void) ParseAbsoluteGeometry(source_image->geometry,&geometry);
3620 GravityAdjustGeometry(new_images->columns,new_images->rows,
3621 new_images->gravity, &geometry);
anthony5f867ae2011-10-09 10:28:34 +00003622
anthony31f1bf72012-01-30 12:37:22 +00003623 mask_image=RemoveFirstImageFromList(&images);
anthony805a2d42011-09-25 08:25:12 +00003624 if (mask_image != (Image *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00003625 { /* handle a third write mask image */
anthony5f867ae2011-10-09 10:28:34 +00003626 if ((compose == DisplaceCompositeOp) ||
3627 (compose == DistortCompositeOp))
anthony31f1bf72012-01-30 12:37:22 +00003628 { /* Merge Y displacement into X displace/distort map. */
3629 (void) CompositeImage(source_image,CopyGreenCompositeOp,
anthony6613bf32011-10-15 07:24:44 +00003630 mask_image,0,0,exception);
anthony805a2d42011-09-25 08:25:12 +00003631 mask_image=DestroyImage(mask_image);
3632 }
3633 else
3634 {
3635 /*
3636 Set a blending mask for the composition.
anthony805a2d42011-09-25 08:25:12 +00003637 */
cristy1539afd2012-01-30 01:32:59 +00003638 (void) NegateImage(mask_image,MagickFalse,exception);
anthony31f1bf72012-01-30 12:37:22 +00003639 (void) SetImageMask(new_images,mask_image,exception);
cristy1539afd2012-01-30 01:32:59 +00003640 mask_image=DestroyImage(mask_image);
anthony805a2d42011-09-25 08:25:12 +00003641 }
3642 }
anthony31f1bf72012-01-30 12:37:22 +00003643 (void) CompositeImage(new_images,compose,source_image,geometry.x,
3644 geometry.y,exception);
3645 (void) SetImageMask(new_images,(Image *) NULL,exception);
3646 source_image=DestroyImage(source_image);
anthony805a2d42011-09-25 08:25:12 +00003647 break;
3648 }
3649 break;
3650 }
3651 case 'd':
3652 {
anthony31f1bf72012-01-30 12:37:22 +00003653 if (LocaleCompare("deconstruct",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003654 {
anthony31f1bf72012-01-30 12:37:22 +00003655 /* DEPRECIATED - use -layers CompareAny */
anthony43f425d2012-02-26 12:58:58 +00003656 CLIListOperatorImages(cli_wand,plus_alt_op,"layer","CompareAny",NULL);
anthony805a2d42011-09-25 08:25:12 +00003657 break;
3658 }
anthony31f1bf72012-01-30 12:37:22 +00003659 if (LocaleCompare("delete",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003660 {
anthony31f1bf72012-01-30 12:37:22 +00003661 if (plus_alt_op != MagickFalse)
3662 DeleteImages(&images,"-1",exception);
anthony805a2d42011-09-25 08:25:12 +00003663 else
anthony31f1bf72012-01-30 12:37:22 +00003664 DeleteImages(&images,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00003665 break;
3666 }
anthony31f1bf72012-01-30 12:37:22 +00003667 if (LocaleCompare("duplicate",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003668 {
anthony31f1bf72012-01-30 12:37:22 +00003669 if (plus_alt_op != MagickFalse)
anthony36a8c2c2012-02-10 00:08:44 +00003670 new_images=DuplicateImages(images,1,"-1",exception);
anthony805a2d42011-09-25 08:25:12 +00003671 else
3672 {
3673 const char
3674 *p;
3675
3676 size_t
3677 number_duplicates;
3678
anthony31f1bf72012-01-30 12:37:22 +00003679 number_duplicates=(size_t) StringToLong(arg1);
3680 p=strchr(arg1,',');
anthony805a2d42011-09-25 08:25:12 +00003681 if (p == (const char *) NULL)
anthony36a8c2c2012-02-10 00:08:44 +00003682 new_images=DuplicateImages(images,number_duplicates,
anthony805a2d42011-09-25 08:25:12 +00003683 "-1",exception);
3684 else
anthony36a8c2c2012-02-10 00:08:44 +00003685 new_images=DuplicateImages(images,number_duplicates,p,
anthony805a2d42011-09-25 08:25:12 +00003686 exception);
3687 }
anthony36a8c2c2012-02-10 00:08:44 +00003688 AppendImageToList(&images, new_images);
3689 new_images=(Image *)NULL;
anthony805a2d42011-09-25 08:25:12 +00003690 break;
3691 }
3692 break;
3693 }
3694 case 'e':
3695 {
anthony31f1bf72012-01-30 12:37:22 +00003696 if (LocaleCompare("evaluate-sequence",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003697 {
anthony805a2d42011-09-25 08:25:12 +00003698 MagickEvaluateOperator
anthony31f1bf72012-01-30 12:37:22 +00003699 method;
anthony805a2d42011-09-25 08:25:12 +00003700
anthony31f1bf72012-01-30 12:37:22 +00003701 method=(MagickEvaluateOperator) ParseCommandOption(
3702 MagickEvaluateOptions,MagickFalse,arg1);
3703 new_images=EvaluateImages(images,method,exception);
anthony805a2d42011-09-25 08:25:12 +00003704 break;
3705 }
3706 break;
3707 }
3708 case 'f':
3709 {
anthony31f1bf72012-01-30 12:37:22 +00003710 if (LocaleCompare("fft",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003711 {
anthony31f1bf72012-01-30 12:37:22 +00003712 new_images=ForwardFourierTransformImage(images,normal_op,exception);
anthony805a2d42011-09-25 08:25:12 +00003713 break;
3714 }
anthony31f1bf72012-01-30 12:37:22 +00003715 if (LocaleCompare("flatten",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003716 {
anthony31f1bf72012-01-30 12:37:22 +00003717 /* DEPRECIATED use -layers mosaic instead */
anthony43f425d2012-02-26 12:58:58 +00003718 CLIListOperatorImages(cli_wand,plus_alt_op,"layer",option,NULL);
anthony805a2d42011-09-25 08:25:12 +00003719 break;
3720 }
anthony31f1bf72012-01-30 12:37:22 +00003721 if (LocaleCompare("fx",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003722 {
anthony31f1bf72012-01-30 12:37:22 +00003723 new_images=FxImage(images,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00003724 break;
3725 }
3726 break;
3727 }
3728 case 'h':
3729 {
anthony31f1bf72012-01-30 12:37:22 +00003730 if (LocaleCompare("hald-clut",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003731 {
anthony31f1bf72012-01-30 12:37:22 +00003732 /* FUTURE - make this a compose option (and thus layers compose )
3733 or perhaps compose last image over all other images.
3734 */
anthony805a2d42011-09-25 08:25:12 +00003735 Image
anthony31f1bf72012-01-30 12:37:22 +00003736 *hald_image;
anthony805a2d42011-09-25 08:25:12 +00003737
anthony31f1bf72012-01-30 12:37:22 +00003738 new_images=RemoveFirstImageFromList(&images);
3739 hald_image=RemoveLastImageFromList(&images);
anthony805a2d42011-09-25 08:25:12 +00003740 if (hald_image == (Image *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00003741 break;
3742 (void) HaldClutImage(new_images,hald_image,exception);
anthony805a2d42011-09-25 08:25:12 +00003743 hald_image=DestroyImage(hald_image);
anthony805a2d42011-09-25 08:25:12 +00003744 break;
3745 }
3746 break;
3747 }
3748 case 'i':
3749 {
anthony31f1bf72012-01-30 12:37:22 +00003750 if (LocaleCompare("ift",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003751 {
3752 Image
anthony805a2d42011-09-25 08:25:12 +00003753 *magnitude_image,
3754 *phase_image;
3755
anthony31f1bf72012-01-30 12:37:22 +00003756 magnitude_image=RemoveFirstImageFromList(&images);
3757 phase_image=RemoveFirstImageFromList(&images);
anthonye8f56492012-02-12 12:39:02 +00003758 /* FUTURE - produce Exception, rather than silent fail */
anthony31f1bf72012-01-30 12:37:22 +00003759 if (phase_image == (Image *) NULL)
3760 break;
3761 new_images=InverseFourierTransformImage(magnitude_image,phase_image,
3762 normal_op,exception);
3763 magnitude_image=DestroyImage(magnitude_image);
3764 phase_image=DestroyImage(phase_image);
anthony805a2d42011-09-25 08:25:12 +00003765 break;
3766 }
anthony31f1bf72012-01-30 12:37:22 +00003767 if (LocaleCompare("insert",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003768 {
3769 Image
anthony31f1bf72012-01-30 12:37:22 +00003770 *insert_image,
3771 *index_image;
3772
3773 ssize_t
3774 index;
anthony805a2d42011-09-25 08:25:12 +00003775
3776 index=0;
anthony31f1bf72012-01-30 12:37:22 +00003777 insert_image=RemoveLastImageFromList(&images);
3778 if (plus_alt_op == MagickFalse)
3779 index=(ssize_t) StringToLong(arg1);
anthony43f425d2012-02-26 12:58:58 +00003780 index_image=insert_image;
anthony805a2d42011-09-25 08:25:12 +00003781 if (index == 0)
anthony31f1bf72012-01-30 12:37:22 +00003782 PrependImageToList(&images,insert_image);
anthony43f425d2012-02-26 12:58:58 +00003783 else if (index == (ssize_t) GetImageListLength(images))
3784 AppendImageToList(&images,insert_image);
anthony805a2d42011-09-25 08:25:12 +00003785 else
anthony43f425d2012-02-26 12:58:58 +00003786 {
3787 index_image=GetImageFromList(images,index-1);
3788 if (index_image == (Image *) NULL)
3789 {
3790 (void) ThrowMagickException(exception,GetMagickModule(),
3791 OptionError,"NoSuchImage","'%s'",arg1);
3792 break;
3793 }
3794 InsertImageInList(&index_image,insert_image);
3795 }
anthony31f1bf72012-01-30 12:37:22 +00003796 images=GetFirstImageInList(index_image);
anthony805a2d42011-09-25 08:25:12 +00003797 break;
3798 }
anthony805a2d42011-09-25 08:25:12 +00003799 break;
3800 }
3801 case 'l':
3802 {
anthony31f1bf72012-01-30 12:37:22 +00003803 if (LocaleCompare("layers",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003804 {
anthony805a2d42011-09-25 08:25:12 +00003805 ImageLayerMethod
3806 method;
3807
anthony805a2d42011-09-25 08:25:12 +00003808 method=(ImageLayerMethod) ParseCommandOption(MagickLayerOptions,
anthony31f1bf72012-01-30 12:37:22 +00003809 MagickFalse,arg1);
anthony805a2d42011-09-25 08:25:12 +00003810 switch (method)
3811 {
3812 case CoalesceLayer:
3813 {
anthony31f1bf72012-01-30 12:37:22 +00003814 new_images=CoalesceImages(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003815 break;
3816 }
3817 case CompareAnyLayer:
3818 case CompareClearLayer:
3819 case CompareOverlayLayer:
3820 default:
3821 {
anthony31f1bf72012-01-30 12:37:22 +00003822 new_images=CompareImagesLayers(images,method,exception);
anthony805a2d42011-09-25 08:25:12 +00003823 break;
3824 }
3825 case MergeLayer:
3826 case FlattenLayer:
3827 case MosaicLayer:
3828 case TrimBoundsLayer:
3829 {
anthony31f1bf72012-01-30 12:37:22 +00003830 new_images=MergeImageLayers(images,method,exception);
anthony805a2d42011-09-25 08:25:12 +00003831 break;
3832 }
3833 case DisposeLayer:
3834 {
anthony31f1bf72012-01-30 12:37:22 +00003835 new_images=DisposeImages(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003836 break;
3837 }
3838 case OptimizeImageLayer:
3839 {
anthony31f1bf72012-01-30 12:37:22 +00003840 new_images=OptimizeImageLayers(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003841 break;
3842 }
3843 case OptimizePlusLayer:
3844 {
anthony31f1bf72012-01-30 12:37:22 +00003845 new_images=OptimizePlusImageLayers(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003846 break;
3847 }
3848 case OptimizeTransLayer:
3849 {
anthony31f1bf72012-01-30 12:37:22 +00003850 OptimizeImageTransparency(images,exception);
anthony805a2d42011-09-25 08:25:12 +00003851 break;
3852 }
3853 case RemoveDupsLayer:
3854 {
anthony31f1bf72012-01-30 12:37:22 +00003855 RemoveDuplicateLayers(&images,exception);
anthony805a2d42011-09-25 08:25:12 +00003856 break;
3857 }
3858 case RemoveZeroLayer:
3859 {
anthony31f1bf72012-01-30 12:37:22 +00003860 RemoveZeroDelayLayers(&images,exception);
anthony805a2d42011-09-25 08:25:12 +00003861 break;
3862 }
3863 case OptimizeLayer:
anthony31f1bf72012-01-30 12:37:22 +00003864 { /* General Purpose, GIF Animation Optimizer. */
3865 new_images=CoalesceImages(images,exception);
3866 if (new_images == (Image *) NULL)
3867 break;
3868 images=DestroyImageList(images);
3869 images=OptimizeImageLayers(new_images,exception);
3870 if (images == (Image *) NULL)
3871 break;
3872 new_images=DestroyImageList(new_images);
3873 OptimizeImageTransparency(images,exception);
3874 (void) RemapImages(quantize_info,images,(Image *) NULL,
anthony805a2d42011-09-25 08:25:12 +00003875 exception);
3876 break;
3877 }
3878 case CompositeLayer:
3879 {
anthony805a2d42011-09-25 08:25:12 +00003880 Image
3881 *source;
3882
3883 RectangleInfo
3884 geometry;
3885
anthony31f1bf72012-01-30 12:37:22 +00003886 CompositeOperator
anthony5f867ae2011-10-09 10:28:34 +00003887 compose;
3888
3889 const char*
3890 value;
3891
3892 value=GetImageOption(image_info,"compose");
anthony31f1bf72012-01-30 12:37:22 +00003893 compose=OverCompositeOp; /* Default to Over */
anthony5f867ae2011-10-09 10:28:34 +00003894 if (value != (const char *) NULL)
3895 compose=(CompositeOperator) ParseCommandOption(
3896 MagickComposeOptions,MagickFalse,value);
anthony5f867ae2011-10-09 10:28:34 +00003897
anthony31f1bf72012-01-30 12:37:22 +00003898 /* Split image sequence at the first 'NULL:' image. */
3899 source=images;
anthony805a2d42011-09-25 08:25:12 +00003900 while (source != (Image *) NULL)
3901 {
3902 source=GetNextImageInList(source);
3903 if ((source != (Image *) NULL) &&
3904 (LocaleCompare(source->magick,"NULL") == 0))
3905 break;
3906 }
3907 if (source != (Image *) NULL)
3908 {
3909 if ((GetPreviousImageInList(source) == (Image *) NULL) ||
3910 (GetNextImageInList(source) == (Image *) NULL))
3911 source=(Image *) NULL;
3912 else
anthony31f1bf72012-01-30 12:37:22 +00003913 { /* Separate the two lists, junk the null: image. */
anthony805a2d42011-09-25 08:25:12 +00003914 source=SplitImageList(source->previous);
3915 DeleteImageFromList(&source);
3916 }
3917 }
3918 if (source == (Image *) NULL)
3919 {
3920 (void) ThrowMagickException(exception,GetMagickModule(),
3921 OptionError,"MissingNullSeparator","layers Composite");
anthony805a2d42011-09-25 08:25:12 +00003922 break;
3923 }
anthony31f1bf72012-01-30 12:37:22 +00003924 /* Adjust offset with gravity and virtual canvas. */
3925 SetGeometry(images,&geometry);
3926 (void) ParseAbsoluteGeometry(images->geometry,&geometry);
anthony805a2d42011-09-25 08:25:12 +00003927 geometry.width=source->page.width != 0 ?
3928 source->page.width : source->columns;
3929 geometry.height=source->page.height != 0 ?
3930 source->page.height : source->rows;
anthony31f1bf72012-01-30 12:37:22 +00003931 GravityAdjustGeometry(images->page.width != 0 ?
3932 images->page.width : images->columns,
3933 images->page.height != 0 ? images->page.height :
3934 images->rows,images->gravity,&geometry);
anthony5f867ae2011-10-09 10:28:34 +00003935
anthony31f1bf72012-01-30 12:37:22 +00003936 /* Compose the two image sequences together */
3937 CompositeLayers(images,compose,source,geometry.x,geometry.y,
anthony805a2d42011-09-25 08:25:12 +00003938 exception);
3939 source=DestroyImageList(source);
3940 break;
3941 }
3942 }
anthony805a2d42011-09-25 08:25:12 +00003943 break;
3944 }
anthony72feaa62012-01-17 06:46:23 +00003945 if (LocaleCompare("limit",option) == 0)
3946 {
3947 MagickSizeType
3948 limit;
3949
3950 ResourceType
3951 type;
3952
anthony72feaa62012-01-17 06:46:23 +00003953 type=(ResourceType) ParseCommandOption(MagickResourceOptions,
anthony31f1bf72012-01-30 12:37:22 +00003954 MagickFalse,arg1);
anthony72feaa62012-01-17 06:46:23 +00003955 limit=MagickResourceInfinity;
anthony31f1bf72012-01-30 12:37:22 +00003956 if (LocaleCompare("unlimited",arg2) != 0)
3957 limit=(MagickSizeType) SiPrefixToDoubleInterval(arg2,100.0);
anthony72feaa62012-01-17 06:46:23 +00003958 (void) SetMagickResourceLimit(type,limit);
3959 break;
3960 }
anthony805a2d42011-09-25 08:25:12 +00003961 break;
3962 }
3963 case 'm':
3964 {
anthony31f1bf72012-01-30 12:37:22 +00003965 if (LocaleCompare("map",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003966 {
anthony31f1bf72012-01-30 12:37:22 +00003967 /* DEPRECIATED use +remap */
3968 (void) RemapImages(quantize_info,images,(Image *) NULL,exception);
anthony805a2d42011-09-25 08:25:12 +00003969 break;
3970 }
anthony31f1bf72012-01-30 12:37:22 +00003971 if (LocaleCompare("morph",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003972 {
3973 Image
3974 *morph_image;
3975
anthony31f1bf72012-01-30 12:37:22 +00003976 morph_image=MorphImages(images,StringToUnsignedLong(arg1),
anthony805a2d42011-09-25 08:25:12 +00003977 exception);
3978 if (morph_image == (Image *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00003979 break;
3980 images=DestroyImageList(images);
3981 images=morph_image;
anthony805a2d42011-09-25 08:25:12 +00003982 break;
3983 }
anthony31f1bf72012-01-30 12:37:22 +00003984 if (LocaleCompare("mosaic",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003985 {
anthony31f1bf72012-01-30 12:37:22 +00003986 /* DEPRECIATED use -layers mosaic instead */
anthony43f425d2012-02-26 12:58:58 +00003987 CLIListOperatorImages(cli_wand,plus_alt_op,"layer",option,NULL);
anthony805a2d42011-09-25 08:25:12 +00003988 break;
3989 }
3990 break;
3991 }
3992 case 'p':
3993 {
anthony31f1bf72012-01-30 12:37:22 +00003994 if (LocaleCompare("print",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00003995 {
3996 char
3997 *string;
3998
anthony31f1bf72012-01-30 12:37:22 +00003999 string=InterpretImageProperties(image_info,images,arg1,
anthony805a2d42011-09-25 08:25:12 +00004000 exception);
4001 if (string == (char *) NULL)
4002 break;
4003 (void) FormatLocaleFile(stdout,"%s",string);
4004 string=DestroyString(string);
4005 }
anthony31f1bf72012-01-30 12:37:22 +00004006 if (LocaleCompare("process",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00004007 {
4008 char
4009 **arguments;
4010
4011 int
4012 j,
4013 number_arguments;
4014
anthony31f1bf72012-01-30 12:37:22 +00004015 arguments=StringToArgv(arg1,&number_arguments);
anthony805a2d42011-09-25 08:25:12 +00004016 if (arguments == (char **) NULL)
4017 break;
anthony31f1bf72012-01-30 12:37:22 +00004018 if (strchr(arguments[1],'=') != (char *) NULL)
anthony805a2d42011-09-25 08:25:12 +00004019 {
4020 char
4021 breaker,
4022 quote,
4023 *token;
4024
4025 const char
4026 *arguments;
4027
4028 int
4029 next,
4030 status;
4031
4032 size_t
4033 length;
4034
4035 TokenInfo
4036 *token_info;
4037
4038 /*
4039 Support old style syntax, filter="-option arg".
4040 */
anthony31f1bf72012-01-30 12:37:22 +00004041 length=strlen(arg1);
anthony805a2d42011-09-25 08:25:12 +00004042 token=(char *) NULL;
4043 if (~length >= (MaxTextExtent-1))
4044 token=(char *) AcquireQuantumMemory(length+MaxTextExtent,
4045 sizeof(*token));
4046 if (token == (char *) NULL)
4047 break;
4048 next=0;
anthony31f1bf72012-01-30 12:37:22 +00004049 arguments=arg1;
anthony805a2d42011-09-25 08:25:12 +00004050 token_info=AcquireTokenInfo();
4051 status=Tokenizer(token_info,0,token,length,arguments,"","=",
4052 "\"",'\0',&breaker,&next,&quote);
4053 token_info=DestroyTokenInfo(token_info);
4054 if (status == 0)
4055 {
4056 const char
4057 *argv;
4058
4059 argv=(&(arguments[next]));
anthony31f1bf72012-01-30 12:37:22 +00004060 (void) InvokeDynamicImageFilter(token,&images,1,&argv,
anthony805a2d42011-09-25 08:25:12 +00004061 exception);
4062 }
4063 token=DestroyString(token);
4064 break;
4065 }
4066 (void) SubstituteString(&arguments[1],"-","");
anthony31f1bf72012-01-30 12:37:22 +00004067 (void) InvokeDynamicImageFilter(arguments[1],&images,
anthony805a2d42011-09-25 08:25:12 +00004068 number_arguments-2,(const char **) arguments+2,exception);
4069 for (j=0; j < number_arguments; j++)
4070 arguments[j]=DestroyString(arguments[j]);
4071 arguments=(char **) RelinquishMagickMemory(arguments);
4072 break;
4073 }
4074 break;
4075 }
4076 case 'r':
4077 {
anthony31f1bf72012-01-30 12:37:22 +00004078 if (LocaleCompare("remap",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00004079 {
anthony31f1bf72012-01-30 12:37:22 +00004080 (void) RemapImages(quantize_info,images,(Image *) NULL,exception);
4081 (void) RemapImages(quantize_info,images,(Image *) NULL,exception);
4082 break;
4083 }
4084 if (LocaleCompare("reverse",option) == 0)
4085 {
4086 ReverseImageList(&images);
anthony805a2d42011-09-25 08:25:12 +00004087 break;
4088 }
4089 break;
4090 }
4091 case 's':
4092 {
anthony31f1bf72012-01-30 12:37:22 +00004093 if (LocaleCompare("smush",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00004094 {
4095 Image
4096 *smush_image;
4097
4098 ssize_t
4099 offset;
4100
anthony31f1bf72012-01-30 12:37:22 +00004101 offset=(ssize_t) StringToLong(arg1);
4102 smush_image=SmushImages(images,normal_op,offset,exception);
anthony805a2d42011-09-25 08:25:12 +00004103 if (smush_image == (Image *) NULL)
anthony31f1bf72012-01-30 12:37:22 +00004104 break;
4105 images=DestroyImageList(images);
4106 images=smush_image;
anthony805a2d42011-09-25 08:25:12 +00004107 break;
4108 }
anthony31f1bf72012-01-30 12:37:22 +00004109 if (LocaleCompare("swap",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00004110 {
4111 Image
4112 *p,
4113 *q,
4114 *swap;
4115
4116 ssize_t
anthony31f1bf72012-01-30 12:37:22 +00004117 index,
anthony805a2d42011-09-25 08:25:12 +00004118 swap_index;
4119
anthony31f1bf72012-01-30 12:37:22 +00004120 index=-1;
4121 swap_index=-2;
4122 if (plus_alt_op == MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00004123 {
4124 GeometryInfo
4125 geometry_info;
4126
4127 MagickStatusType
4128 flags;
4129
4130 swap_index=(-1);
anthony31f1bf72012-01-30 12:37:22 +00004131 flags=ParseGeometry(arg1,&geometry_info);
anthony805a2d42011-09-25 08:25:12 +00004132 index=(ssize_t) geometry_info.rho;
4133 if ((flags & SigmaValue) != 0)
4134 swap_index=(ssize_t) geometry_info.sigma;
4135 }
anthony31f1bf72012-01-30 12:37:22 +00004136 p=GetImageFromList(images,index);
4137 q=GetImageFromList(images,swap_index);
anthony805a2d42011-09-25 08:25:12 +00004138 if ((p == (Image *) NULL) || (q == (Image *) NULL))
4139 {
4140 (void) ThrowMagickException(exception,GetMagickModule(),
anthony43f425d2012-02-26 12:58:58 +00004141 OptionError,"NoSuchImage","'%s'",images->filename);
anthony805a2d42011-09-25 08:25:12 +00004142 break;
4143 }
4144 if (p == q)
4145 break;
4146 swap=CloneImage(p,0,0,MagickTrue,exception);
4147 ReplaceImageInList(&p,CloneImage(q,0,0,MagickTrue,exception));
4148 ReplaceImageInList(&q,swap);
anthony31f1bf72012-01-30 12:37:22 +00004149 images=GetFirstImageInList(q);
anthony805a2d42011-09-25 08:25:12 +00004150 break;
4151 }
4152 break;
4153 }
4154 case 'w':
4155 {
anthony31f1bf72012-01-30 12:37:22 +00004156 if (LocaleCompare("write",option) == 0)
anthony805a2d42011-09-25 08:25:12 +00004157 {
4158 char
4159 key[MaxTextExtent];
4160
4161 Image
4162 *write_images;
4163
4164 ImageInfo
4165 *write_info;
4166
anthony31f1bf72012-01-30 12:37:22 +00004167 (void) FormatLocaleString(key,MaxTextExtent,"cache:%s",arg1);
anthony805a2d42011-09-25 08:25:12 +00004168 (void) DeleteImageRegistry(key);
anthony31f1bf72012-01-30 12:37:22 +00004169 write_images=images;
4170 if (plus_alt_op != MagickFalse)
4171 write_images=CloneImageList(images,exception);
anthony805a2d42011-09-25 08:25:12 +00004172 write_info=CloneImageInfo(image_info);
anthony31f1bf72012-01-30 12:37:22 +00004173 (void) WriteImages(write_info,write_images,arg1,exception);
anthony805a2d42011-09-25 08:25:12 +00004174 write_info=DestroyImageInfo(write_info);
anthony31f1bf72012-01-30 12:37:22 +00004175 if (plus_alt_op != MagickFalse)
anthony805a2d42011-09-25 08:25:12 +00004176 write_images=DestroyImageList(write_images);
4177 break;
4178 }
4179 break;
4180 }
4181 default:
4182 break;
4183 }
anthony31f1bf72012-01-30 12:37:22 +00004184 if (new_images == (Image *) NULL)
4185 return;
anthony805a2d42011-09-25 08:25:12 +00004186
anthony31f1bf72012-01-30 12:37:22 +00004187 if (images != (Image *) NULL)
4188 images=DestroyImageList(images);
anthony43f425d2012-02-26 12:58:58 +00004189 images=GetFirstImageInList(new_images);
anthony31f1bf72012-01-30 12:37:22 +00004190 return;
4191
4192#undef image_info
anthony31f1bf72012-01-30 12:37:22 +00004193#undef images
4194#undef exception
anthony43f425d2012-02-26 12:58:58 +00004195#undef draw_info
4196#undef quantize_info
anthony31f1bf72012-01-30 12:37:22 +00004197#undef normal_op
anthony805a2d42011-09-25 08:25:12 +00004198}
anthony43f425d2012-02-26 12:58:58 +00004199
4200/*
4201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202% %
4203% %
4204% %
4205+ C L I S p e c i a l O p e r a t i o n s %
4206% %
4207% %
4208% %
4209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4210%
4211% CLISpecialOption() Applies operations that may involve empty image lists
4212% and or stacks of image lists or image_info settings.
4213%
4214% Note: inlike other Operators, these may involve other special 'option'
4215% character prefixes, other than simply '-' or '+' and as such the full
4216% original otpion must be passed.
4217%
4218% The format of the CLISpecialOption method is:
4219%
4220% void CLISpecialOption(MagickCLI *cli_wand,const char *option,
4221% const char *arg)
4222%
4223% A description of each parameter follows:
4224%
4225% o cli_wand: the main CLI Wand to use.
4226%
4227% o option: The special option (with any switch char) to process
4228%
4229% o arg: Argument for option, if required
anthony2052d272012-02-28 12:48:29 +00004230%
4231% Example Usage...
4232%
4233% CLISpecialOperator(cli_wand,"-read", "rose:");
4234% if ( cli_wand->wand.exception->severity != UndefinedException ) {
4235% CatchException(exception);
4236% exit(1);
4237% }
4238%
4239% Or for handling command line arguments EG: +/-option ["arg"]
4240%
4241% cli_wand
4242% argc,argv
4243% i=index in argv
4244%
4245% option_info = GetCommandOptionInfo(argv[i]);
4246% count=option_info->type;
4247% option_type=option_info->flags;
4248%
4249% if ( (option_type & SpecialOptionFlag) != 0 )
4250% CLISpecialOperator(cli_wand,argv[i],
4251% count>=1 ? argv[i+1] : (char *)NULL);
4252% i += count+1;
anthony43f425d2012-02-26 12:58:58 +00004253%
4254*/
4255
4256#define MaxImageStackDepth 32
4257
4258WandExport void CLISpecialOperator(MagickCLI *cli_wand,
4259 const char *option, const char *arg)
4260{
4261#define exception (cli_wand->wand.exception)
4262
4263 assert(cli_wand != (MagickCLI *) NULL);
4264 assert(cli_wand->signature == WandSignature);
4265 assert(cli_wand->wand.signature == WandSignature);
4266 if (cli_wand->wand.debug != MagickFalse)
4267 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cli_wand->wand.name);
4268
4269 if (LocaleCompare(option,"(") == 0)
4270 {
4271 /* stack 'push' images */
4272 Stack
4273 *node;
4274
4275 size_t
4276 size;
4277
4278 const char*
4279 value;
4280
4281 size=0;
4282 node=cli_wand->image_list_stack;
4283 for ( ; node != (Stack *)NULL; node=node->next)
4284 size++;
4285 if ( size >= MaxImageStackDepth )
4286 {
4287 ThrowMagickException(exception,GetMagickModule(),
4288 OptionError,"ParenthesisNestedTooDeeply", option);
4289 return;
4290 }
4291 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4292 if (node == (Stack *) NULL)
4293 {
4294 ThrowMagickException(exception,GetMagickModule(),
4295 ResourceLimitFatalError,"MemoryAllocationFailed", "PushImages");
4296 return;
4297 }
4298 node->data = (void *)cli_wand->wand.images;
4299 cli_wand->wand.images = NewImageList();
4300 node->next = cli_wand->image_list_stack;
4301 cli_wand->image_list_stack = node;
4302
4303 /* handle respect-parenthesis */
4304 value=GetImageOption(cli_wand->wand.image_info,"respect-parenthesis");
4305 if (value != (const char *) NULL)
4306 option="{";
4307 else
4308 return;
4309 }
4310 if (LocaleCompare(option,"{") == 0)
4311 {
4312 /* stack 'push' of image_info settings */
4313 Stack
4314 *node;
4315
4316 size_t
4317 size;
4318
4319 size=0;
4320 node=cli_wand->image_info_stack;
4321 for ( ; node != (Stack *)NULL; node=node->next)
4322 size++;
4323 if ( size >= MaxImageStackDepth )
4324 {
4325 ThrowMagickException(exception,GetMagickModule(),
4326 OptionError,"ParenthesisNestedTooDeeply", option);
4327 return;
4328 }
4329 node=(Stack *) AcquireMagickMemory(sizeof(*node));
4330 if (node == (Stack *) NULL)
4331 {
4332 ThrowMagickException(exception,GetMagickModule(),
4333 ResourceLimitFatalError,"MemoryAllocationFailed", "PushSettings");
4334 return;
4335 }
4336
4337 node->data = (void *)cli_wand->wand.image_info;
4338 cli_wand->wand.image_info = CloneImageInfo(cli_wand->wand.image_info);
4339 if (cli_wand->wand.image_info == (ImageInfo *)NULL)
4340 {
4341 ThrowMagickException(exception,GetMagickModule(),
4342 ResourceLimitFatalError,"MemoryAllocationFailed", "PushSettings");
4343 cli_wand->wand.image_info = (ImageInfo *)node->data;
4344 node = (Stack *)RelinquishMagickMemory(node);
4345 return;
4346 }
4347
4348 node->next = cli_wand->image_info_stack;
4349 cli_wand->image_info_stack = node;
4350
4351 return;
4352 }
4353 if (LocaleCompare(option,")") == 0)
4354 {
4355 /* pop images from stack */
4356 Stack
4357 *node;
4358
4359 const char*
4360 value;
4361
4362 node = (void *)cli_wand->image_list_stack;
4363 if ( node == (Stack *)NULL)
4364 {
4365 ThrowMagickException(exception,GetMagickModule(),
4366 OptionError,"UnbalancedParenthesis", option);
4367 return;
4368 }
4369 cli_wand->image_list_stack = node->next;
4370
4371 AppendImageToList((Image **)&node->data,cli_wand->wand.images);
4372 cli_wand->wand.images= (Image *)node->data;
4373 node = (Stack *)RelinquishMagickMemory(node);
4374
4375 /* handle respect-parenthesis - of the previous 'push' settings */
4376 node = cli_wand->image_info_stack;
4377 if ( node != (Stack *)NULL)
4378 {
4379 value=GetImageOption((ImageInfo *)node->data,"respect-parenthesis");
4380 if (value != (const char *) NULL)
4381 option="}";
4382 else
4383 return;
4384 }
4385 else
4386 return;
4387 }
4388 if (LocaleCompare(option,"}") == 0)
4389 {
4390 /* pop image_info settings from stack */
4391 Stack
4392 *node;
4393
4394 node = (void *)cli_wand->image_info_stack;
4395 if ( node == (Stack *)NULL)
4396 {
4397 ThrowMagickException(exception,GetMagickModule(),
4398 OptionError,"UnbalancedParenthesis", option);
4399 return;
4400 }
4401 cli_wand->image_info_stack = node->next;
4402
4403 (void) DestroyImageInfo(cli_wand->wand.image_info);
4404 cli_wand->wand.image_info = (ImageInfo *)node->data;
4405 node = (Stack *)RelinquishMagickMemory(node);
4406
4407 GetDrawInfo(cli_wand->wand.image_info, cli_wand->draw_info);
4408 cli_wand->quantize_info=DestroyQuantizeInfo(cli_wand->quantize_info);
4409 cli_wand->quantize_info=AcquireQuantizeInfo(cli_wand->wand.image_info);
4410
4411 return;
4412 }
4413 if (LocaleCompare(option+1,"clone") == 0)
4414 {
4415 Image
4416 *new_images;
4417
4418 if (*option == '+')
4419 arg="-1";
4420 if (IsSceneGeometry(arg,MagickFalse) == MagickFalse)
4421 {
4422 ThrowMagickException(exception,GetMagickModule(),
4423 OptionError,"InvalidArgument", "'%s': %s", option, arg);
4424 return;
4425 }
4426 if ( cli_wand->image_list_stack == (Stack *)NULL)
4427 {
4428 ThrowMagickException(exception,GetMagickModule(),
4429 OptionError,"UnableToCloneImage", option);
4430 return;
4431 }
4432 new_images = (Image *)cli_wand->image_list_stack->data;
4433 if (new_images == (Image *) NULL)
4434 {
4435 ThrowMagickException(exception,GetMagickModule(),
4436 OptionError,"UnableToCloneImage", option);
4437 return;
4438 }
4439 new_images=CloneImages(new_images,arg,exception);
4440 if (new_images == (Image *) NULL)
4441 {
4442 ThrowMagickException(exception,GetMagickModule(),
4443 OptionError,"NoSuchImage",option);
4444 return;
4445 }
4446 AppendImageToList(&cli_wand->wand.images,new_images);
4447 return;
4448 }
4449 if ( LocaleCompare("-read",option) == 0 )
4450 {
anthony2052d272012-02-28 12:48:29 +00004451#if 0
anthony43f425d2012-02-26 12:58:58 +00004452 Image *
4453 new_images;
4454
4455 CopyMagickString(cli_wand->wand.image_info->filename,arg,MaxTextExtent);
4456 if (cli_wand->wand.image_info->ping != MagickFalse)
4457 new_images=PingImages(cli_wand->wand.image_info,exception);
4458 else
4459 new_images=ReadImages(cli_wand->wand.image_info,exception);
4460 AppendImageToList(&cli_wand->wand.images, new_images);
4461#else
4462 /* read images using MagickWand method - no ping */
4463 /* This is not working! - it locks up in a CPU loop! */
4464 MagickSetLastIterator(&cli_wand->wand);
4465 MagickReadImage(&cli_wand->wand,arg);
4466 MagickSetFirstIterator(&cli_wand->wand);
4467#endif
4468 return;
4469 }
4470 if (LocaleCompare("-noop",option) == 0)
4471 return;
4472 if (LocaleCompare("-sans",option) == 0)
4473 return;
4474 if (LocaleCompare("-sans0",option) == 0)
4475 return;
4476 if (LocaleCompare("-sans2",option) == 0)
4477 return;
4478 if (LocaleCompare("-list",option) == 0)
4479 {
4480 /* FUTURE: This should really be built into the MagickCore
4481 It does not actually require any wand or images at all!
4482 */
4483 ssize_t
4484 list;
4485
4486 list=ParseCommandOption(MagickListOptions,MagickFalse, arg);
4487 switch (list)
4488 {
4489 case MagickCoderOptions:
4490 {
4491 (void) ListCoderInfo((FILE *) NULL,exception);
4492 break;
4493 }
4494 case MagickColorOptions:
4495 {
4496 (void) ListColorInfo((FILE *) NULL,exception);
4497 break;
4498 }
4499 case MagickConfigureOptions:
4500 {
4501 (void) ListConfigureInfo((FILE *) NULL,exception);
4502 break;
4503 }
4504 case MagickDelegateOptions:
4505 {
4506 (void) ListDelegateInfo((FILE *) NULL,exception);
4507 break;
4508 }
4509 case MagickFontOptions:
4510 {
4511 (void) ListTypeInfo((FILE *) NULL,exception);
4512 break;
4513 }
4514 case MagickFormatOptions:
4515 (void) ListMagickInfo((FILE *) NULL,exception);
4516 break;
4517 case MagickLocaleOptions:
4518 (void) ListLocaleInfo((FILE *) NULL,exception);
4519 break;
4520 case MagickLogOptions:
4521 (void) ListLogInfo((FILE *) NULL,exception);
4522 break;
4523 case MagickMagicOptions:
4524 (void) ListMagicInfo((FILE *) NULL,exception);
4525 break;
4526 case MagickMimeOptions:
4527 (void) ListMimeInfo((FILE *) NULL,exception);
4528 break;
4529 case MagickModuleOptions:
4530 (void) ListModuleInfo((FILE *) NULL,exception);
4531 break;
4532 case MagickPolicyOptions:
4533 (void) ListPolicyInfo((FILE *) NULL,exception);
4534 break;
4535 case MagickResourceOptions:
4536 (void) ListMagickResourceInfo((FILE *) NULL,exception);
4537 break;
4538 case MagickThresholdOptions:
4539 (void) ListThresholdMaps((FILE *) NULL,exception);
4540 break;
4541 default:
4542 (void) ListCommandOptions((FILE *) NULL,(CommandOption) list,
4543 exception);
4544 break;
4545 }
4546 return;
4547 }
4548
4549#if 0
4550 // adjust stack handling
4551 // Other 'special' options this should handle
4552 // "region" "list" "version"
4553 // It does not do "exit" however as due to its side-effect requirements
4554#endif
4555#if 0
4556 if ( ( process_flags & ProcessUnknownOptionError ) != 0 )
4557 MagickExceptionReturn(OptionError,"InvalidUseOfOption",option);
4558#endif
4559
4560#undef image_info
4561#undef images
4562#undef exception
4563}