validate.c revision c96a1bac56d5eb7f6a4dc99d11aa22f5baeea03e
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                                                                             %
7%           V   V   AAA   L      IIIII  DDDD    AAA   TTTTT  EEEEE            %
8%           V   V  A   A  L        I    D   D  A   A    T    E                %
9%           V   V  AAAAA  L        I    D   D  AAAAA    T    EEE              %
10%            V V   A   A  L        I    D   D  A   A    T    E                %
11%             V    A   A  LLLLL  IIIII  DDDD   A   A    T    EEEEE            %
12%                                                                             %
13%                                                                             %
14%                        ImageMagick Validation Suite                         %
15%                                                                             %
16%                             Software Design                                 %
17%                               John Cristy                                   %
18%                               March 2001                                    %
19%                                                                             %
20%                                                                             %
21%  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
22%  dedicated to making software imaging solutions freely available.           %
23%                                                                             %
24%  You may not use this file except in compliance with the License.  You may  %
25%  obtain a copy of the License at                                            %
26%                                                                             %
27%    http://www.imagemagick.org/script/license.php                            %
28%                                                                             %
29%  Unless required by applicable law or agreed to in writing, software        %
30%  distributed under the License is distributed on an "AS IS" BASIS,          %
31%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32%  see the License for the specific language governing permissions and        %
33%  limitations under the License.                                             %
34%                                                                             %
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <ctype.h>
47#include <math.h>
48#include <locale.h>
49#include "MagickWand/MagickWand.h"
50#include "MagickCore/colorspace-private.h"
51#include "MagickCore/resource_.h"
52#include "MagickCore/string-private.h"
53#include "validate.h"
54
55/*
56%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57%                                                                             %
58%                                                                             %
59%                                                                             %
60%   V a l i d a t e C o m p a r e C o m m a n d                               %
61%                                                                             %
62%                                                                             %
63%                                                                             %
64%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65%
66%  ValidateCompareCommand() validates the ImageMagick compare command line
67%  program and returns the number of validation tests that passed and failed.
68%
69%  The format of the ValidateCompareCommand method is:
70%
71%      size_t ValidateCompareCommand(ImageInfo *image_info,
72%        const char *reference_filename,const char *output_filename,
73%        size_t *fail,ExceptionInfo *exception)
74%
75%  A description of each parameter follows:
76%
77%    o image_info: the image info.
78%
79%    o reference_filename: the reference image filename.
80%
81%    o output_filename: the output image filename.
82%
83%    o fail: return the number of validation tests that pass.
84%
85%    o exception: return any errors or warnings in this structure.
86%
87*/
88static size_t ValidateCompareCommand(ImageInfo *image_info,
89  const char *reference_filename,const char *output_filename,size_t *fail,
90  ExceptionInfo *exception)
91{
92  char
93    **arguments,
94    command[MaxTextExtent];
95
96  int
97    number_arguments;
98
99  MagickBooleanType
100    status;
101
102  register ssize_t
103    i,
104    j;
105
106  size_t
107    test;
108
109  test=0;
110  (void) FormatLocaleFile(stdout,"validate compare command line program:\n");
111  for (i=0; compare_options[i] != (char *) NULL; i++)
112  {
113    CatchException(exception);
114    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
115      compare_options[i]);
116    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
117      compare_options[i],reference_filename,reference_filename,output_filename);
118    arguments=StringToArgv(command,&number_arguments);
119    if (arguments == (char **) NULL)
120      {
121        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
122          GetMagickModule());
123        (*fail)++;
124        continue;
125      }
126    status=CompareImagesCommand(image_info,number_arguments,arguments,
127      (char **) NULL,exception);
128    for (j=0; j < (ssize_t) number_arguments; j++)
129      arguments[j]=DestroyString(arguments[j]);
130    arguments=(char **) RelinquishMagickMemory(arguments);
131    if (status != MagickFalse)
132      {
133        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
134          GetMagickModule());
135        (*fail)++;
136        continue;
137      }
138    (void) FormatLocaleFile(stdout,"... pass.\n");
139  }
140  (void) FormatLocaleFile(stdout,
141    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
142    (double) (test-(*fail)),(double) *fail);
143  return(test);
144}
145
146/*
147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148%                                                                             %
149%                                                                             %
150%                                                                             %
151%   V a l i d a t e C o m p o s i t e C o m m a n d                           %
152%                                                                             %
153%                                                                             %
154%                                                                             %
155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156%
157%  ValidateCompositeCommand() validates the ImageMagick composite command line
158%  program and returns the number of validation tests that passed and failed.
159%
160%  The format of the ValidateCompositeCommand method is:
161%
162%      size_t ValidateCompositeCommand(ImageInfo *image_info,
163%        const char *reference_filename,const char *output_filename,
164%        size_t *fail,ExceptionInfo *exception)
165%
166%  A description of each parameter follows:
167%
168%    o image_info: the image info.
169%
170%    o reference_filename: the reference image filename.
171%
172%    o output_filename: the output image filename.
173%
174%    o fail: return the number of validation tests that pass.
175%
176%    o exception: return any errors or warnings in this structure.
177%
178*/
179static size_t ValidateCompositeCommand(ImageInfo *image_info,
180  const char *reference_filename,const char *output_filename,size_t *fail,
181  ExceptionInfo *exception)
182{
183  char
184    **arguments,
185    command[MaxTextExtent];
186
187  int
188    number_arguments;
189
190  MagickBooleanType
191    status;
192
193  register ssize_t
194    i,
195    j;
196
197  size_t
198    test;
199
200  test=0;
201  (void) FormatLocaleFile(stdout,"validate composite command line program:\n");
202  for (i=0; composite_options[i] != (char *) NULL; i++)
203  {
204    CatchException(exception);
205    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
206      composite_options[i]);
207    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
208      reference_filename,composite_options[i],reference_filename,
209      output_filename);
210    arguments=StringToArgv(command,&number_arguments);
211    if (arguments == (char **) NULL)
212      {
213        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
214          GetMagickModule());
215        (*fail)++;
216        continue;
217      }
218    status=CompositeImageCommand(image_info,number_arguments,arguments,
219      (char **) NULL,exception);
220    for (j=0; j < (ssize_t) number_arguments; j++)
221      arguments[j]=DestroyString(arguments[j]);
222    arguments=(char **) RelinquishMagickMemory(arguments);
223    if (status != MagickFalse)
224      {
225        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
226          GetMagickModule());
227        (*fail)++;
228        continue;
229      }
230    (void) FormatLocaleFile(stdout,"... pass.\n");
231  }
232  (void) FormatLocaleFile(stdout,
233    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
234    (double) (test-(*fail)),(double) *fail);
235  return(test);
236}
237
238/*
239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240%                                                                             %
241%                                                                             %
242%                                                                             %
243%   V a l i d a t e C o n v e r t C o m m a n d                               %
244%                                                                             %
245%                                                                             %
246%                                                                             %
247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248%
249%  ValidateConvertCommand() validates the ImageMagick convert command line
250%  program and returns the number of validation tests that passed and failed.
251%
252%  The format of the ValidateConvertCommand method is:
253%
254%      size_t ValidateConvertCommand(ImageInfo *image_info,
255%        const char *reference_filename,const char *output_filename,
256%        size_t *fail,ExceptionInfo *exception)
257%
258%  A description of each parameter follows:
259%
260%    o image_info: the image info.
261%
262%    o reference_filename: the reference image filename.
263%
264%    o output_filename: the output image filename.
265%
266%    o fail: return the number of validation tests that pass.
267%
268%    o exception: return any errors or warnings in this structure.
269%
270*/
271static size_t ValidateConvertCommand(ImageInfo *image_info,
272  const char *reference_filename,const char *output_filename,size_t *fail,
273  ExceptionInfo *exception)
274{
275  char
276    **arguments,
277    command[MaxTextExtent];
278
279  int
280    number_arguments;
281
282  MagickBooleanType
283    status;
284
285  register ssize_t
286    i,
287    j;
288
289  size_t
290    test;
291
292  test=0;
293  (void) FormatLocaleFile(stdout,"validate convert command line program:\n");
294  for (i=0; convert_options[i] != (char *) NULL; i++)
295  {
296    CatchException(exception);
297    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
298      convert_options[i]);
299    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
300      reference_filename,convert_options[i],reference_filename,output_filename);
301    arguments=StringToArgv(command,&number_arguments);
302    if (arguments == (char **) NULL)
303      {
304        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
305          GetMagickModule());
306        (*fail)++;
307        continue;
308      }
309    status=ConvertImageCommand(image_info,number_arguments,arguments,
310      (char **) NULL,exception);
311    for (j=0; j < (ssize_t) number_arguments; j++)
312      arguments[j]=DestroyString(arguments[j]);
313    arguments=(char **) RelinquishMagickMemory(arguments);
314    if (status != MagickFalse)
315      {
316        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
317          GetMagickModule());
318        (*fail)++;
319        continue;
320      }
321    (void) FormatLocaleFile(stdout,"... pass.\n");
322  }
323  (void) FormatLocaleFile(stdout,
324    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
325    (double) (test-(*fail)),(double) *fail);
326  return(test);
327}
328
329/*
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%                                                                             %
332%                                                                             %
333%                                                                             %
334%   V a l i d a t e I d e n t i f y C o m m a n d                             %
335%                                                                             %
336%                                                                             %
337%                                                                             %
338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339%
340%  ValidateIdentifyCommand() validates the ImageMagick identify command line
341%  program and returns the number of validation tests that passed and failed.
342%
343%  The format of the ValidateIdentifyCommand method is:
344%
345%      size_t ValidateIdentifyCommand(ImageInfo *image_info,
346%        const char *reference_filename,const char *output_filename,
347%        size_t *fail,ExceptionInfo *exception)
348%
349%  A description of each parameter follows:
350%
351%    o image_info: the image info.
352%
353%    o reference_filename: the reference image filename.
354%
355%    o output_filename: the output image filename.
356%
357%    o fail: return the number of validation tests that pass.
358%
359%    o exception: return any errors or warnings in this structure.
360%
361*/
362static size_t ValidateIdentifyCommand(ImageInfo *image_info,
363  const char *reference_filename,const char *output_filename,size_t *fail,
364  ExceptionInfo *exception)
365{
366  char
367    **arguments,
368    command[MaxTextExtent];
369
370  int
371    number_arguments;
372
373  MagickBooleanType
374    status;
375
376  register ssize_t
377    i,
378    j;
379
380  size_t
381    test;
382
383  (void) output_filename;
384  test=0;
385  (void) FormatLocaleFile(stdout,"validate identify command line program:\n");
386  for (i=0; identify_options[i] != (char *) NULL; i++)
387  {
388    CatchException(exception);
389    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) test++,
390      identify_options[i]);
391    (void) FormatLocaleString(command,MaxTextExtent,"%s %s",
392      identify_options[i],reference_filename);
393    arguments=StringToArgv(command,&number_arguments);
394    if (arguments == (char **) NULL)
395      {
396        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
397          GetMagickModule());
398        (*fail)++;
399        continue;
400      }
401    status=IdentifyImageCommand(image_info,number_arguments,arguments,
402      (char **) NULL,exception);
403    for (j=0; j < (ssize_t) number_arguments; j++)
404      arguments[j]=DestroyString(arguments[j]);
405    arguments=(char **) RelinquishMagickMemory(arguments);
406    if (status != MagickFalse)
407      {
408        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
409          GetMagickModule());
410        (*fail)++;
411        continue;
412      }
413    (void) FormatLocaleFile(stdout,"... pass.\n");
414  }
415  (void) FormatLocaleFile(stdout,
416    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
417    (double) (test-(*fail)),(double) *fail);
418  return(test);
419}
420
421/*
422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423%                                                                             %
424%                                                                             %
425%                                                                             %
426%   V a l i d a t e I m a g e F o r m a t s I n M e m o r y                   %
427%                                                                             %
428%                                                                             %
429%                                                                             %
430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431%
432%  ValidateImageFormatsInMemory() validates the ImageMagick image formats in
433%  memory and returns the number of validation tests that passed and failed.
434%
435%  The format of the ValidateImageFormatsInMemory method is:
436%
437%      size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
438%        const char *reference_filename,const char *output_filename,
439%        size_t *fail,ExceptionInfo *exception)
440%
441%  A description of each parameter follows:
442%
443%    o image_info: the image info.
444%
445%    o reference_filename: the reference image filename.
446%
447%    o output_filename: the output image filename.
448%
449%    o fail: return the number of validation tests that pass.
450%
451%    o exception: return any errors or warnings in this structure.
452%
453*/
454
455/*
456  Enable this to count remaining $TMPDIR/magick-* files.  Note that the count
457  includes any files left over from other runs.
458*/
459#undef MagickCountTempFiles
460
461static size_t ValidateImageFormatsInMemory(ImageInfo *image_info,
462  const char *reference_filename,const char *output_filename,size_t *fail,
463  ExceptionInfo *exception)
464{
465  char
466#ifdef MagickCountTempFiles
467    SystemCommand[MaxTextExtent],
468    path[MaxTextExtent],
469#endif
470    size[MaxTextExtent];
471
472  const MagickInfo
473    *magick_info;
474
475  double
476    distortion,
477    fuzz;
478
479  Image
480    *difference_image,
481    *ping_image,
482    *reconstruct_image,
483    *reference_image;
484
485  MagickBooleanType
486    status;
487
488  register ssize_t
489    i,
490    j;
491
492  size_t
493    length,
494    test;
495
496  unsigned char
497    *blob;
498
499  test=0;
500  (void) FormatLocaleFile(stdout,"validate image formats in memory:\n");
501
502#ifdef MagickCountTempFiles
503  (void)GetPathTemplate(path);
504  /* Remove file template except for the leading "/path/to/magick-" */
505  path[strlen(path)-17]='\0';
506  (void) FormatLocaleFile(stdout," tmp path is '%s*'\n",path);
507#endif
508
509  for (i=0; reference_formats[i].magick != (char *) NULL; i++)
510  {
511    magick_info=GetMagickInfo(reference_formats[i].magick,exception);
512    if ((magick_info == (const MagickInfo *) NULL) ||
513        (magick_info->decoder == (DecodeImageHandler *) NULL) ||
514        (magick_info->encoder == (EncodeImageHandler *) NULL))
515      continue;
516    for (j=0; reference_types[j].type != UndefinedType; j++)
517    {
518      /*
519        Generate reference image.
520      */
521      CatchException(exception);
522      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
523        (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
524        MagickCompressOptions,reference_formats[i].compression),
525        CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
526        (double) reference_types[j].depth);
527      (void) CopyMagickString(image_info->filename,reference_filename,
528        MaxTextExtent);
529      reference_image=ReadImage(image_info,exception);
530      if (reference_image == (Image *) NULL)
531        {
532          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
533            GetMagickModule());
534          (*fail)++;
535          continue;
536        }
537      /*
538        Write reference image.
539      */
540      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",
541        (double) reference_image->columns,(double) reference_image->rows);
542      (void) CloneString(&image_info->size,size);
543      image_info->depth=reference_types[j].depth;
544      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
545        reference_formats[i].magick,output_filename);
546      status=SetImageType(reference_image,reference_types[j].type,exception);
547      if (status == MagickFalse)
548        {
549          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
550            GetMagickModule());
551          (*fail)++;
552          reference_image=DestroyImage(reference_image);
553          continue;
554        }
555      status=SetImageDepth(reference_image,reference_types[j].depth,exception);
556      if (status == MagickFalse)
557        {
558          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
559            GetMagickModule());
560          (*fail)++;
561          reference_image=DestroyImage(reference_image);
562          continue;
563        }
564      reference_image->compression=reference_formats[i].compression;
565      status=WriteImage(image_info,reference_image,exception);
566      reference_image=DestroyImage(reference_image);
567      if (status == MagickFalse)
568        {
569          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
570            GetMagickModule());
571          (*fail)++;
572          continue;
573        }
574      /*
575        Ping reference image.
576      */
577      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
578        reference_formats[i].magick,output_filename);
579      ping_image=PingImage(image_info,exception);
580      if (ping_image == (Image *) NULL)
581        {
582          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
583            GetMagickModule());
584          (*fail)++;
585          continue;
586        }
587      ping_image=DestroyImage(ping_image);
588      /*
589        Read reference image.
590      */
591      reference_image=ReadImage(image_info,exception);
592      if (reference_image == (Image *) NULL)
593        {
594          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
595            GetMagickModule());
596          (*fail)++;
597          continue;
598        }
599      /*
600        Write reference image.
601      */
602      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
603        reference_formats[i].magick,output_filename);
604      (void) CopyMagickString(image_info->magick,reference_formats[i].magick,
605        MaxTextExtent);
606      reference_image->depth=reference_types[j].depth;
607      reference_image->compression=reference_formats[i].compression;
608      length=8192;
609      blob=ImageToBlob(image_info,reference_image,&length,exception);
610      if (blob == (unsigned char *) NULL)
611        {
612          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
613            GetMagickModule());
614          (*fail)++;
615          reference_image=DestroyImage(reference_image);
616          continue;
617        }
618      /*
619        Ping reference blob.
620      */
621      ping_image=PingBlob(image_info,blob,length,exception);
622      if (ping_image == (Image *) NULL)
623        {
624          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
625            GetMagickModule());
626          (*fail)++;
627          blob=(unsigned char *) RelinquishMagickMemory(blob);
628          continue;
629        }
630      ping_image=DestroyImage(ping_image);
631      /*
632        Read reconstruct image.
633      */
634      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
635        reference_formats[i].magick,output_filename);
636      reconstruct_image=BlobToImage(image_info,blob,length,exception);
637      blob=(unsigned char *) RelinquishMagickMemory(blob);
638      if (reconstruct_image == (Image *) NULL)
639        {
640          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
641            GetMagickModule());
642          (*fail)++;
643          reference_image=DestroyImage(reference_image);
644          continue;
645        }
646      /*
647        Compare reference to reconstruct image.
648      */
649      fuzz=0.0;
650      if (reference_formats[i].fuzz != 0.0)
651        fuzz=reference_formats[i].fuzz;
652#if defined(MAGICKCORE_HDRI_SUPPORT)
653      fuzz+=0.003;
654#endif
655      if (IssRGBColorspace(reference_image->colorspace) == MagickFalse)
656        fuzz+=0.3;
657      fuzz+=MagickEpsilon;
658      difference_image=CompareImages(reference_image,reconstruct_image,
659        RootMeanSquaredErrorMetric,&distortion,exception);
660      reconstruct_image=DestroyImage(reconstruct_image);
661      reference_image=DestroyImage(reference_image);
662      if (difference_image == (Image *) NULL)
663        {
664          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
665            GetMagickModule());
666          (*fail)++;
667          continue;
668        }
669      difference_image=DestroyImage(difference_image);
670      if ((QuantumScale*distortion) > fuzz)
671        {
672          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
673            QuantumScale*distortion);
674          (*fail)++;
675          continue;
676        }
677#ifdef MagickCountTempFiles
678      (void) FormatLocaleFile(stdout,"... pass, ");
679      (void) fflush(stdout);
680      SystemCommand[0]='\0';
681      (void)strncat(SystemCommand,"echo `ls ",9);
682      (void)strncat(SystemCommand,path,MaxTextExtent-31);
683      (void)strncat(SystemCommand,"* | wc -w` tmp files.",20);
684      (void)system(SystemCommand);
685      (void) fflush(stdout);
686#else
687      (void) FormatLocaleFile(stdout,"... pass\n");
688#endif
689    }
690  }
691  (void) FormatLocaleFile(stdout,
692    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
693    (double) (test-(*fail)),(double) *fail);
694  return(test);
695}
696
697/*
698%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699%                                                                             %
700%                                                                             %
701%                                                                             %
702%   V a l i d a t e I m a g e F o r m a t s O n D i s k                       %
703%                                                                             %
704%                                                                             %
705%                                                                             %
706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
707%
708%  ValidateImageFormatsOnDisk() validates the ImageMagick image formats on disk
709%  and returns the number of validation tests that passed and failed.
710%
711%  The format of the ValidateImageFormatsOnDisk method is:
712%
713%      size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
714%        const char *reference_filename,const char *output_filename,
715%        size_t *fail,ExceptionInfo *exception)
716%
717%  A description of each parameter follows:
718%
719%    o image_info: the image info.
720%
721%    o reference_filename: the reference image filename.
722%
723%    o output_filename: the output image filename.
724%
725%    o fail: return the number of validation tests that pass.
726%
727%    o exception: return any errors or warnings in this structure.
728%
729*/
730static size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
731  const char *reference_filename,const char *output_filename,size_t *fail,
732  ExceptionInfo *exception)
733{
734  char
735    size[MaxTextExtent];
736
737  const MagickInfo
738    *magick_info;
739
740  double
741    distortion,
742    fuzz;
743
744  Image
745    *difference_image,
746    *reference_image,
747    *reconstruct_image;
748
749  MagickBooleanType
750    status;
751
752  register ssize_t
753    i,
754    j;
755
756  size_t
757    test;
758
759  test=0;
760  (void) FormatLocaleFile(stdout,"validate image formats on disk:\n");
761  for (i=0; reference_formats[i].magick != (char *) NULL; i++)
762  {
763    magick_info=GetMagickInfo(reference_formats[i].magick,exception);
764    if ((magick_info == (const MagickInfo *) NULL) ||
765        (magick_info->decoder == (DecodeImageHandler *) NULL) ||
766        (magick_info->encoder == (EncodeImageHandler *) NULL))
767      continue;
768    for (j=0; reference_types[j].type != UndefinedType; j++)
769    {
770      /*
771        Generate reference image.
772      */
773      CatchException(exception);
774      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
775        (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
776        MagickCompressOptions,reference_formats[i].compression),
777        CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
778        (double) reference_types[j].depth);
779      (void) CopyMagickString(image_info->filename,reference_filename,
780        MaxTextExtent);
781      reference_image=ReadImage(image_info,exception);
782      if (reference_image == (Image *) NULL)
783        {
784          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
785            GetMagickModule());
786          (*fail)++;
787          continue;
788        }
789      /*
790        Write reference image.
791      */
792      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",
793        (double) reference_image->columns,(double) reference_image->rows);
794      (void) CloneString(&image_info->size,size);
795      image_info->depth=reference_types[j].depth;
796      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
797        reference_formats[i].magick,output_filename);
798      status=SetImageType(reference_image,reference_types[j].type,exception);
799      if (status == MagickFalse)
800        {
801          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
802            GetMagickModule());
803          (*fail)++;
804          reference_image=DestroyImage(reference_image);
805          continue;
806        }
807      status=SetImageDepth(reference_image,reference_types[j].depth,exception);
808      if (status == MagickFalse)
809        {
810          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
811            GetMagickModule());
812          (*fail)++;
813          reference_image=DestroyImage(reference_image);
814          continue;
815        }
816      reference_image->compression=reference_formats[i].compression;
817      status=WriteImage(image_info,reference_image,exception);
818      reference_image=DestroyImage(reference_image);
819      if (status == MagickFalse)
820        {
821          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
822            GetMagickModule());
823          (*fail)++;
824          continue;
825        }
826      /*
827        Read reference image.
828      */
829      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
830        reference_formats[i].magick,output_filename);
831      reference_image=ReadImage(image_info,exception);
832      if (reference_image == (Image *) NULL)
833        {
834          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
835            GetMagickModule());
836          (*fail)++;
837          continue;
838        }
839      /*
840        Write reference image.
841      */
842      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
843        reference_formats[i].magick,output_filename);
844      reference_image->depth=reference_types[j].depth;
845      reference_image->compression=reference_formats[i].compression;
846      status=WriteImage(image_info,reference_image,exception);
847      if (status == MagickFalse)
848        {
849          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
850            GetMagickModule());
851          (*fail)++;
852          reference_image=DestroyImage(reference_image);
853          continue;
854        }
855      /*
856        Read reconstruct image.
857      */
858      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
859        reference_formats[i].magick,output_filename);
860      reconstruct_image=ReadImage(image_info,exception);
861      if (reconstruct_image == (Image *) NULL)
862        {
863          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
864            GetMagickModule());
865          (*fail)++;
866          reference_image=DestroyImage(reference_image);
867          continue;
868        }
869      /*
870        Compare reference to reconstruct image.
871      */
872      fuzz=0.0;
873      if (reference_formats[i].fuzz != 0.0)
874        fuzz=reference_formats[i].fuzz;
875#if defined(MAGICKCORE_HDRI_SUPPORT)
876      fuzz+=0.003;
877#endif
878      if (IssRGBColorspace(reference_image->colorspace) == MagickFalse)
879        fuzz+=0.3;
880      fuzz+=MagickEpsilon;
881      difference_image=CompareImages(reference_image,reconstruct_image,
882        RootMeanSquaredErrorMetric,&distortion,exception);
883      reconstruct_image=DestroyImage(reconstruct_image);
884      reference_image=DestroyImage(reference_image);
885      if (difference_image == (Image *) NULL)
886        {
887          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
888            GetMagickModule());
889          (*fail)++;
890          continue;
891        }
892      difference_image=DestroyImage(difference_image);
893      if ((QuantumScale*distortion) > fuzz)
894        {
895          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
896            QuantumScale*distortion);
897          (*fail)++;
898          continue;
899        }
900      (void) FormatLocaleFile(stdout,"... pass.\n");
901    }
902  }
903  (void) FormatLocaleFile(stdout,
904    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
905    (double) (test-(*fail)),(double) *fail);
906  return(test);
907}
908
909/*
910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911%                                                                             %
912%                                                                             %
913%                                                                             %
914%   V a l i d a t e I m p o r t E x p o r t P i x e l s                       %
915%                                                                             %
916%                                                                             %
917%                                                                             %
918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
919%
920%  ValidateImportExportPixels() validates the pixel import and export methods.
921%  It returns the number of validation tests that passed and failed.
922%
923%  The format of the ValidateImportExportPixels method is:
924%
925%      size_t ValidateImportExportPixels(ImageInfo *image_info,
926%        const char *reference_filename,const char *output_filename,
927%        size_t *fail,ExceptionInfo *exception)
928%
929%  A description of each parameter follows:
930%
931%    o image_info: the image info.
932%
933%    o reference_filename: the reference image filename.
934%
935%    o output_filename: the output image filename.
936%
937%    o fail: return the number of validation tests that pass.
938%
939%    o exception: return any errors or warnings in this structure.
940%
941*/
942static size_t ValidateImportExportPixels(ImageInfo *image_info,
943  const char *reference_filename,const char *output_filename,size_t *fail,
944  ExceptionInfo *exception)
945{
946  double
947    distortion;
948
949  Image
950    *difference_image,
951    *reference_image,
952    *reconstruct_image;
953
954  MagickBooleanType
955    status;
956
957  register ssize_t
958    i,
959    j;
960
961  size_t
962    length;
963
964  unsigned char
965    *pixels;
966
967  size_t
968    test;
969
970  (void) output_filename;
971  test=0;
972  (void) FormatLocaleFile(stdout,
973    "validate the import and export of image pixels:\n");
974  for (i=0; reference_map[i] != (char *) NULL; i++)
975  {
976    for (j=0; reference_storage[j].type != UndefinedPixel; j++)
977    {
978      /*
979        Generate reference image.
980      */
981      CatchException(exception);
982      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s",(double) (test++),
983        reference_map[i],CommandOptionToMnemonic(MagickStorageOptions,
984        reference_storage[j].type));
985      (void) CopyMagickString(image_info->filename,reference_filename,
986        MaxTextExtent);
987      reference_image=ReadImage(image_info,exception);
988      if (reference_image == (Image *) NULL)
989        {
990          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
991            GetMagickModule());
992          (*fail)++;
993          continue;
994        }
995      if (LocaleNCompare(reference_map[i],"cmy",3) == 0)
996        (void) SetImageColorspace(reference_image,CMYKColorspace,exception);
997      length=strlen(reference_map[i])*reference_image->columns*
998        reference_image->rows*reference_storage[j].quantum;
999      pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1000      if (pixels == (unsigned char *) NULL)
1001        {
1002          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1003            GetMagickModule());
1004          (*fail)++;
1005          reference_image=DestroyImage(reference_image);
1006          continue;
1007        }
1008      (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels));
1009      status=ExportImagePixels(reference_image,0,0,reference_image->columns,
1010        reference_image->rows,reference_map[i],reference_storage[j].type,pixels,
1011        exception);
1012      if (status == MagickFalse)
1013        {
1014          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1015            GetMagickModule());
1016          (*fail)++;
1017          pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1018          reference_image=DestroyImage(reference_image);
1019          continue;
1020        }
1021      (void) SetImageBackgroundColor(reference_image,exception);
1022      status=ImportImagePixels(reference_image,0,0,reference_image->columns,
1023        reference_image->rows,reference_map[i],reference_storage[j].type,
1024        pixels,exception);
1025      if (status == MagickFalse)
1026        {
1027          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1028            GetMagickModule());
1029          (*fail)++;
1030           pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1031          reference_image=DestroyImage(reference_image);
1032          continue;
1033        }
1034      /*
1035        Read reconstruct image.
1036      */
1037      reconstruct_image=AcquireImage(image_info,exception);
1038      (void) SetImageExtent(reconstruct_image,reference_image->columns,
1039        reference_image->rows,exception);
1040      (void) SetImageColorspace(reconstruct_image,reference_image->colorspace,
1041        exception);
1042      (void) SetImageBackgroundColor(reconstruct_image,exception);
1043      status=ImportImagePixels(reconstruct_image,0,0,reconstruct_image->columns,
1044        reconstruct_image->rows,reference_map[i],reference_storage[j].type,
1045        pixels,exception);
1046      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1047      if (status == MagickFalse)
1048        {
1049          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1050            GetMagickModule());
1051          (*fail)++;
1052          reference_image=DestroyImage(reference_image);
1053          continue;
1054        }
1055      /*
1056        Compare reference to reconstruct image.
1057      */
1058      difference_image=CompareImages(reference_image,reconstruct_image,
1059        RootMeanSquaredErrorMetric,&distortion,exception);
1060      reconstruct_image=DestroyImage(reconstruct_image);
1061      reference_image=DestroyImage(reference_image);
1062      if (difference_image == (Image *) NULL)
1063        {
1064          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1065            GetMagickModule());
1066          (*fail)++;
1067          continue;
1068        }
1069      difference_image=DestroyImage(difference_image);
1070      if ((QuantumScale*distortion) > 0.0)
1071        {
1072          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
1073            QuantumScale*distortion);
1074          (*fail)++;
1075          continue;
1076        }
1077      (void) FormatLocaleFile(stdout,"... pass.\n");
1078    }
1079  }
1080  (void) FormatLocaleFile(stdout,
1081    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1082    (double) (test-(*fail)),(double) *fail);
1083  return(test);
1084}
1085
1086/*
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088%                                                                             %
1089%                                                                             %
1090%                                                                             %
1091%   V a l i d a t e M o n t a g e C o m m a n d                               %
1092%                                                                             %
1093%                                                                             %
1094%                                                                             %
1095%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096%
1097%  ValidateMontageCommand() validates the ImageMagick montage command line
1098%  program and returns the number of validation tests that passed and failed.
1099%
1100%  The format of the ValidateMontageCommand method is:
1101%
1102%      size_t ValidateMontageCommand(ImageInfo *image_info,
1103%        const char *reference_filename,const char *output_filename,
1104%        size_t *fail,ExceptionInfo *exception)
1105%
1106%  A description of each parameter follows:
1107%
1108%    o image_info: the image info.
1109%
1110%    o reference_filename: the reference image filename.
1111%
1112%    o output_filename: the output image filename.
1113%
1114%    o fail: return the number of validation tests that pass.
1115%
1116%    o exception: return any errors or warnings in this structure.
1117%
1118*/
1119static size_t ValidateMontageCommand(ImageInfo *image_info,
1120  const char *reference_filename,const char *output_filename,size_t *fail,
1121  ExceptionInfo *exception)
1122{
1123  char
1124    **arguments,
1125    command[MaxTextExtent];
1126
1127  int
1128    number_arguments;
1129
1130  MagickBooleanType
1131    status;
1132
1133  register ssize_t
1134    i,
1135    j;
1136
1137  size_t
1138    test;
1139
1140  test=0;
1141  (void) FormatLocaleFile(stdout,"validate montage command line program:\n");
1142  for (i=0; montage_options[i] != (char *) NULL; i++)
1143  {
1144    CatchException(exception);
1145    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1146      montage_options[i]);
1147    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
1148      reference_filename,montage_options[i],reference_filename,
1149      output_filename);
1150    arguments=StringToArgv(command,&number_arguments);
1151    if (arguments == (char **) NULL)
1152      {
1153        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1154            GetMagickModule());
1155        (*fail)++;
1156        continue;
1157      }
1158    status=MontageImageCommand(image_info,number_arguments,arguments,
1159      (char **) NULL,exception);
1160    for (j=0; j < (ssize_t) number_arguments; j++)
1161      arguments[j]=DestroyString(arguments[j]);
1162    arguments=(char **) RelinquishMagickMemory(arguments);
1163    if (status != MagickFalse)
1164      {
1165        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1166            GetMagickModule());
1167        (*fail)++;
1168        continue;
1169      }
1170    (void) FormatLocaleFile(stdout,"... pass.\n");
1171  }
1172  (void) FormatLocaleFile(stdout,
1173    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1174    (double) (test-(*fail)),(double) *fail);
1175  return(test);
1176}
1177
1178/*
1179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180%                                                                             %
1181%                                                                             %
1182%                                                                             %
1183%   V a l i d a t e S t r e a m C o m m a n d                                 %
1184%                                                                             %
1185%                                                                             %
1186%                                                                             %
1187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188%
1189%  ValidateStreamCommand() validates the ImageMagick stream command line
1190%  program and returns the number of validation tests that passed and failed.
1191%
1192%  The format of the ValidateStreamCommand method is:
1193%
1194%      size_t ValidateStreamCommand(ImageInfo *image_info,
1195%        const char *reference_filename,const char *output_filename,
1196%        size_t *fail,ExceptionInfo *exception)
1197%
1198%  A description of each parameter follows:
1199%
1200%    o image_info: the image info.
1201%
1202%    o reference_filename: the reference image filename.
1203%
1204%    o output_filename: the output image filename.
1205%
1206%    o fail: return the number of validation tests that pass.
1207%
1208%    o exception: return any errors or warnings in this structure.
1209%
1210*/
1211static size_t ValidateStreamCommand(ImageInfo *image_info,
1212  const char *reference_filename,const char *output_filename,size_t *fail,
1213  ExceptionInfo *exception)
1214{
1215  char
1216    **arguments,
1217    command[MaxTextExtent];
1218
1219  int
1220    number_arguments;
1221
1222  MagickBooleanType
1223    status;
1224
1225  register ssize_t
1226    i,
1227    j;
1228
1229  size_t
1230    test;
1231
1232  test=0;
1233  (void) FormatLocaleFile(stdout,"validate stream command line program:\n");
1234  for (i=0; stream_options[i] != (char *) NULL; i++)
1235  {
1236    CatchException(exception);
1237    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1238      stream_options[i]);
1239    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s",
1240      stream_options[i],reference_filename,output_filename);
1241    arguments=StringToArgv(command,&number_arguments);
1242    if (arguments == (char **) NULL)
1243      {
1244        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1245            GetMagickModule());
1246        (*fail)++;
1247        continue;
1248      }
1249    status=StreamImageCommand(image_info,number_arguments,arguments,
1250      (char **) NULL,exception);
1251    for (j=0; j < (ssize_t) number_arguments; j++)
1252      arguments[j]=DestroyString(arguments[j]);
1253    arguments=(char **) RelinquishMagickMemory(arguments);
1254    if (status != MagickFalse)
1255      {
1256        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1257            GetMagickModule());
1258        (*fail)++;
1259        continue;
1260      }
1261    (void) FormatLocaleFile(stdout,"... pass.\n");
1262  }
1263  (void) FormatLocaleFile(stdout,
1264    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1265    (double) (test-(*fail)),(double) *fail);
1266  return(test);
1267}
1268
1269/*
1270%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271%                                                                             %
1272%                                                                             %
1273%                                                                             %
1274%  M a i n                                                                    %
1275%                                                                             %
1276%                                                                             %
1277%                                                                             %
1278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279%
1280%
1281*/
1282
1283static MagickBooleanType ValidateUsage(void)
1284{
1285  const char
1286    **p;
1287
1288  static const char
1289    *miscellaneous[]=
1290    {
1291      "-debug events        display copious debugging information",
1292      "-help                print program options",
1293      "-log format          format of debugging information",
1294      "-validate type       validation type",
1295      "-version             print version information",
1296      (char *) NULL
1297    },
1298    *settings[]=
1299    {
1300      "-regard-warnings     pay attention to warning messages",
1301      "-verbose             print detailed information about the image",
1302      (char *) NULL
1303    };
1304
1305  (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
1306  (void) printf("Copyright: %s\n\n",GetMagickCopyright());
1307  (void) printf("Features: %s\n",GetMagickFeatures());
1308  (void) printf("Usage: %s [options ...] reference-file\n",GetClientName());
1309  (void) printf("\nValidate Settings:\n");
1310  for (p=settings; *p != (char *) NULL; p++)
1311    (void) printf("  %s\n",*p);
1312  (void) printf("\nMiscellaneous Options:\n");
1313  for (p=miscellaneous; *p != (char *) NULL; p++)
1314    (void) printf("  %s\n",*p);
1315  return(MagickTrue);
1316}
1317
1318int main(int argc,char **argv)
1319{
1320#define DestroyValidate() \
1321{ \
1322  image_info=DestroyImageInfo(image_info); \
1323  exception=DestroyExceptionInfo(exception); \
1324}
1325#define ThrowValidateException(asperity,tag,option) \
1326{ \
1327  (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag,"`%s'", \
1328    option); \
1329  CatchException(exception); \
1330  DestroyValidate(); \
1331  return(MagickFalse); \
1332}
1333
1334  char
1335    output_filename[MaxTextExtent],
1336    reference_filename[MaxTextExtent],
1337    *option;
1338
1339  double
1340    elapsed_time,
1341    user_time;
1342
1343  ExceptionInfo
1344    *exception;
1345
1346  Image
1347    *reference_image;
1348
1349  ImageInfo
1350    *image_info;
1351
1352  MagickBooleanType
1353    regard_warnings,
1354    status;
1355
1356  MagickSizeType
1357    memory_resource,
1358    map_resource;
1359
1360  register ssize_t
1361    i;
1362
1363  TimerInfo
1364    *timer;
1365
1366  size_t
1367    fail,
1368    iterations,
1369    tests;
1370
1371  ValidateType
1372    type;
1373
1374  /*
1375    Validate the ImageMagick image processing suite.
1376  */
1377  MagickCoreGenesis(*argv,MagickTrue);
1378  (void) setlocale(LC_ALL,"");
1379  (void) setlocale(LC_NUMERIC,"C");
1380  iterations=1;
1381  status=MagickFalse;
1382  type=AllValidate;
1383  regard_warnings=MagickFalse;
1384  (void) regard_warnings;
1385  exception=AcquireExceptionInfo();
1386  image_info=AcquireImageInfo();
1387  (void) CopyMagickString(image_info->filename,ReferenceFilename,MaxTextExtent);
1388  (void) SetImageOption(image_info,"intensity","Rec601Lumniance");
1389  for (i=1; i < (ssize_t) argc; i++)
1390  {
1391    option=argv[i];
1392    if (IsCommandOption(option) == MagickFalse)
1393      {
1394        (void) CopyMagickString(image_info->filename,option,MaxTextExtent);
1395        continue;
1396      }
1397    switch (*(option+1))
1398    {
1399      case 'b':
1400      {
1401        if (LocaleCompare("bench",option+1) == 0)
1402          {
1403            iterations=StringToUnsignedLong(argv[++i]);
1404            break;
1405          }
1406        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1407      }
1408      case 'd':
1409      {
1410        if (LocaleCompare("debug",option+1) == 0)
1411          {
1412            (void) SetLogEventMask(argv[++i]);
1413            break;
1414          }
1415        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1416      }
1417      case 'h':
1418      {
1419        if (LocaleCompare("help",option+1) == 0)
1420          {
1421            (void) ValidateUsage();
1422            return(0);
1423          }
1424        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1425      }
1426      case 'l':
1427      {
1428        if (LocaleCompare("log",option+1) == 0)
1429          {
1430            if (*option != '+')
1431              (void) SetLogFormat(argv[i+1]);
1432            break;
1433          }
1434        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1435      }
1436      case 'r':
1437      {
1438        if (LocaleCompare("regard-warnings",option+1) == 0)
1439          {
1440            regard_warnings=MagickTrue;
1441            break;
1442          }
1443        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1444      }
1445      case 'v':
1446      {
1447        if (LocaleCompare("validate",option+1) == 0)
1448          {
1449            ssize_t
1450              validate;
1451
1452            if (*option == '+')
1453              break;
1454            i++;
1455            if (i == (ssize_t) argc)
1456              ThrowValidateException(OptionError,"MissingArgument",option);
1457            validate=ParseCommandOption(MagickValidateOptions,MagickFalse,
1458              argv[i]);
1459            if (validate < 0)
1460              ThrowValidateException(OptionError,"UnrecognizedValidateType",
1461                argv[i]);
1462            type=(ValidateType) validate;
1463            break;
1464          }
1465        if ((LocaleCompare("version",option+1) == 0) ||
1466            (LocaleCompare("-version",option+1) == 0))
1467          {
1468            (void) FormatLocaleFile(stdout,"Version: %s\n",
1469              GetMagickVersion((size_t *) NULL));
1470            (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
1471              GetMagickCopyright());
1472            (void) FormatLocaleFile(stdout,"Features: %s\n\n",
1473              GetMagickFeatures());
1474            return(0);
1475          }
1476        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1477      }
1478      default:
1479        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1480    }
1481  }
1482  timer=(TimerInfo *) NULL;
1483  if (iterations > 1)
1484    timer=AcquireTimerInfo();
1485  reference_image=ReadImage(image_info,exception);
1486  tests=0;
1487  fail=0;
1488  if (reference_image == (Image *) NULL)
1489    fail++;
1490  else
1491    {
1492      if (LocaleCompare(image_info->filename,ReferenceFilename) == 0)
1493        (void) CopyMagickString(reference_image->magick,ReferenceImageFormat,
1494          MaxTextExtent);
1495      (void) AcquireUniqueFilename(reference_filename);
1496      (void) AcquireUniqueFilename(output_filename);
1497      (void) CopyMagickString(reference_image->filename,reference_filename,
1498        MaxTextExtent);
1499      status=WriteImage(image_info,reference_image,exception);
1500      reference_image=DestroyImage(reference_image);
1501      if (status == MagickFalse)
1502        fail++;
1503      else
1504        {
1505          (void) FormatLocaleFile(stdout,"Version: %s\n",
1506            GetMagickVersion((size_t *) NULL));
1507          (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
1508            GetMagickCopyright());
1509          (void) FormatLocaleFile(stdout,
1510            "ImageMagick Validation Suite (%s)\n\n",CommandOptionToMnemonic(
1511            MagickValidateOptions,(ssize_t) type));
1512          if ((type & CompareValidate) != 0)
1513            tests+=ValidateCompareCommand(image_info,reference_filename,
1514              output_filename,&fail,exception);
1515          if ((type & CompositeValidate) != 0)
1516            tests+=ValidateCompositeCommand(image_info,reference_filename,
1517              output_filename,&fail,exception);
1518          if ((type & ConvertValidate) != 0)
1519            tests+=ValidateConvertCommand(image_info,reference_filename,
1520              output_filename,&fail,exception);
1521          if ((type & FormatsInMemoryValidate) != 0)
1522            {
1523              (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
1524              tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
1525                output_filename,&fail,exception);
1526              (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
1527              memory_resource=SetMagickResourceLimit(MemoryResource,0);
1528              tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
1529                output_filename,&fail,exception);
1530              (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
1531              map_resource=SetMagickResourceLimit(MapResource,0);
1532              tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
1533                output_filename,&fail,exception);
1534              (void) SetMagickResourceLimit(MemoryResource,memory_resource);
1535              (void) SetMagickResourceLimit(MapResource,map_resource);
1536            }
1537          if ((type & FormatsOnDiskValidate) != 0)
1538            {
1539              (void) FormatLocaleFile(stdout,"[pixel-cache: memory] ");
1540              tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
1541                output_filename,&fail,exception);
1542              (void) FormatLocaleFile(stdout,"[pixel-cache: memory-mapped] ");
1543              memory_resource=SetMagickResourceLimit(MemoryResource,0);
1544              tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
1545                output_filename,&fail,exception);
1546              (void) FormatLocaleFile(stdout,"[pixel-cache: disk] ");
1547              map_resource=SetMagickResourceLimit(MapResource,0);
1548              tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
1549                output_filename,&fail,exception);
1550              (void) SetMagickResourceLimit(MemoryResource,memory_resource);
1551              (void) SetMagickResourceLimit(MapResource,map_resource);
1552            }
1553          if ((type & IdentifyValidate) != 0)
1554            tests+=ValidateIdentifyCommand(image_info,reference_filename,
1555              output_filename,&fail,exception);
1556          if ((type & ImportExportValidate) != 0)
1557            tests+=ValidateImportExportPixels(image_info,reference_filename,
1558              output_filename,&fail,exception);
1559          if ((type & MontageValidate) != 0)
1560            tests+=ValidateMontageCommand(image_info,reference_filename,
1561              output_filename,&fail,exception);
1562          if ((type & StreamValidate) != 0)
1563            tests+=ValidateStreamCommand(image_info,reference_filename,
1564              output_filename,&fail,exception);
1565          (void) FormatLocaleFile(stdout,
1566            "validation suite: %.20g tests; %.20g passed; %.20g failed.\n",
1567            (double) tests,(double) (tests-fail),(double) fail);
1568        }
1569      (void) RelinquishUniqueFileResource(output_filename);
1570      (void) RelinquishUniqueFileResource(reference_filename);
1571    }
1572  if (exception->severity != UndefinedException)
1573    CatchException(exception);
1574  if (iterations > 1)
1575    {
1576      elapsed_time=GetElapsedTime(timer);
1577      user_time=GetUserTime(timer);
1578      (void) FormatLocaleFile(stderr,
1579        "Performance: %.20gi %gips %0.3fu %ld:%02ld.%03ld\n",(double)
1580        iterations,1.0*iterations/elapsed_time,user_time,(long)
1581        (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)),
1582        (long) (1000.0*(elapsed_time-floor(elapsed_time))));
1583      timer=DestroyTimerInfo(timer);
1584    }
1585  DestroyValidate();
1586  MagickCoreTerminus();
1587  return(fail == 0 ? 0 : 1);
1588}
1589