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