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