source: ImageMagick/trunk/MagickWand/magick-cli.c @ 6832

Revision 6832, 18.4 KB checked in by anthony, 15 months ago (diff)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                 M   M   AAA    GGGG  IIIII   CCCC  K   K                    %
7%                 MM MM  A   A  G        I    C      K  K                     %
8%                 M M M  AAAAA  G GGG    I    C      KKK                      %
9%                 M   M  A   A  G   G    I    C      K  K                     %
10%                 M   M  A   A   GGGG  IIIII   CCCC  K   K                    %
11%                                                                             %
12%                            CCCC  L      IIIII                               %
13%                           C      L        I                                 %
14%                           C      L        I                                 %
15%                           C      L        I                                 %
16%                            CCCC  LLLLL  IIIII                               %
17%                                                                             %
18%       Perform "Magick" on Images via the Command Line Interface             %
19%                                                                             %
20%                             Dragon Computing                                %
21%                             Anthony Thyssen                                 %
22%                               January 2012                                  %
23%                                                                             %
24%                                                                             %
25%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
26%  dedicated to making software imaging solutions freely available.           %
27%                                                                             %
28%  You may not use this file except in compliance with the License.  You may  %
29%  obtain a copy of the License at                                            %
30%                                                                             %
31%    http://www.imagemagick.org/script/license.php                            %
32%                                                                             %
33%  Unless required by applicable law or agreed to in writing, software        %
34%  distributed under the License is distributed on an "AS IS" BASIS,          %
35%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
36%  See the License for the specific language governing permissions and        %
37%  limitations under the License.                                             %
38%                                                                             %
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40%
41%  Read CLI arguments, script files, and pipelines, to provide options that
42%  manipulate images from many different formats.
43%
44*/
45
46/*
47  Include declarations.
48*/
49#include "MagickWand/studio.h"
50#include "MagickWand/MagickWand.h"
51#include "MagickWand/magick-wand-private.h"
52#include "MagickWand/operation.h"
53#include "MagickCore/version.h"
54#include "MagickCore/string-private.h"
55#include "MagickCore/utility-private.h"
56
57/*
58%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59%                                                                             %
60%                                                                             %
61%                                                                             %
62+   M a g i c k C o m m a n d S p e c i a l                                   %
63%                                                                             %
64%                                                                             %
65%                                                                             %
66%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67%
68%  MagickS() Reads the various reads various options defining how
69%  to read, process and write images. The options can be sourced from the
70%  command line, or from script files, or pipelines.
71%
72%  Processing is performed using stack of expanded 'Wand' structures, which
73%  not only define 'image_info' store of current global options, but also the
74%  current input source of the options.
75%
76%  The format of the MagickImageCommand method is:
77%
78%      void MagickSpecialOption(MagickWand *wand,
79%               const char *option, const char *arg)
80%
81%  A description of each parameter follows:
82%
83%    o wand: the main CLI Wand to use.
84%
85%    o option: The special option (with any switch char) to process
86%
87%    o arg: Argument for option, if required
88%
89*/
90WandExport void MagickSpecialOption(MagickWand *wand,
91     const char *option, const char *arg)
92{
93  if (LocaleCompare("-read",option) == 0)
94    {
95#if 1
96      /* MagickCore style of Read */
97      Image *
98        new_images;
99
100      CopyMagickString(wand->image_info->filename,arg,MaxTextExtent);
101      if (wand->image_info->ping != MagickFalse)
102        new_images=PingImages(wand->image_info,wand->exception);
103      else
104        new_images=ReadImages(wand->image_info,wand->exception);
105      AppendImageToList(&wand->images, new_images);
106#else
107      /* MagickWand style of Read - append new images -- FAILS */
108      MagickSetLastIterator(wand);
109      MagickReadImage(wand, arg);
110      MagickSetFirstIterator(wand);
111#endif
112      return;
113    }
114#if 0
115  if (LocaleCompare(option,"(") == 0)
116    // push images/settings
117  if (LocaleCompare(option,")") == 0)
118    // pop images/settings
119  if (LocaleCompare(option,"respect_parenthesis") == 0)
120    // adjust stack handling
121  // Other 'special' options this should handle
122  //    "region" "clone"  "list" "version" "noop" "sans*"?
123  // It does not do "exit" however as due to its side-effect requirements
124#endif
125}
126/*
127%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128%                                                                             %
129%                                                                             %
130%                                                                             %
131+   M a g i c k C o m m a n d P r o c e s s O p t i o n s                     %
132%                                                                             %
133%                                                                             %
134%                                                                             %
135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136%
137%  MagickCommandsProcessOptions() reads and processes arguments in the given
138%  command line argument array.
139%
140%  The format of the MagickImageCommand method is:
141%
142%      void MagickCommandArgs(MagickWand *wand,int argc,char **argv)
143%
144%  A description of each parameter follows:
145%
146%    o wand: the main CLI Wand to use.
147%
148%    o argc: the number of elements in the argument vector.
149%
150%    o argv: A text array containing the command line arguments.
151%
152*/
153#define MagickExceptionContinue(severity,tag,option,arg) \
154  (void) ThrowMagickException(wand->exception,GetMagickModule(),severity,tag, \
155       "'%s' arg#%lu", option, (unsigned long)arg)
156#define MagickExceptionReturn(severity,tag,option,arg) \
157{ \
158  MagickExceptionContinue(severity,tag,option,arg); \
159  return; \
160}
161
162WandExport void MagickCommandProcessOptions(MagickWand *wand,int argc,
163     char **argv)
164{
165  const char
166    *option,
167    *arg1,
168    *arg2;
169
170  MagickBooleanType
171    plus_alt_op;
172
173  ssize_t
174    i,
175    count;
176
177  CommandOptionFlags
178    flags;
179
180  assert(wand != (MagickWand *) NULL);
181  assert(wand->signature == WandSignature);
182  assert(wand->draw_info != (DrawInfo *) NULL); /* ensure it is a CLI wand */
183  if (wand->debug != MagickFalse)
184    (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",wand->name);
185
186  /*
187    Parse command-line options.
188  */
189  count=0;
190  for (i=1; i < (ssize_t) (argc-1); i+=count+1)
191    {
192      option=argv[i];
193      plus_alt_op = MagickFalse;
194      arg1=(char *)NULL;
195      arg2=(char *)NULL;
196
197      /* FUTURE: merge these into one call */
198      count=ParseCommandOption(MagickCommandOptions,MagickFalse,argv[i]);
199      flags=(CommandOptionFlags) GetCommandOptionFlags(
200                   MagickCommandOptions,MagickFalse,argv[i]);
201
202#define MagickCommandDebug 1
203
204      if ( count == -1 || flags == UndefinedOptionFlag ||
205           (flags & NonConvertOptionFlag) != 0 )
206        {
207#if MagickCommandDebug
208          (void) FormatLocaleFile(stderr, "CLI Non-Option: \"%s\"\n", option);
209#endif
210          if (IsCommandOption(option) == MagickFalse)
211            {
212              /* non-option -- treat as a image read */
213              MagickSpecialOption(wand,"-read",option);
214              count = 0;
215              continue;
216            }
217          else
218            MagickExceptionReturn(OptionError,"UnrecognizedOption",option,i);
219        }
220
221      if ( (flags & DeprecateOptionFlag) != 0 )
222        MagickExceptionContinue(OptionWarning,"DeprecatedOption",option,i);
223        /* continue processing option anyway */
224
225      if ((i+count) > (ssize_t) (argc-1))
226        MagickExceptionReturn(OptionError,"MissingArgument",option,i);
227      if (*option=='+') plus_alt_op = MagickTrue;
228      if (*option!='+') arg1 = "true";
229      if ( count >= 1 ) arg1 = argv[i+1];
230      if ( count >= 2 ) arg2 = argv[i+2];
231
232#if MagickCommandDebug
233      (void) FormatLocaleFile(stderr,
234          "CLI Option: \"%s\" \tCount: %d  Flags: %04x Args: \"%s\" \"%s\"\n",
235          option,count,flags,arg1,arg2);
236#endif
237
238      if ( (flags & SpecialOptionFlag) != 0 )
239        {
240          if (LocaleCompare(option,"-exit") == 0)
241            return;
242#if 0
243          if (LocaleCompare(option,"-script") == 0)
244            {
245              // Unbalanced Parenthesis if stack not empty
246              // Call Script, with filename as argv[0]
247              return;
248            }
249#endif
250          MagickSpecialOption(wand,option,arg1);
251        }
252
253      if ( (flags & SettingOptionFlags) != 0 )
254        {
255          WandSettingOptionInfo(wand, option+1, arg1);
256          // FUTURE: Sync Specific Settings into Images
257        }
258
259      if ( (flags & SimpleOperatorOptionFlag) != 0)
260        {
261          WandSimpleOperatorImages(wand, plus_alt_op, option+1, arg1, arg2);
262        }
263
264      if ( (flags & ListOperatorOptionFlag) != 0 )
265        {
266          WandListOperatorImages(wand, plus_alt_op, option+1, arg1, arg2);
267        }
268
269      // FUTURE: '-regard_warning' causes IM to exit more prematurely!
270      // Note pipelined options may like more control over this level
271      if (wand->exception->severity > ErrorException)
272        {
273          if (wand->exception->severity > ErrorException)
274              //(regard_warnings != MagickFalse))
275            return;                        /* FATAL - let caller handle */
276          CatchException(wand->exception); /* output warnings and clear!!! */
277        }
278    }
279
280  assert(i==(ssize_t)(argc-1));
281  option=argv[i];  /* the last argument - output filename! */
282#if MagickCommandDebug
283  (void) FormatLocaleFile(stderr, "CLI Output: \"%s\"\n", option );
284#endif
285
286  // if stacks are not empty
287  //  ThrowConvertException(OptionError,"UnbalancedParenthesis",option,i);
288
289  /* FUTURE: in the following produce a better error report
290     -- Missing Output filename
291  */
292
293
294  /* This is the only value 'do no write' option for a CLI */
295  if (LocaleCompare(option,"-exit") == 0 )
296    return;  /* just exit, no image write */
297
298  /* If there is an option -- produce an error */
299  if (IsCommandOption(option) != MagickFalse)
300    MagickExceptionReturn(OptionError,"MissingAnImageFilename",option,i);
301
302  /* If no images */
303  if ( wand->images == (Image *) NULL )
304    {
305      /* a "null:" output coder with no images is ok */
306      if ( LocaleCompare(option,"null:") == 0 )
307        return;
308      MagickExceptionReturn(OptionError,"MissingAnImageFilename",option,i);
309    }
310
311  /*
312     Write out final image!
313  */
314  //WandListOperatorImages(wand,MagickFalse,"write",option,(const char *)NULL);
315  (void) SyncImagesSettings(wand->image_info,wand->images,wand->exception);
316  (void) WriteImages(wand->image_info,wand->images,option,wand->exception);
317
318  return;
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323%                                                                             %
324%                                                                             %
325%                                                                             %
326+   M a g i c k I m a g e C o m m a n d                                       %
327%                                                                             %
328%                                                                             %
329%                                                                             %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332%  MagickImageCommand() Handle special 'once only' CLI arguments and
333%  prepare to process the command line using a special CLI Magick Wand
334%  via the MagickImageProcess() function.
335%
336%  The format of the MagickImageCommand method is:
337%
338%      MagickBooleanType MagickImageCommand(ImageInfo *image_info,
339%           int argc, char **argv, char **metadata, ExceptionInfo *exception)
340%
341%  A description of each parameter follows:
342%
343%    o image_info: the starting image_info structure
344%         (for compatibilty with MagickCommandGenisis())
345%
346%    o argc: the number of elements in the argument vector.
347%
348%    o argv: A text array containing the command line arguments.
349%
350%    o metadata: any metadata is returned here.
351%         (for compatibilty with MagickCommandGenisis())
352%
353%    o exception: return any errors or warnings in this structure.
354%
355*/
356
357static MagickBooleanType MagickUsage(void)
358{
359  printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
360  printf("Copyright: %s\n",GetMagickCopyright());
361  printf("Features: %s\n\n",GetMagickFeatures());
362  printf("\n");
363
364  printf("Usage: %s [(options|images) ...] output_image\n", GetClientName());
365  printf("       %s -script filename [script args...]\n", GetClientName());
366  printf("       ... | %s -script - | ...\n", GetClientName());
367  printf("\n");
368
369  printf("  For more information on usage, options, examples, and technqiues\n");
370  printf("  see the ImageMagick website at\n    %s\n", MagickAuthoritativeURL);
371  printf("  Or the web pages in ImageMagick Sources\n");
372  return(MagickFalse);
373}
374
375/*
376   Concatanate given file arguments to the given output argument.
377   Used for a special -concatenate option used for specific 'delegates'.
378   The option is not formally documented.
379
380      magick -concatenate files... output
381
382   This is much like the UNIX "cat" command, but for both UNIX and Windows,
383   however the last argument provides the output filename.
384*/
385#define ThrowFileException(exception,severity,tag,context) \
386{ \
387  char \
388    *message; \
389 \
390  message=GetExceptionMessage(errno); \
391  (void) ThrowMagickException(exception,GetMagickModule(),severity, \
392    tag == (const char *) NULL ? "unknown" : tag,"`%s': %s",context,message); \
393  message=DestroyString(message); \
394}
395
396static MagickBooleanType ConcatenateImages(int argc,char **argv,
397  ExceptionInfo *exception)
398{
399  FILE
400    *input,
401    *output;
402
403  int
404    c;
405
406  register ssize_t
407    i;
408
409  output=fopen_utf8(argv[argc-1],"wb");
410  if (output == (FILE *) NULL)
411    {
412      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
413        argv[argc-1]);
414      return(MagickFalse);
415    }
416  for (i=2; i < (ssize_t) (argc-1); i++)
417  {
418    input=fopen_utf8(argv[i],"rb");
419    if (input == (FILE *) NULL)
420      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
421    for (c=fgetc(input); c != EOF; c=fgetc(input))
422      (void) fputc((char) c,output);
423    (void) fclose(input);
424    (void) remove_utf8(argv[i]);
425  }
426  (void) fclose(output);
427  return(MagickTrue);
428}
429
430WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
431  int argc,char **argv,char **metadata,ExceptionInfo *exception)
432{
433  MagickWand
434    *wand;
435
436  const char
437    *option;
438
439  /* Handle special single use options */
440  if (argc == 2)
441    {
442      option=argv[1];
443      if ((LocaleCompare("-version",option+1) == 0) ||
444          (LocaleCompare("--version",option+1) == 0) )
445        {
446          (void) FormatLocaleFile(stdout,"Version: %s\n",
447            GetMagickVersion((size_t *) NULL));
448          (void) FormatLocaleFile(stdout,"Copyright: %s\n",
449            GetMagickCopyright());
450          (void) FormatLocaleFile(stdout,"Features: %s\n\n",
451            GetMagickFeatures());
452          return(MagickFalse);
453        }
454    }
455  if (argc < 3)
456    return(MagickUsage());
457  ReadCommandlLine(argc,&argv);
458#if 0
459  status=ExpandFilenames(&argc,&argv);
460  if (status == MagickFalse)
461    ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed",
462      GetExceptionMessage(errno));
463#endif
464  if (LocaleCompare("-concatenate",argv[1]) == 0)
465    return(ConcatenateImages(argc,argv,exception));
466
467  /* create a special CLI Wand to hold all working settings */
468  /* FUTURE: add this to 'operations.c' */
469  wand=NewMagickWand();
470  wand->image_info=DestroyImageInfo(wand->image_info);
471  wand->image_info=image_info;
472  wand->exception=DestroyExceptionInfo(wand->exception);
473  wand->exception=exception;
474  wand->draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
475  wand->quantize_info=AcquireQuantizeInfo(image_info);
476
477  if (LocaleCompare("-list",argv[1]) == 0)
478    WandSettingOptionInfo(wand, argv[1]+1, argv[2]);
479  else
480    MagickCommandProcessOptions(wand,argc,argv);
481
482  assert(wand->exception == exception);
483  assert(wand->image_info == image_info);
484
485  /* Handle metadata for ImageMagickObject COM object for Windows VBS */
486  if (metadata != (char **) NULL)
487    {
488      const char
489        *format;
490
491      char
492        *text;
493
494      format="%w,%h,%m";   // Get this from image_info Option splaytree
495
496      text=InterpretImageProperties(image_info,wand->images,format,exception);
497      if (text == (char *) NULL)
498        ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
499             "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
500      else
501        {
502          (void) ConcatenateString(&(*metadata),text);
503          text=DestroyString(text);
504        }
505    }
506
507  /* Destroy the special CLI Wand */
508  wand->exception = (ExceptionInfo *)NULL;
509  wand->image_info = (ImageInfo *)NULL;
510  wand=DestroyMagickWand(wand);
511
512  return((exception->severity > ErrorException) ? MagickFalse : MagickTrue);
513}
Note: See TracBrowser for help on using the repository browser.