validate.c revision e2c4f18a7274c0c5c6231a2f3d73741a87d583fa
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-2012 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 < (ssize_t) 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 < (ssize_t) 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 < (ssize_t) 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 < (ssize_t) 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    *reconstruct_image,
469    *reference_image;
470
471  MagickBooleanType
472    status;
473
474  register ssize_t
475    i,
476    j;
477
478  size_t
479    length,
480    test;
481
482  unsigned char
483    *blob;
484
485  test=0;
486  (void) FormatLocaleFile(stdout,"validate image formats in memory:\n");
487  for (i=0; reference_formats[i].magick != (char *) NULL; i++)
488  {
489    magick_info=GetMagickInfo(reference_formats[i].magick,exception);
490    if ((magick_info == (const MagickInfo *) NULL) ||
491        (magick_info->decoder == (DecodeImageHandler *) NULL) ||
492        (magick_info->encoder == (EncodeImageHandler *) NULL))
493      continue;
494    for (j=0; reference_types[j].type != UndefinedType; j++)
495    {
496      /*
497        Generate reference image.
498      */
499      CatchException(exception);
500      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
501        (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
502        MagickCompressOptions,reference_formats[i].compression),
503        CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
504        (double) reference_types[j].depth);
505      (void) CopyMagickString(image_info->filename,reference_filename,
506        MaxTextExtent);
507      reference_image=ReadImage(image_info,exception);
508      if (reference_image == (Image *) NULL)
509        {
510          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
511            GetMagickModule());
512          (*fail)++;
513          continue;
514        }
515      /*
516        Write reference image.
517      */
518      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",
519        (double) reference_image->columns,(double) reference_image->rows);
520      (void) CloneString(&image_info->size,size);
521      image_info->depth=reference_types[j].depth;
522      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
523        reference_formats[i].magick,output_filename);
524      status=SetImageType(reference_image,reference_types[j].type,exception);
525      if (status == MagickFalse)
526        {
527          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
528            GetMagickModule());
529          (*fail)++;
530          reference_image=DestroyImage(reference_image);
531          continue;
532        }
533      status=SetImageDepth(reference_image,reference_types[j].depth,exception);
534      if (status == MagickFalse)
535        {
536          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
537            GetMagickModule());
538          (*fail)++;
539          reference_image=DestroyImage(reference_image);
540          continue;
541        }
542      reference_image->compression=reference_formats[i].compression;
543      status=WriteImage(image_info,reference_image,exception);
544      reference_image=DestroyImage(reference_image);
545      if (status == MagickFalse)
546        {
547          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
548            GetMagickModule());
549          (*fail)++;
550          continue;
551        }
552      /*
553        Read reference image.
554      */
555      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
556        reference_formats[i].magick,output_filename);
557      reference_image=ReadImage(image_info,exception);
558      if (reference_image == (Image *) NULL)
559        {
560          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
561            GetMagickModule());
562          (*fail)++;
563          continue;
564        }
565      /*
566        Write reference image.
567      */
568      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
569        reference_formats[i].magick,output_filename);
570      (void) CopyMagickString(image_info->magick,reference_formats[i].magick,
571        MaxTextExtent);
572      reference_image->depth=reference_types[j].depth;
573      reference_image->compression=reference_formats[i].compression;
574      length=8192;
575      blob=ImageToBlob(image_info,reference_image,&length,exception);
576      if (blob == (unsigned char *) NULL)
577        {
578          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
579            GetMagickModule());
580          (*fail)++;
581          reference_image=DestroyImage(reference_image);
582          continue;
583        }
584      /*
585        Read reconstruct image.
586      */
587      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
588        reference_formats[i].magick,output_filename);
589      reconstruct_image=BlobToImage(image_info,blob,length,exception);
590      blob=(unsigned char *) RelinquishMagickMemory(blob);
591      if (reconstruct_image == (Image *) NULL)
592        {
593          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
594            GetMagickModule());
595          (*fail)++;
596          reference_image=DestroyImage(reference_image);
597          continue;
598        }
599      /*
600        Compare reference to reconstruct image.
601      */
602      fuzz=0.0;
603      if (reference_formats[i].fuzz != 0.0)
604        fuzz=reference_formats[i].fuzz;
605#if defined(MAGICKCORE_HDRI_SUPPORT)
606      fuzz+=0.003;
607#endif
608      if (IssRGBColorspace(reference_image->colorspace) == MagickFalse)
609        fuzz+=0.3;
610      fuzz+=MagickEpsilon;
611      difference_image=CompareImages(reference_image,reconstruct_image,
612        MeanSquaredErrorMetric,&distortion,exception);
613      reconstruct_image=DestroyImage(reconstruct_image);
614      reference_image=DestroyImage(reference_image);
615      if (difference_image == (Image *) NULL)
616        {
617          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
618            GetMagickModule());
619          (*fail)++;
620          continue;
621        }
622      difference_image=DestroyImage(difference_image);
623      if ((distortion/QuantumRange) > fuzz)
624        {
625          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
626            distortion/QuantumRange);
627          (*fail)++;
628          continue;
629        }
630      (void) FormatLocaleFile(stdout,"... pass.\n");
631    }
632  }
633  (void) FormatLocaleFile(stdout,
634    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
635    (double) (test-(*fail)),(double) *fail);
636  return(test);
637}
638
639/*
640%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641%                                                                             %
642%                                                                             %
643%                                                                             %
644%   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                       %
645%                                                                             %
646%                                                                             %
647%                                                                             %
648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649%
650%  ValidateImageFormatsOnDisk() validates the ImageMagick image formats on disk
651%  and returns the number of validation tests that passed and failed.
652%
653%  The format of the ValidateImageFormatsOnDisk method is:
654%
655%      size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
656%        const char *reference_filename,const char *output_filename,
657%        size_t *fail,ExceptionInfo *exception)
658%
659%  A description of each parameter follows:
660%
661%    o image_info: the image info.
662%
663%    o reference_filename: the reference image filename.
664%
665%    o output_filename: the output image filename.
666%
667%    o fail: return the number of validation tests that pass.
668%
669%    o exception: return any errors or warnings in this structure.
670%
671*/
672static size_t ValidateImageFormatsOnDisk(ImageInfo *image_info,
673  const char *reference_filename,const char *output_filename,
674  size_t *fail,ExceptionInfo *exception)
675{
676  char
677    size[MaxTextExtent];
678
679  const MagickInfo
680    *magick_info;
681
682  double
683    distortion,
684    fuzz;
685
686  Image
687    *difference_image,
688    *reference_image,
689    *reconstruct_image;
690
691  MagickBooleanType
692    status;
693
694  register ssize_t
695    i,
696    j;
697
698  size_t
699    test;
700
701  test=0;
702  (void) FormatLocaleFile(stdout,"validate image formats on disk:\n");
703  for (i=0; reference_formats[i].magick != (char *) NULL; i++)
704  {
705    magick_info=GetMagickInfo(reference_formats[i].magick,exception);
706    if ((magick_info == (const MagickInfo *) NULL) ||
707        (magick_info->decoder == (DecodeImageHandler *) NULL) ||
708        (magick_info->encoder == (EncodeImageHandler *) NULL))
709      continue;
710    for (j=0; reference_types[j].type != UndefinedType; j++)
711    {
712      /*
713        Generate reference image.
714      */
715      CatchException(exception);
716      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s/%s/%.20g-bits",
717        (double) (test++),reference_formats[i].magick,CommandOptionToMnemonic(
718        MagickCompressOptions,reference_formats[i].compression),
719        CommandOptionToMnemonic(MagickTypeOptions,reference_types[j].type),
720        (double) reference_types[j].depth);
721      (void) CopyMagickString(image_info->filename,reference_filename,
722        MaxTextExtent);
723      reference_image=ReadImage(image_info,exception);
724      if (reference_image == (Image *) NULL)
725        {
726          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
727            GetMagickModule());
728          (*fail)++;
729          continue;
730        }
731      /*
732        Write reference image.
733      */
734      (void) FormatLocaleString(size,MaxTextExtent,"%.20gx%.20g",
735        (double) reference_image->columns,(double) reference_image->rows);
736      (void) CloneString(&image_info->size,size);
737      image_info->depth=reference_types[j].depth;
738      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
739        reference_formats[i].magick,output_filename);
740      status=SetImageType(reference_image,reference_types[j].type,exception);
741      if (status == MagickFalse)
742        {
743          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
744            GetMagickModule());
745          (*fail)++;
746          reference_image=DestroyImage(reference_image);
747          continue;
748        }
749      status=SetImageDepth(reference_image,reference_types[j].depth,exception);
750      if (status == MagickFalse)
751        {
752          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
753            GetMagickModule());
754          (*fail)++;
755          reference_image=DestroyImage(reference_image);
756          continue;
757        }
758      reference_image->compression=reference_formats[i].compression;
759      status=WriteImage(image_info,reference_image,exception);
760      reference_image=DestroyImage(reference_image);
761      if (status == MagickFalse)
762        {
763          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
764            GetMagickModule());
765          (*fail)++;
766          continue;
767        }
768      /*
769        Read reference image.
770      */
771      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
772        reference_formats[i].magick,output_filename);
773      reference_image=ReadImage(image_info,exception);
774      if (reference_image == (Image *) NULL)
775        {
776          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
777            GetMagickModule());
778          (*fail)++;
779          continue;
780        }
781      /*
782        Write reference image.
783      */
784      (void) FormatLocaleString(reference_image->filename,MaxTextExtent,"%s:%s",
785        reference_formats[i].magick,output_filename);
786      reference_image->depth=reference_types[j].depth;
787      reference_image->compression=reference_formats[i].compression;
788      status=WriteImage(image_info,reference_image,exception);
789      if (status == MagickFalse)
790        {
791          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
792            GetMagickModule());
793          (*fail)++;
794          reference_image=DestroyImage(reference_image);
795          continue;
796        }
797      /*
798        Read reconstruct image.
799      */
800      (void) FormatLocaleString(image_info->filename,MaxTextExtent,"%s:%s",
801        reference_formats[i].magick,output_filename);
802      reconstruct_image=ReadImage(image_info,exception);
803      if (reconstruct_image == (Image *) NULL)
804        {
805          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
806            GetMagickModule());
807          (*fail)++;
808          reference_image=DestroyImage(reference_image);
809          continue;
810        }
811      /*
812        Compare reference to reconstruct image.
813      */
814      fuzz=0.0;
815      if (reference_formats[i].fuzz != 0.0)
816        fuzz=reference_formats[i].fuzz;
817#if defined(MAGICKCORE_HDRI_SUPPORT)
818      fuzz+=0.003;
819#endif
820      if (IssRGBColorspace(reference_image->colorspace) == MagickFalse)
821        fuzz+=0.3;
822      fuzz+=MagickEpsilon;
823      difference_image=CompareImages(reference_image,reconstruct_image,
824        MeanSquaredErrorMetric,&distortion,exception);
825      reconstruct_image=DestroyImage(reconstruct_image);
826      reference_image=DestroyImage(reference_image);
827      if (difference_image == (Image *) NULL)
828        {
829          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
830            GetMagickModule());
831          (*fail)++;
832          continue;
833        }
834      difference_image=DestroyImage(difference_image);
835      if ((distortion/QuantumRange) > fuzz)
836        {
837          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
838            distortion/QuantumRange);
839          (*fail)++;
840          continue;
841        }
842      (void) FormatLocaleFile(stdout,"... pass.\n");
843    }
844  }
845  (void) FormatLocaleFile(stdout,
846    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
847    (double) (test-(*fail)),(double) *fail);
848  return(test);
849}
850
851/*
852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853%                                                                             %
854%                                                                             %
855%                                                                             %
856%   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                       %
857%                                                                             %
858%                                                                             %
859%                                                                             %
860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
861%
862%  ValidateImportExportPixels() validates the pixel import and export methods.
863%  It returns the number of validation tests that passed and failed.
864%
865%  The format of the ValidateImportExportPixels method is:
866%
867%      size_t ValidateImportExportPixels(ImageInfo *image_info,
868%        const char *reference_filename,const char *output_filename,
869%        size_t *fail,ExceptionInfo *exception)
870%
871%  A description of each parameter follows:
872%
873%    o image_info: the image info.
874%
875%    o reference_filename: the reference image filename.
876%
877%    o output_filename: the output image filename.
878%
879%    o fail: return the number of validation tests that pass.
880%
881%    o exception: return any errors or warnings in this structure.
882%
883*/
884static size_t ValidateImportExportPixels(ImageInfo *image_info,
885  const char *reference_filename,const char *output_filename,
886  size_t *fail,ExceptionInfo *exception)
887{
888  double
889    distortion;
890
891  Image
892    *difference_image,
893    *reference_image,
894    *reconstruct_image;
895
896  MagickBooleanType
897    status;
898
899  register ssize_t
900    i,
901    j;
902
903  size_t
904    length;
905
906  unsigned char
907    *pixels;
908
909  size_t
910    test;
911
912  (void) output_filename;
913  test=0;
914  (void) FormatLocaleFile(stdout,
915    "validate the import and export of image pixels:\n");
916  for (i=0; reference_map[i] != (char *) NULL; i++)
917  {
918    for (j=0; reference_storage[j].type != UndefinedPixel; j++)
919    {
920      /*
921        Generate reference image.
922      */
923      CatchException(exception);
924      (void) FormatLocaleFile(stdout,"  test %.20g: %s/%s",(double) (test++),
925        reference_map[i],CommandOptionToMnemonic(MagickStorageOptions,
926        reference_storage[j].type));
927      (void) CopyMagickString(image_info->filename,reference_filename,
928        MaxTextExtent);
929      reference_image=ReadImage(image_info,exception);
930      if (reference_image == (Image *) NULL)
931        {
932          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
933            GetMagickModule());
934          (*fail)++;
935          continue;
936        }
937      if (LocaleNCompare(reference_map[i],"cmy",3) == 0)
938        SetImageColorspace(reference_image,CMYKColorspace,exception);
939      length=strlen(reference_map[i])*reference_image->columns*
940        reference_image->rows*reference_storage[j].quantum;
941      pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
942      if (pixels == (unsigned char *) NULL)
943        {
944          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
945            GetMagickModule());
946          (*fail)++;
947          reference_image=DestroyImage(reference_image);
948          continue;
949        }
950      (void) ResetMagickMemory(pixels,0,length*sizeof(*pixels));
951      status=ExportImagePixels(reference_image,0,0,reference_image->columns,
952        reference_image->rows,reference_map[i],reference_storage[j].type,pixels,
953        exception);
954      if (status == MagickFalse)
955        {
956          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
957            GetMagickModule());
958          (*fail)++;
959          pixels=(unsigned char *) RelinquishMagickMemory(pixels);
960          reference_image=DestroyImage(reference_image);
961          continue;
962        }
963      (void) SetImageBackgroundColor(reference_image,exception);
964      status=ImportImagePixels(reference_image,0,0,reference_image->columns,
965        reference_image->rows,reference_map[i],reference_storage[j].type,
966        pixels,exception);
967      if (status == MagickFalse)
968        {
969          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
970            GetMagickModule());
971          (*fail)++;
972           pixels=(unsigned char *) RelinquishMagickMemory(pixels);
973          reference_image=DestroyImage(reference_image);
974          continue;
975        }
976      /*
977        Read reconstruct image.
978      */
979      reconstruct_image=AcquireImage(image_info,exception);
980      (void) SetImageExtent(reconstruct_image,reference_image->columns,
981        reference_image->rows,exception);
982      (void) SetImageColorspace(reconstruct_image,reference_image->colorspace,
983        exception);
984      (void) SetImageBackgroundColor(reconstruct_image,exception);
985      status=ImportImagePixels(reconstruct_image,0,0,reconstruct_image->columns,
986        reconstruct_image->rows,reference_map[i],reference_storage[j].type,
987        pixels,exception);
988      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
989      if (status == MagickFalse)
990        {
991          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
992            GetMagickModule());
993          (*fail)++;
994          reference_image=DestroyImage(reference_image);
995          continue;
996        }
997      /*
998        Compare reference to reconstruct image.
999      */
1000      difference_image=CompareImages(reference_image,reconstruct_image,
1001        MeanSquaredErrorMetric,&distortion,exception);
1002      reconstruct_image=DestroyImage(reconstruct_image);
1003      reference_image=DestroyImage(reference_image);
1004      if (difference_image == (Image *) NULL)
1005        {
1006          (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1007            GetMagickModule());
1008          (*fail)++;
1009          continue;
1010        }
1011      difference_image=DestroyImage(difference_image);
1012      if ((distortion/QuantumRange) > 0.0)
1013        {
1014          (void) FormatLocaleFile(stdout,"... fail (with distortion %g).\n",
1015            distortion/QuantumRange);
1016          (*fail)++;
1017          continue;
1018        }
1019      (void) FormatLocaleFile(stdout,"... pass.\n");
1020    }
1021  }
1022  (void) FormatLocaleFile(stdout,
1023    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1024    (double) (test-(*fail)),(double) *fail);
1025  return(test);
1026}
1027
1028/*
1029%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030%                                                                             %
1031%                                                                             %
1032%                                                                             %
1033%   V a l i d a t e M o n t a g e C o m m a n d                               %
1034%                                                                             %
1035%                                                                             %
1036%                                                                             %
1037%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038%
1039%  ValidateMontageCommand() validates the ImageMagick montage command line
1040%  program and returns the number of validation tests that passed and failed.
1041%
1042%  The format of the ValidateMontageCommand method is:
1043%
1044%      size_t ValidateMontageCommand(ImageInfo *image_info,
1045%        const char *reference_filename,const char *output_filename,
1046%        size_t *fail,ExceptionInfo *exception)
1047%
1048%  A description of each parameter follows:
1049%
1050%    o image_info: the image info.
1051%
1052%    o reference_filename: the reference image filename.
1053%
1054%    o output_filename: the output image filename.
1055%
1056%    o fail: return the number of validation tests that pass.
1057%
1058%    o exception: return any errors or warnings in this structure.
1059%
1060*/
1061static size_t ValidateMontageCommand(ImageInfo *image_info,
1062  const char *reference_filename,const char *output_filename,
1063  size_t *fail,ExceptionInfo *exception)
1064{
1065  char
1066    **arguments,
1067    command[MaxTextExtent];
1068
1069  int
1070    number_arguments;
1071
1072  MagickBooleanType
1073    status;
1074
1075  register ssize_t
1076    i,
1077    j;
1078
1079  size_t
1080    test;
1081
1082  test=0;
1083  (void) FormatLocaleFile(stdout,"validate montage command line program:\n");
1084  for (i=0; montage_options[i] != (char *) NULL; i++)
1085  {
1086    CatchException(exception);
1087    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1088      montage_options[i]);
1089    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s %s",
1090      reference_filename,montage_options[i],reference_filename,
1091      output_filename);
1092    arguments=StringToArgv(command,&number_arguments);
1093    if (arguments == (char **) NULL)
1094      {
1095        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1096            GetMagickModule());
1097        (*fail)++;
1098        continue;
1099      }
1100    status=MontageImageCommand(image_info,number_arguments,arguments,
1101      (char **) NULL,exception);
1102    for (j=0; j < (ssize_t) number_arguments; j++)
1103      arguments[j]=DestroyString(arguments[j]);
1104    arguments=(char **) RelinquishMagickMemory(arguments);
1105    if (status != MagickFalse)
1106      {
1107        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1108            GetMagickModule());
1109        (*fail)++;
1110        continue;
1111      }
1112    (void) FormatLocaleFile(stdout,"... pass.\n");
1113  }
1114  (void) FormatLocaleFile(stdout,
1115    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1116    (double) (test-(*fail)),(double) *fail);
1117  return(test);
1118}
1119
1120/*
1121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122%                                                                             %
1123%                                                                             %
1124%                                                                             %
1125%   V a l i d a t e S t r e a m C o m m a n d                                 %
1126%                                                                             %
1127%                                                                             %
1128%                                                                             %
1129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130%
1131%  ValidateStreamCommand() validates the ImageMagick stream command line
1132%  program and returns the number of validation tests that passed and failed.
1133%
1134%  The format of the ValidateStreamCommand method is:
1135%
1136%      size_t ValidateStreamCommand(ImageInfo *image_info,
1137%        const char *reference_filename,const char *output_filename,
1138%        size_t *fail,ExceptionInfo *exception)
1139%
1140%  A description of each parameter follows:
1141%
1142%    o image_info: the image info.
1143%
1144%    o reference_filename: the reference image filename.
1145%
1146%    o output_filename: the output image filename.
1147%
1148%    o fail: return the number of validation tests that pass.
1149%
1150%    o exception: return any errors or warnings in this structure.
1151%
1152*/
1153static size_t ValidateStreamCommand(ImageInfo *image_info,
1154  const char *reference_filename,const char *output_filename,
1155  size_t *fail,ExceptionInfo *exception)
1156{
1157  char
1158    **arguments,
1159    command[MaxTextExtent];
1160
1161  int
1162    number_arguments;
1163
1164  MagickBooleanType
1165    status;
1166
1167  register ssize_t
1168    i,
1169    j;
1170
1171  size_t
1172    test;
1173
1174  test=0;
1175  (void) FormatLocaleFile(stdout,"validate stream command line program:\n");
1176  for (i=0; stream_options[i] != (char *) NULL; i++)
1177  {
1178    CatchException(exception);
1179    (void) FormatLocaleFile(stdout,"  test %.20g: %s",(double) (test++),
1180      stream_options[i]);
1181    (void) FormatLocaleString(command,MaxTextExtent,"%s %s %s",
1182      stream_options[i],reference_filename,output_filename);
1183    arguments=StringToArgv(command,&number_arguments);
1184    if (arguments == (char **) NULL)
1185      {
1186        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1187            GetMagickModule());
1188        (*fail)++;
1189        continue;
1190      }
1191    status=StreamImageCommand(image_info,number_arguments,arguments,
1192      (char **) NULL,exception);
1193    for (j=0; j < (ssize_t) number_arguments; j++)
1194      arguments[j]=DestroyString(arguments[j]);
1195    arguments=(char **) RelinquishMagickMemory(arguments);
1196    if (status != MagickFalse)
1197      {
1198        (void) FormatLocaleFile(stdout,"... fail @ %s/%s/%lu.\n",
1199            GetMagickModule());
1200        (*fail)++;
1201        continue;
1202      }
1203    (void) FormatLocaleFile(stdout,"... pass.\n");
1204  }
1205  (void) FormatLocaleFile(stdout,
1206    "  summary: %.20g subtests; %.20g passed; %.20g failed.\n",(double) test,
1207    (double) (test-(*fail)),(double) *fail);
1208  return(test);
1209}
1210
1211/*
1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213%                                                                             %
1214%                                                                             %
1215%                                                                             %
1216%  M a i n                                                                    %
1217%                                                                             %
1218%                                                                             %
1219%                                                                             %
1220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221%
1222%
1223*/
1224
1225static MagickBooleanType ValidateUsage(void)
1226{
1227  const char
1228    **p;
1229
1230  static const char
1231    *miscellaneous[]=
1232    {
1233      "-debug events        display copious debugging information",
1234      "-help                print program options",
1235      "-log format          format of debugging information",
1236      "-validate type       validation type",
1237      "-version             print version information",
1238      (char *) NULL
1239    },
1240    *settings[]=
1241    {
1242      "-regard-warnings     pay attention to warning messages",
1243      "-verbose             print detailed information about the image",
1244      (char *) NULL
1245    };
1246
1247  (void) printf("Version: %s\n",GetMagickVersion((size_t *) NULL));
1248  (void) printf("Copyright: %s\n\n",GetMagickCopyright());
1249  (void) printf("Features: %s\n",GetMagickFeatures());
1250  (void) printf("Usage: %s [options ...] reference-file\n",GetClientName());
1251  (void) printf("\nValidate Settings:\n");
1252  for (p=settings; *p != (char *) NULL; p++)
1253    (void) printf("  %s\n",*p);
1254  (void) printf("\nMiscellaneous Options:\n");
1255  for (p=miscellaneous; *p != (char *) NULL; p++)
1256    (void) printf("  %s\n",*p);
1257  return(MagickTrue);
1258}
1259
1260int main(int argc,char **argv)
1261{
1262#define DestroyValidate() \
1263{ \
1264  image_info=DestroyImageInfo(image_info); \
1265  exception=DestroyExceptionInfo(exception); \
1266}
1267#define ThrowValidateException(asperity,tag,option) \
1268{ \
1269  (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag,"`%s'", \
1270    option); \
1271  CatchException(exception); \
1272  DestroyValidate(); \
1273  return(MagickFalse); \
1274}
1275
1276  char
1277    output_filename[MaxTextExtent],
1278    reference_filename[MaxTextExtent],
1279    *option;
1280
1281  double
1282    elapsed_time,
1283    user_time;
1284
1285  ExceptionInfo
1286    *exception;
1287
1288  Image
1289    *reference_image;
1290
1291  ImageInfo
1292    *image_info;
1293
1294  MagickBooleanType
1295    regard_warnings,
1296    status;
1297
1298  register ssize_t
1299    i;
1300
1301  TimerInfo
1302    *timer;
1303
1304  size_t
1305    fail,
1306    iterations,
1307    tests;
1308
1309  ValidateType
1310    type;
1311
1312  /*
1313    Validate the ImageMagick image processing suite.
1314  */
1315  MagickCoreGenesis(*argv,MagickFalse);
1316  iterations=1;
1317  status=MagickFalse;
1318  type=AllValidate;
1319  regard_warnings=MagickFalse;
1320  (void) regard_warnings;
1321  exception=AcquireExceptionInfo();
1322  image_info=AcquireImageInfo();
1323  (void) CopyMagickString(image_info->filename,ReferenceFilename,MaxTextExtent);
1324  for (i=1; i < (ssize_t) argc; i++)
1325  {
1326    option=argv[i];
1327    if (IsCommandOption(option) == MagickFalse)
1328      {
1329        (void) CopyMagickString(image_info->filename,option,MaxTextExtent);
1330        continue;
1331      }
1332    switch (*(option+1))
1333    {
1334      case 'b':
1335      {
1336        if (LocaleCompare("bench",option+1) == 0)
1337          {
1338            iterations=StringToUnsignedLong(argv[++i]);
1339            break;
1340          }
1341        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1342      }
1343      case 'd':
1344      {
1345        if (LocaleCompare("debug",option+1) == 0)
1346          {
1347            (void) SetLogEventMask(argv[++i]);
1348            break;
1349          }
1350        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1351      }
1352      case 'h':
1353      {
1354        if (LocaleCompare("help",option+1) == 0)
1355          {
1356            (void) ValidateUsage();
1357            return(0);
1358          }
1359        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1360      }
1361      case 'l':
1362      {
1363        if (LocaleCompare("log",option+1) == 0)
1364          {
1365            if (*option != '+')
1366              (void) SetLogFormat(argv[i+1]);
1367            break;
1368          }
1369        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1370      }
1371      case 'r':
1372      {
1373        if (LocaleCompare("regard-warnings",option+1) == 0)
1374          {
1375            regard_warnings=MagickTrue;
1376            break;
1377          }
1378        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1379      }
1380      case 'v':
1381      {
1382        if (LocaleCompare("validate",option+1) == 0)
1383          {
1384            ssize_t
1385              validate;
1386
1387            if (*option == '+')
1388              break;
1389            i++;
1390            if (i == (ssize_t) argc)
1391              ThrowValidateException(OptionError,"MissingArgument",option);
1392            validate=ParseCommandOption(MagickValidateOptions,MagickFalse,
1393              argv[i]);
1394            if (validate < 0)
1395              ThrowValidateException(OptionError,"UnrecognizedValidateType",
1396                argv[i]);
1397            type=(ValidateType) validate;
1398            break;
1399          }
1400        if ((LocaleCompare("version",option+1) == 0) ||
1401            (LocaleCompare("-version",option+1) == 0))
1402          {
1403            (void) FormatLocaleFile(stdout,"Version: %s\n",
1404              GetMagickVersion((size_t *) NULL));
1405            (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
1406              GetMagickCopyright());
1407            (void) FormatLocaleFile(stdout,"Features: %s\n\n",
1408              GetMagickFeatures());
1409            return(0);
1410          }
1411        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1412      }
1413      default:
1414        ThrowValidateException(OptionError,"UnrecognizedOption",option)
1415    }
1416  }
1417  timer=(TimerInfo *) NULL;
1418  if (iterations > 1)
1419    timer=AcquireTimerInfo();
1420  reference_image=ReadImage(image_info,exception);
1421  tests=0;
1422  fail=0;
1423  if (reference_image == (Image *) NULL)
1424    fail++;
1425  else
1426    {
1427      if (LocaleCompare(image_info->filename,ReferenceFilename) == 0)
1428        (void) CopyMagickString(reference_image->magick,ReferenceImageFormat,
1429          MaxTextExtent);
1430      (void) AcquireUniqueFilename(reference_filename);
1431      (void) AcquireUniqueFilename(output_filename);
1432      (void) CopyMagickString(reference_image->filename,reference_filename,
1433        MaxTextExtent);
1434      status=WriteImage(image_info,reference_image,exception);
1435      reference_image=DestroyImage(reference_image);
1436      if (status == MagickFalse)
1437        fail++;
1438      else
1439        {
1440          (void) FormatLocaleFile(stdout,"Version: %s\n",
1441            GetMagickVersion((size_t *) NULL));
1442          (void) FormatLocaleFile(stdout,"Copyright: %s\n\n",
1443            GetMagickCopyright());
1444          (void) FormatLocaleFile(stdout,
1445            "ImageMagick Validation Suite (%s)\n\n",CommandOptionToMnemonic(
1446            MagickValidateOptions,(ssize_t) type));
1447          if ((type & CompareValidate) != 0)
1448            tests+=ValidateCompareCommand(image_info,reference_filename,
1449              output_filename,&fail,exception);
1450          if ((type & CompositeValidate) != 0)
1451            tests+=ValidateCompositeCommand(image_info,reference_filename,
1452              output_filename,&fail,exception);
1453          if ((type & ConvertValidate) != 0)
1454            tests+=ValidateConvertCommand(image_info,reference_filename,
1455              output_filename,&fail,exception);
1456          if ((type & FormatsInMemoryValidate) != 0)
1457            tests+=ValidateImageFormatsInMemory(image_info,reference_filename,
1458              output_filename,&fail,exception);
1459          if ((type & FormatsOnDiskValidate) != 0)
1460            tests+=ValidateImageFormatsOnDisk(image_info,reference_filename,
1461              output_filename,&fail,exception);
1462          if ((type & IdentifyValidate) != 0)
1463            tests+=ValidateIdentifyCommand(image_info,reference_filename,
1464              output_filename,&fail,exception);
1465          if ((type & ImportExportValidate) != 0)
1466            tests+=ValidateImportExportPixels(image_info,reference_filename,
1467              output_filename,&fail,exception);
1468          if ((type & MontageValidate) != 0)
1469            tests+=ValidateMontageCommand(image_info,reference_filename,
1470              output_filename,&fail,exception);
1471          if ((type & StreamValidate) != 0)
1472            tests+=ValidateStreamCommand(image_info,reference_filename,
1473              output_filename,&fail,exception);
1474          (void) FormatLocaleFile(stdout,
1475            "validation suite: %.20g tests; %.20g passed; %.20g failed.\n",
1476            (double) tests,(double) (tests-fail),(double) fail);
1477        }
1478      (void) RelinquishUniqueFileResource(output_filename);
1479      (void) RelinquishUniqueFileResource(reference_filename);
1480    }
1481  if (exception->severity != UndefinedException)
1482    CatchException(exception);
1483  if (iterations > 1)
1484    {
1485      elapsed_time=GetElapsedTime(timer);
1486      user_time=GetUserTime(timer);
1487      (void) FormatLocaleFile(stderr,
1488        "Performance: %.20gi %gips %0.3fu %ld:%02ld.%03ld\n",(double)
1489        iterations,1.0*iterations/elapsed_time,user_time,(long)
1490        (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)),
1491        (long) (1000.0*(elapsed_time-floor(elapsed_time))));
1492      timer=DestroyTimerInfo(timer);
1493    }
1494  DestroyValidate();
1495  MagickCoreTerminus();
1496  return(fail == 0 ? 0 : 1);
1497}
1498