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