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

Revision 6830, 18.4 KB checked in by anthony, 16 months ago (diff)

Adding initial development program of "magick" comamnd

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 0
203
204      if ( count == -1 || flags == UndefinedOptionFlag ||
205           (flags & NonConvertOptionFlag) != 0 )
206        {
207          count = 0;
208#if MagickCommandDebug
209      (void) FormatLocaleFile(stderr, "CLI Non-Option: \"%s\"\n", option);
210#endif
211          if (IsCommandOption(option) == MagickFalse)
212            {
213              /* non-option -- treat as a image read */
214              MagickSpecialOption(wand,"-read",option);
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  /* FUTURE: in the following produce a better error report
281     -- Missing Output filename
282  */
283
284  assert(i!=(ssize_t)(argc-1));
285  option=argv[i];  /* the last argument - output filename! */
286
287#if MagickCommandDebug
288  (void) FormatLocaleFile(stderr, "CLI Output: \"%s\"\n", option );
289#endif
290
291  // if stacks are not empty
292  //  ThrowConvertException(OptionError,"UnbalancedParenthesis",option,i);
293
294
295  /* This is the only value 'do no write' option for a CLI */
296  if (LocaleCompare(option,"-exit") == 0 )
297    return;  /* just exit, no image write */
298
299  /* If there is an option -- produce an error */
300  if (IsCommandOption(option) != MagickFalse)
301    MagickExceptionReturn(OptionError,"MissingAnImageFilename",option,i);
302
303  /* If no images */
304  if ( wand->images == (Image *) NULL )
305    {
306      /* a "null:" output coder with no images is ok */
307      if ( LocaleCompare(option,"null:") == 0 )
308        return;
309      MagickExceptionReturn(OptionError,"MissingAnImageFilename",option,i);
310    }
311
312  /*
313     Write out final image!
314  */
315  //WandListOperatorImages(wand,MagickFalse,"write",option,(const char *)NULL);
316  (void) SyncImagesSettings(wand->image_info,wand->images,wand->exception);
317  (void) WriteImages(wand->image_info,wand->images,option,wand->exception);
318
319  return;
320}
321
322/*
323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324%                                                                             %
325%                                                                             %
326%                                                                             %
327+   M a g i c k I m a g e C o m m a n d                                       %
328%                                                                             %
329%                                                                             %
330%                                                                             %
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332%
333%  MagickImageCommand() Handle special 'once only' CLI arguments and
334%  prepare to process the command line using a special CLI Magick Wand
335%  via the MagickImageProcess() function.
336%
337%  The format of the MagickImageCommand method is:
338%
339%      MagickBooleanType MagickImageCommand(ImageInfo *image_info,
340%           int argc, char **argv, char **metadata, ExceptionInfo *exception)
341%
342%  A description of each parameter follows:
343%
344%    o image_info: the starting image_info structure
345%         (for compatibilty with MagickCommandGenisis())
346%
347%    o argc: the number of elements in the argument vector.
348%
349%    o argv: A text array containing the command line arguments.
350%
351%    o metadata: any metadata is returned here.
352%         (for compatibilty with MagickCommandGenisis())
353%
354%    o exception: return any errors or warnings in this structure.
355%
356*/
357
358static MagickBooleanType MagickUsage(void)
359{
360  printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
361  printf("Copyright: %s\n",GetMagickCopyright());
362  printf("Features: %s\n\n",GetMagickFeatures());
363  printf("\n");
364
365  printf("Usage: %s [(options|images) ...] output_image\n", GetClientName());
366  printf("       %s -script filename [script args...]\n", GetClientName());
367  printf("       ... | %s -script - | ...\n", GetClientName());
368  printf("\n");
369
370  printf("  For more information on usage, options, examples, and technqiues\n");
371  printf("  see the ImageMagick website at\n    %s\n", MagickAuthoritativeURL);
372  printf("  Or the web pages in ImageMagick Sources\n");
373  return(MagickFalse);
374}
375
376/*
377   Concatanate given file arguments to the given output argument.
378   Used for a special -concatenate option used for specific 'delegates'.
379   The option is not formally documented.
380
381      magick -concatenate files... output
382
383   This is much like the UNIX "cat" command, but for both UNIX and Windows,
384   however the last argument provides the output filename.
385*/
386#define ThrowFileException(exception,severity,tag,context) \
387{ \
388  char \
389    *message; \
390 \
391  message=GetExceptionMessage(errno); \
392  (void) ThrowMagickException(exception,GetMagickModule(),severity, \
393    tag == (const char *) NULL ? "unknown" : tag,"`%s': %s",context,message); \
394  message=DestroyString(message); \
395}
396
397static MagickBooleanType ConcatenateImages(int argc,char **argv,
398  ExceptionInfo *exception)
399{
400  FILE
401    *input,
402    *output;
403
404  int
405    c;
406
407  register ssize_t
408    i;
409
410  output=fopen_utf8(argv[argc-1],"wb");
411  if (output == (FILE *) NULL)
412    {
413      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
414        argv[argc-1]);
415      return(MagickFalse);
416    }
417  for (i=2; i < (ssize_t) (argc-1); i++)
418  {
419    input=fopen_utf8(argv[i],"rb");
420    if (input == (FILE *) NULL)
421      ThrowFileException(exception,FileOpenError,"UnableToOpenFile",argv[i]);
422    for (c=fgetc(input); c != EOF; c=fgetc(input))
423      (void) fputc((char) c,output);
424    (void) fclose(input);
425    (void) remove_utf8(argv[i]);
426  }
427  (void) fclose(output);
428  return(MagickTrue);
429}
430
431WandExport MagickBooleanType MagickImageCommand(ImageInfo *image_info,
432  int argc,char **argv,char **metadata,ExceptionInfo *exception)
433{
434  MagickWand
435    *wand;
436
437  const char
438    *option;
439
440  /* Handle special single use options */
441  if (argc == 2)
442    {
443      option=argv[1];
444      if ((LocaleCompare("-version",option+1) == 0) ||
445          (LocaleCompare("--version",option+1) == 0) )
446        {
447          (void) FormatLocaleFile(stdout,"Version: %s\n",
448            GetMagickVersion((size_t *) NULL));
449          (void) FormatLocaleFile(stdout,"Copyright: %s\n",
450            GetMagickCopyright());
451          (void) FormatLocaleFile(stdout,"Features: %s\n\n",
452            GetMagickFeatures());
453          return(MagickFalse);
454        }
455    }
456  if (argc < 3)
457    return(MagickUsage());
458  ReadCommandlLine(argc,&argv);
459#if 0
460  status=ExpandFilenames(&argc,&argv);
461  if (status == MagickFalse)
462    ThrowConvertException(ResourceLimitError,"MemoryAllocationFailed",
463      GetExceptionMessage(errno));
464#endif
465  if (LocaleCompare("-concatenate",argv[1]) == 0)
466    return(ConcatenateImages(argc,argv,exception));
467
468  /* create a special CLI Wand to hold all working settings */
469  /* FUTURE: add this to 'operations.c' */
470  wand=NewMagickWand();
471  wand->image_info=DestroyImageInfo(wand->image_info);
472  wand->image_info=image_info;
473  wand->exception=DestroyExceptionInfo(wand->exception);
474  wand->exception=exception;
475  wand->draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
476  wand->quantize_info=AcquireQuantizeInfo(image_info);
477
478  if (LocaleCompare("-list",argv[1]) == 0)
479    WandSettingOptionInfo(wand, argv[1]+1, argv[2]);
480  else
481    MagickCommandProcessOptions(wand,argc,argv);
482
483  assert(wand->exception == exception);
484  assert(wand->image_info == image_info);
485
486  /* Handle metadata for ImageMagickObject COM object for Windows VBS */
487  if (metadata != (char **) NULL)
488    {
489      const char
490        *format;
491
492      char
493        *text;
494
495      format="%w,%h,%m";   // Get this from image_info Option splaytree
496
497      text=InterpretImageProperties(image_info,wand->images,format,exception);
498      if (text == (char *) NULL)
499        ThrowMagickException(exception,GetMagickModule(),ResourceLimitError,
500             "MemoryAllocationFailed","`%s'", GetExceptionMessage(errno));
501      else
502        {
503          (void) ConcatenateString(&(*metadata),text);
504          text=DestroyString(text);
505        }
506    }
507
508  /* Destroy the special CLI Wand */
509  wand->exception = (ExceptionInfo *)NULL;
510  wand->image_info = (ImageInfo *)NULL;
511  wand=DestroyMagickWand(wand);
512
513  return((exception->severity > ErrorException) ? MagickFalse : MagickTrue);
514}
Note: See TracBrowser for help on using the repository browser.