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