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