00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
#include "magick/studio.h"
00044
#include "magick/client.h"
00045
#include "magick/color.h"
00046
#include "magick/color_private.h"
00047
#include "magick/colorspace.h"
00048
#include "magick/colorspace_private.h"
00049
#include "magick/compare.h"
00050
#include "magick/composite_private.h"
00051
#include "magick/constitute.h"
00052
#include "magick/geometry.h"
00053
#include "magick/image_private.h"
00054
#include "magick/list.h"
00055
#include "magick/log.h"
00056
#include "magick/memory_.h"
00057
#include "magick/mogrify.h"
00058
#include "magick/option.h"
00059
#include "magick/resource_.h"
00060
#include "magick/string_.h"
00061
#include "magick/utility.h"
00062
#include "magick/version.h"
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 MagickExport Image *
CompareImages(
Image *image,
const Image *reconstruct_image,
00102
const MetricType metric,
double *distortion,
ExceptionInfo *
exception)
00103 {
00104
Image
00105 *difference_image;
00106
00107 difference_image=
CompareImageChannels(image,reconstruct_image,
AllChannels,
00108 metric,distortion,exception);
00109
return(difference_image);
00110 }
00111
00112 static inline void CompositeOver(
const MagickPixelPacket *p,
00113
const MagickRealType alpha,
const MagickPixelPacket *q,
00114
const MagickRealType beta,
MagickPixelPacket *composite)
00115 {
00116
MagickRealType
00117 gamma;
00118
00119 gamma=1.0-
QuantumScale*
QuantumScale*alpha*beta;
00120 composite->
opacity=
MaxRGB*(1.0-gamma);
00121 gamma=1.0/(gamma <=
MagickEpsilon ? 1.0 : gamma);
00122 composite->
red=gamma*
MagickOver_(p->
red,alpha,q->
red,beta);
00123 composite->
green=gamma*
MagickOver_(p->
green,alpha,q->
green,beta);
00124 composite->
blue=gamma*
MagickOver_(p->
blue,alpha,q->
blue,beta);
00125
if (q->
colorspace ==
CMYKColorspace)
00126 composite->
index=gamma*
MagickOver_(p->
index,alpha,q->
index,beta);
00127 }
00128
00129 static MagickRealType GetMeanAbsoluteError(
const Image *image,
00130
const Image *reconstruct_image,
const ChannelType channel,
00131
ExceptionInfo *
exception)
00132 {
00133
IndexPacket
00134 *indexes,
00135 *reconstruct_indexes;
00136
00137
long
00138 y;
00139
00140
MagickRealType
00141 area,
00142 distortion;
00143
00144
register const PixelPacket
00145 *p,
00146 *q;
00147
00148
register long
00149 x;
00150
00151 area=0.0;
00152 distortion=0.0;
00153
for (y=0; y < (
long) image->
rows; y++)
00154 {
00155 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
00156 q=
AcquireImagePixels(reconstruct_image,0,y,reconstruct_image->
columns,1,
00157 exception);
00158
if ((p == (
const PixelPacket *) NULL) || (q == (
const PixelPacket *) NULL))
00159
break;
00160 indexes=
GetIndexes(image);
00161 reconstruct_indexes=
GetIndexes(reconstruct_image);
00162
for (x=0; x < (
long) image->
columns; x++)
00163 {
00164
if ((channel &
RedChannel) != 0)
00165 {
00166 distortion+=fabs(p->
red-(
MagickRealType) q->
red);
00167 area++;
00168 }
00169
if ((channel &
GreenChannel) != 0)
00170 {
00171 distortion+=fabs(p->
green-(
MagickRealType) q->
green);
00172 area++;
00173 }
00174
if ((channel &
BlueChannel) != 0)
00175 {
00176 distortion+=fabs(p->
blue-(
MagickRealType) q->
blue);
00177 area++;
00178 }
00179
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00180 {
00181 distortion+=fabs(p->
opacity-(
MagickRealType) q->
opacity);
00182 area++;
00183 }
00184
if (((channel &
IndexChannel) != 0) &&
00185 (image->
colorspace ==
CMYKColorspace))
00186 {
00187 distortion+=fabs(indexes[x]-(
MagickRealType) reconstruct_indexes[x]);
00188 area++;
00189 }
00190 p++;
00191 q++;
00192 }
00193 }
00194
return(distortion/area);
00195 }
00196
00197 static MagickRealType GetMeanSquaredError(
const Image *image,
00198
const Image *reconstruct_image,
const ChannelType channel,
00199
ExceptionInfo *
exception)
00200 {
00201
IndexPacket
00202 *indexes,
00203 *reconstruct_indexes;
00204
00205
long
00206 y;
00207
00208
MagickRealType
00209 area,
00210 distance,
00211 distortion;
00212
00213
register const PixelPacket
00214 *p,
00215 *q;
00216
00217
register long
00218 x;
00219
00220 area=0.0;
00221 distortion=0.0;
00222
for (y=0; y < (
long) image->
rows; y++)
00223 {
00224 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
00225 q=
AcquireImagePixels(reconstruct_image,0,y,reconstruct_image->
columns,1,
00226 exception);
00227
if ((p == (
const PixelPacket *) NULL) || (q == (
const PixelPacket *) NULL))
00228
break;
00229 indexes=
GetIndexes(image);
00230 reconstruct_indexes=
GetIndexes(reconstruct_image);
00231
for (x=0; x < (
long) image->
columns; x++)
00232 {
00233
if ((channel &
RedChannel) != 0)
00234 {
00235 distance=p->
red-(
MagickRealType) q->
red;
00236 distortion+=distance*distance;
00237 area++;
00238 }
00239
if ((channel &
GreenChannel) != 0)
00240 {
00241 distance=p->
green-(
MagickRealType) q->
green;
00242 distortion+=distance*distance;
00243 area++;
00244 }
00245
if ((channel &
BlueChannel) != 0)
00246 {
00247 distance=p->
blue-(
MagickRealType) q->
blue;
00248 distortion+=distance*distance;
00249 area++;
00250 }
00251
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00252 {
00253 distance=p->
opacity-(
MagickRealType) q->
opacity;
00254 distortion+=distance*distance;
00255 area++;
00256 }
00257
if (((channel &
IndexChannel) != 0) &&
00258 (image->
colorspace ==
CMYKColorspace))
00259 {
00260 distance=indexes[x]-(
MagickRealType) reconstruct_indexes[x];
00261 distortion+=distance*distance;
00262 area++;
00263 }
00264 p++;
00265 q++;
00266 }
00267 }
00268
return(distortion/area);
00269 }
00270
00271 static MagickRealType GetPeakAbsoluteError(
const Image *image,
00272
const Image *reconstruct_image,
const ChannelType channel,
00273
ExceptionInfo *
exception)
00274 {
00275
IndexPacket
00276 *indexes,
00277 *reconstruct_indexes;
00278
00279
long
00280 y;
00281
00282
MagickRealType
00283 distance,
00284 distortion;
00285
00286
register const PixelPacket
00287 *p,
00288 *q;
00289
00290
register long
00291 x;
00292
00293 distortion=0.0;
00294
for (y=0; y < (
long) image->
rows; y++)
00295 {
00296 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
00297 q=
AcquireImagePixels(reconstruct_image,0,y,reconstruct_image->
columns,1,
00298 exception);
00299
if ((p == (
const PixelPacket *) NULL) || (q == (
const PixelPacket *) NULL))
00300
break;
00301 indexes=
GetIndexes(image);
00302 reconstruct_indexes=
GetIndexes(reconstruct_image);
00303
for (x=0; x < (
long) image->
columns; x++)
00304 {
00305
if ((channel &
RedChannel) != 0)
00306 {
00307 distance=fabs(p->
red-(
MagickRealType) q->
red);
00308
if (distance > distortion)
00309 distortion=distance;
00310 }
00311
if ((channel &
GreenChannel) != 0)
00312 {
00313 distance=fabs(p->
green-(
MagickRealType) q->
green);
00314
if (distance > distortion)
00315 distortion=distance;
00316 }
00317
if ((channel &
BlueChannel) != 0)
00318 {
00319 distance=fabs(p->
blue-(
MagickRealType) q->
blue);
00320
if (distance > distortion)
00321 distortion=distance;
00322 }
00323
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00324 {
00325 distance=fabs(p->
opacity-(
MagickRealType) q->
opacity);
00326
if (distance > distortion)
00327 distortion=distance;
00328 }
00329
if (((channel &
IndexChannel) != 0) &&
00330 (image->
colorspace ==
CMYKColorspace))
00331 {
00332 distance=
00333 fabs(indexes[x]-(
MagickRealType) reconstruct_indexes[x]);
00334
if (distance > distortion)
00335 distortion=distance;
00336 }
00337 p++;
00338 q++;
00339 }
00340 }
00341
return(distortion);
00342 }
00343
00344 static MagickRealType GetPeakSignalToNoiseRatio(
const Image *image,
00345
const Image *reconstruct_image,
const ChannelType channel,
00346
ExceptionInfo *
exception)
00347 {
00348
MagickRealType
00349 distortion;
00350
00351 distortion=
GetMeanSquaredError(image,reconstruct_image,channel,exception);
00352
return(20.0*log10(
MaxRGB/sqrt(distortion)));
00353 }
00354
00355 static MagickRealType GetRootMeanSquaredError(
const Image *image,
00356
const Image *reconstruct_image,
const ChannelType channel,
00357
ExceptionInfo *
exception)
00358 {
00359
MagickRealType
00360 distortion;
00361
00362 distortion=
GetMeanSquaredError(image,reconstruct_image,channel,exception);
00363
return(sqrt(distortion));
00364 }
00365
00366 MagickExport Image *
CompareImageChannels(
Image *image,
00367
const Image *reconstruct_image,
const ChannelType channel,
00368
const MetricType metric,
double *distortion,
ExceptionInfo *
exception)
00369 {
00370
Image
00371 *difference_image;
00372
00373
long
00374 y;
00375
00376
MagickPixelPacket
00377 composite,
00378 red,
00379 source,
00380 white;
00381
00382
MagickRealType
00383 alpha,
00384 beta;
00385
00386
register const PixelPacket
00387 *p,
00388 *q;
00389
00390
register IndexPacket
00391 *difference_indexes,
00392 *indexes,
00393 *reconstruct_indexes;
00394
00395
register long
00396 x;
00397
00398
register PixelPacket
00399 *r;
00400
00401
assert(image != (
Image *) NULL);
00402
assert(image->
signature ==
MagickSignature);
00403
if (image->
debug !=
MagickFalse)
00404 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00405
assert(reconstruct_image != (
const Image *) NULL);
00406
assert(reconstruct_image->
signature ==
MagickSignature);
00407
assert(distortion != (
double *) NULL);
00408
if (image->
debug !=
MagickFalse)
00409 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00410
if ((reconstruct_image->
columns != image->
columns) ||
00411 (reconstruct_image->
rows != image->
rows))
00412
ThrowImageException(
ImageError,
"ImageSizeDiffers");
00413
if (image->
colorspace != reconstruct_image->
colorspace)
00414
ThrowImageException(
ImageError,
"ImageColorspaceDiffers");
00415
if (image->
matte != reconstruct_image->
matte)
00416
ThrowImageException(
ImageError,
"ImageOpacityDiffers");
00417 difference_image=
CloneImage(image,image->
columns,image->
rows,
MagickTrue,
00418 exception);
00419
if (difference_image == (
Image *) NULL)
00420
return((
Image *) NULL);
00421 difference_image->
storage_class=
DirectClass;
00422 (
void)
QueryMagickColor(
"#f1001e00",&red,exception);
00423 (
void)
QueryMagickColor(
"#ffffff00",&white,exception);
00424
if (difference_image->
colorspace ==
CMYKColorspace)
00425 {
00426
RGBtoCMYK(&red);
00427
RGBtoCMYK(&white);
00428 }
00429
00430
00431
00432 *distortion=0.0;
00433
switch (metric)
00434 {
00435
case MeanAbsoluteErrorMetric:
00436 {
00437 *distortion=
GetMeanAbsoluteError(image,reconstruct_image,channel,
00438 exception);
00439
break;
00440 }
00441
case MeanSquaredErrorMetric:
00442 {
00443 *distortion=
GetMeanSquaredError(image,reconstruct_image,channel,
00444 exception);
00445
break;
00446 }
00447
case PeakAbsoluteErrorMetric:
00448
default:
00449 {
00450 *distortion=
GetPeakAbsoluteError(image,reconstruct_image,channel,
00451 exception);
00452
break;
00453 }
00454
case PeakSignalToNoiseRatioMetric:
00455 {
00456 *distortion=
GetPeakSignalToNoiseRatio(image,reconstruct_image,channel,
00457 exception);
00458
break;
00459 }
00460
case RootMeanSquaredErrorMetric:
00461 {
00462 *distortion=
GetRootMeanSquaredError(image,reconstruct_image,channel,
00463 exception);
00464
break;
00465 }
00466 }
00467
00468
00469
00470
GetMagickPixelPacket(reconstruct_image,&source);
00471
GetMagickPixelPacket(difference_image,&composite);
00472
for (y=0; y < (
long) image->
rows; y++)
00473 {
00474 p=
AcquireImagePixels(image,0,y,image->
columns,1,exception);
00475 q=
AcquireImagePixels(reconstruct_image,0,y,reconstruct_image->
columns,1,
00476 exception);
00477 r=
SetImagePixels(difference_image,0,y,difference_image->
columns,1);
00478
if ((p == (
const PixelPacket *) NULL) ||
00479 (q == (
const PixelPacket *) NULL) || (r == (
PixelPacket *) NULL))
00480
break;
00481 indexes=
GetIndexes(image);
00482 reconstruct_indexes=
GetIndexes(reconstruct_image);
00483 difference_indexes=
GetIndexes(difference_image);
00484
for (x=0; x < (
long) image->
columns; x++)
00485 {
00486 alpha=0.0;
00487 beta=0.0;
00488
if ((channel &
RedChannel) != 0)
00489 {
00490 alpha+=p->
red;
00491 beta+=q->
red;
00492 }
00493
if ((channel &
GreenChannel) != 0)
00494 {
00495 alpha+=p->
green;
00496 beta+=q->
green;
00497 }
00498
if ((channel &
BlueChannel) != 0)
00499 {
00500 alpha+=p->
blue;
00501 beta+=q->
blue;
00502 }
00503
if (((channel &
OpacityChannel) != 0) && (image->
matte !=
MagickFalse))
00504 {
00505 alpha+=p->
opacity;
00506 beta+=q->
opacity;
00507 }
00508
if (((channel &
IndexChannel) != 0) &&
00509 (image->
colorspace ==
CMYKColorspace))
00510 {
00511 alpha+=indexes[x];
00512 beta+=reconstruct_indexes[x];
00513 }
00514 source.
red=(
MagickRealType) q->
red;
00515 source.
green=(
MagickRealType) q->
green;
00516 source.
blue=(
MagickRealType) q->
blue;
00517
if (reconstruct_image->
matte !=
MagickFalse)
00518 source.
opacity=(
MagickRealType) q->
opacity;
00519
if (alpha != beta)
00520
CompositeOver(&source,9.0*
MaxRGB/10.0,&red,(
double) red.
opacity,
00521 &composite);
00522
else
00523
CompositeOver(&source,9.0*
MaxRGB/10.0,&white,(
double) white.
opacity,
00524 &composite);
00525
SetPixelPacket(&composite,r,difference_indexes+x);
00526 p++;
00527 q++;
00528 r++;
00529 }
00530
if (
SyncImagePixels(difference_image) ==
MagickFalse)
00531
break;
00532 }
00533
return(difference_image);
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 static void CompareUsage(
void)
00572 {
00573
const char
00574 **p;
00575
00576
static const char
00577 *options[]=
00578 {
00579
"-authenticate value decrypt image with this password",
00580
"-channel type Red, Green, Blue, Opacity, Index, Cyan, Yellow, ",
00581
" Magenta, Black, or All",
00582
"-colorspace type alternate image colorspace",
00583
"-compress type image compression type",
00584
"-debug events display copious debugging information",
00585
"-define format:option",
00586
" define one or more image format options",
00587
"-density geometry horizontal and vertical density of the image",
00588
"-depth value image depth",
00589
"-extract geometry extract area from image",
00590
"-help print program options",
00591
"-interlace type None, Line, Plane, or Partition",
00592
"-limit type value Area, Disk, Map, or Memory resource limit",
00593
"-log format format of debugging information",
00594
"-metric type MAE, MSE, PSE, PSNR, or RMSE",
00595
"-quality value JPEG/MIFF/PNG compression level",
00596
"-profile filename add, delete, or apply an image profile",
00597
"-sampling-factor geometry",
00598
" horizontal and vertical sampling factor",
00599
"-size geometry width and height of image",
00600
"-verbose print detailed information about the image",
00601
"-version print version information",
00602
"-virtual-pixel method",
00603
" Constant, Edge, Mirror, or Tile",
00604 (
char *) NULL
00605 };
00606
00607 (
void) printf(
"Version: %s\n",
GetMagickVersion((
unsigned long *) NULL));
00608 (
void) printf(
"Copyright: %s\n\n",
GetMagickCopyright());
00609 (
void) printf(
"Usage: %s [options ...] image reconstruct difference\n",
00610
GetClientName());
00611 (
void) printf(
"\nWhere options include:\n");
00612
for (p=options; *p != (
char *) NULL; p++)
00613 (
void) printf(
" %s\n",*p);
00614
Exit(0);
00615 }
00616
00617 MagickExport MagickBooleanType CompareImageCommand(
ImageInfo *image_info,
00618
int argc,
char **argv,
char **metadata,
ExceptionInfo *
exception)
00619 {
00620
#define DestroyCompare() \
00621
{ \
00622
DestroyImageList(image); \
00623
for (i=0; i < (long) argc; i++) \
00624
argv[i]=(char *) RelinquishMagickMemory(argv[i]); \
00625
argv=(char **) RelinquishMagickMemory(argv); \
00626
}
00627
#define ThrowCompareException(severity,tag,option) \
00628
{ \
00629
(void) ThrowMagickException(exception,GetMagickModule(),severity,tag,option);\
00630
DestroyCompare(); \
00631
return(MagickFalse); \
00632
}
00633
#define ThrowCompareInvalidArgumentException(option,argument) \
00634
{ \
00635
(void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
00636
"InvalidArgument",argument,option); \
00637
DestroyCompare(); \
00638
return(MagickFalse); \
00639
}
00640
00641
char
00642 *filename,
00643 *option;
00644
00645
ChannelType
00646 channel;
00647
00648
double
00649 distortion;
00650
00651
Image
00652 *difference_image,
00653 *image,
00654 *reconstruct_image;
00655
00656
long
00657 j;
00658
00659
MagickStatusType
00660 status;
00661
00662
MetricType
00663 metric;
00664
00665
register long
00666 i;
00667
00668
00669
00670
00671
assert(image_info != (
ImageInfo *) NULL);
00672
assert(image_info->
signature ==
MagickSignature);
00673
if (image_info->
debug !=
MagickFalse)
00674 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),
"...");
00675
assert(exception != (
ExceptionInfo *) NULL);
00676
if (argc < 2)
00677
CompareUsage();
00678 channel=
AllChannels;
00679 difference_image=(
Image *) NULL;
00680 distortion=0.0;
00681 image=(
Image *) NULL;
00682 metric=
UndefinedMetric;
00683 option=(
char *) NULL;
00684 reconstruct_image=(
Image *) NULL;
00685
00686
00687
00688
ReadCommandlLine(argc,&argv);
00689 status=
ExpandFilenames(&argc,&argv);
00690
if (status ==
MagickFalse)
00691
ThrowCompareException(
ResourceLimitError,
"MemoryAllocationFailed",
00692 strerror(errno));
00693 j=1;
00694
for (i=1; i < (
long) (argc-1); i++)
00695 {
00696 option=argv[i];
00697
if ((strlen(option) == 1) || ((*option !=
'-') && (*option !=
'+')))
00698 {
00699
00700
00701
00702 filename=argv[i];
00703 (
void)
CopyMagickString(image_info->
filename,filename,
MaxTextExtent);
00704
if (image == (
Image *) NULL)
00705 {
00706 image=
ReadImage(image_info,exception);
00707
CatchException(exception);
00708
if (image != (
Image *) NULL)
00709 {
00710 status&=
MogrifyImages(image_info,(
int) (i-j),argv+j,&image);
00711
GetImageException(image,exception);
00712 }
00713 j=i+1;
00714
continue;
00715 }
00716
if (reconstruct_image != (
Image *) NULL)
00717
ThrowCompareException(
OptionError,
"InputImagesAlreadySpecified",
00718 filename);
00719 reconstruct_image=
ReadImage(image_info,exception);
00720
CatchException(exception);
00721 status&=reconstruct_image != (
Image *) NULL;
00722
continue;
00723 }
00724
switch (*(option+1))
00725 {
00726
case 'c':
00727 {
00728
if (
LocaleCompare(
"cache",option+1) == 0)
00729 {
00730
if (*option ==
'-')
00731 {
00732
unsigned long
00733 limit;
00734
00735 i++;
00736
if (i == (
long) argc)
00737
ThrowCompareException(
OptionError,
"MissingArgument",option);
00738
if (
IsGeometry(argv[i]) ==
MagickFalse)
00739
ThrowCompareInvalidArgumentException(option,argv[i]);
00740 limit=(~0UL);
00741
if (
LocaleCompare(
"unlimited",argv[i]) != 0)
00742 limit=(
unsigned long) atol(argv[i]);
00743 (
void)
SetMagickResourceLimit(
MemoryResource,limit);
00744 (
void)
SetMagickResourceLimit(
MapResource,2*limit);
00745 }
00746
break;
00747 }
00748
if (
LocaleCompare(
"channel",option+1) == 0)
00749 {
00750
if (*option ==
'-')
00751 {
00752 i++;
00753
if (i == (
long) argc)
00754
ThrowCompareException(
OptionError,
"MissingArgument",option);
00755 channel=(
ChannelType)
ParseMagickOption(
MagickChannelOptions,
00756
MagickTrue,argv[i]);
00757
if (channel <=
UndefinedChannel)
00758
ThrowCompareException(
OptionError,
"UnrecognizedChannelType",
00759 argv[i]);
00760 }
00761
break;
00762 }
00763
if (
LocaleCompare(
"colorspace",option+1) == 0)
00764 {
00765 image_info->
colorspace=
UndefinedColorspace;
00766
if (*option ==
'-')
00767 {
00768
long
00769 colorspace;
00770
00771 i++;
00772
if (i == (
long) (argc-1))
00773
ThrowCompareException(
OptionError,
"MissingArgument",option);
00774 colorspace=
ParseMagickOption(
MagickColorspaceOptions,
MagickFalse,
00775 argv[i]);
00776
if (colorspace < 0)
00777
ThrowCompareException(
OptionError,
"UnrecognizedColorspace",
00778 argv[i]);
00779 image_info->
colorspace=(
ColorspaceType) colorspace;
00780 }
00781
break;
00782 }
00783
if (
LocaleCompare(
"compress",option+1) == 0)
00784 {
00785 image_info->
compression=
UndefinedCompression;
00786
if (*option ==
'-')
00787 {
00788
long
00789 compression;
00790
00791 i++;
00792
if (i == (
long) (argc-1))
00793
ThrowCompareException(
OptionError,
"MissingArgument",option);
00794 compression=
ParseMagickOption(
MagickCompressionOptions,
00795
MagickFalse,argv[i]);
00796
if (compression < 0)
00797
ThrowCompareException(
OptionError,
00798
"UnrecognizedImageCompression",argv[i]);
00799 image_info->
compression=(
CompressionType) compression;
00800 }
00801
break;
00802 }
00803
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00804 }
00805
case 'd':
00806 {
00807
if (
LocaleCompare(
"debug",option+1) == 0)
00808 {
00809 (
void)
SetLogEventMask(
"None");
00810
if (*option ==
'-')
00811 {
00812
LogEventType
00813 event_mask;
00814
00815 i++;
00816
if (i == (
long) argc)
00817
ThrowCompareException(
OptionError,
"MissingArgument",option);
00818 event_mask=
SetLogEventMask(argv[i]);
00819
if (event_mask ==
UndefinedEvents)
00820
ThrowCompareException(
OptionError,
"UnrecognizedEventType",
00821 option);
00822 }
00823 image_info->
debug=
IsEventLogging();
00824
break;
00825 }
00826
if (
LocaleCompare(
"define",option+1) == 0)
00827 {
00828 i++;
00829
if (i == (
long) argc)
00830
ThrowCompareException(
OptionError,
"MissingArgument",option);
00831
if (*option ==
'+')
00832 {
00833
char
00834 *define;
00835
00836 define=
RemoveImageOption(image_info,argv[i]);
00837
if (define == (
char *) NULL)
00838
ThrowCompareException(
OptionError,
"NoSuchOption",argv[i]);
00839 define=(
char *)
RelinquishMagickMemory(define);
00840
break;
00841 }
00842 status=
DefineImageOption(image_info,argv[i]);
00843
if (status ==
MagickFalse)
00844
ThrowCompareException(
OptionError,
"UnrecognizedOption",argv[i]);
00845
break;
00846 }
00847
if (
LocaleCompare(
"density",option+1) == 0)
00848 {
00849 (
void)
CloneString(&image_info->
density,(
char *) NULL);
00850
if (*option ==
'-')
00851 {
00852 i++;
00853
if (i == (
long) argc)
00854
ThrowCompareException(
OptionError,
"MissingArgument",option);
00855
if (
IsGeometry(argv[i]) ==
MagickFalse)
00856
ThrowCompareInvalidArgumentException(option,argv[i]);
00857 (
void)
CloneString(&image_info->
density,argv[i]);
00858 }
00859
break;
00860 }
00861
if (
LocaleCompare(
"depth",option+1) == 0)
00862 {
00863 image_info->
depth=
QuantumDepth;
00864
if (*option ==
'-')
00865 {
00866 i++;
00867
if (i == (
long) argc)
00868
ThrowCompareException(
OptionError,
"MissingArgument",option);
00869
if (
IsGeometry(argv[i]) ==
MagickFalse)
00870
ThrowCompareInvalidArgumentException(option,argv[i]);
00871 image_info->
depth=(
unsigned long) atol(argv[i]);
00872 }
00873
break;
00874 }
00875
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00876 }
00877
case 'f':
00878 {
00879
if (
LocaleCompare(
"format",option+1) == 0)
00880 {
00881
if (*option ==
'-')
00882 {
00883 i++;
00884
if (i == (
long) argc)
00885
ThrowCompareException(
OptionError,
"MissingArgument",option);
00886 }
00887
break;
00888 }
00889
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00890 }
00891
case 'h':
00892 {
00893
if (
LocaleCompare(
"help",option+1) == 0)
00894
CompareUsage();
00895
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00896 }
00897
case 'i':
00898 {
00899
if (
LocaleCompare(
"interlace",option+1) == 0)
00900 {
00901 image_info->
interlace=
UndefinedInterlace;
00902
if (*option ==
'-')
00903 {
00904
long
00905 interlace;
00906
00907 i++;
00908
if (i == (
long) argc)
00909
ThrowCompareException(
OptionError,
"MissingArgument",option);
00910 interlace=
ParseMagickOption(
MagickInterlaceOptions,
MagickFalse,
00911 argv[i]);
00912
if (interlace < 0)
00913
ThrowCompareException(
OptionError,
"UnrecognizedInterlaceType",
00914 argv[i]);
00915 image->
interlace=(
InterlaceType) interlace;
00916 }
00917
break;
00918 }
00919
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00920 }
00921
case 'l':
00922 {
00923
if (
LocaleCompare(
"limit",option+1) == 0)
00924 {
00925
if (*option ==
'-')
00926 {
00927
char
00928 *type;
00929
00930
long
00931 resource;
00932
00933
unsigned long
00934 limit;
00935
00936 i++;
00937
if (i == (
long) argc)
00938
ThrowCompareException(
OptionError,
"MissingArgument",option);
00939 type=argv[i];
00940 i++;
00941
if (i == (
long) argc)
00942
ThrowCompareException(
OptionError,
"MissingArgument",option);
00943
if (
IsGeometry(argv[i]) ==
MagickFalse)
00944
ThrowCompareInvalidArgumentException(option,argv[i]);
00945 limit=(~0UL);
00946
if (
LocaleCompare(
"unlimited",argv[i]) != 0)
00947 limit=(
unsigned long) atol(argv[i]);
00948 resource=
ParseMagickOption(
MagickResourceOptions,
MagickFalse,
00949 type);
00950
if (resource < 0)
00951
ThrowCompareException(
OptionError,
00952
"UnrecognizedResourceType",type);
00953 (
void)
SetMagickResourceLimit((
ResourceType) resource,limit);
00954
break;
00955 }
00956
break;
00957 }
00958
if (
LocaleCompare(
"log",option+1) == 0)
00959 {
00960
if (*option ==
'-')
00961 {
00962 i++;
00963
if ((i == (
long) argc) || (
strchr(argv[i],
'%') == (
char *) NULL))
00964
ThrowCompareException(
OptionError,
"MissingArgument",option);
00965 (
void)
SetLogFormat(argv[i]);
00966 }
00967
break;
00968 }
00969
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00970 }
00971
case 'm':
00972 {
00973
if (
LocaleCompare(
"metric",option+1) == 0)
00974 {
00975
if (*option ==
'-')
00976 {
00977 i++;
00978
if (i == (
long) argc)
00979
ThrowCompareException(
OptionError,
"MissingArgument",option);
00980 metric=(
MetricType)
ParseMagickOption(
MagickMetricOptions,
00981
MagickTrue,argv[i]);
00982
if (metric <=
UndefinedMetric)
00983
ThrowCompareException(
OptionError,
"UnrecognizedMetricType",
00984 argv[i]);
00985 }
00986
break;
00987 }
00988
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
00989 }
00990
case 'p':
00991 {
00992
if (
LocaleCompare(
"profile",option+1) == 0)
00993 {
00994 i++;
00995
if (i == (
long) (argc-1))
00996
ThrowCompareException(
OptionError,
"MissingArgument",option);
00997
break;
00998 }
00999
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
01000 }
01001
case 'q':
01002 {
01003
if (
LocaleCompare(
"quality",option+1) == 0)
01004 {
01005 image_info->
quality=
UndefinedCompressionQuality;
01006
if (*option ==
'-')
01007 {
01008 i++;
01009
if (i == (
long) (argc-1))
01010
ThrowCompareException(
OptionError,
"MissingArgument",option);
01011
if (
IsGeometry(argv[i]) ==
MagickFalse)
01012
ThrowCompareInvalidArgumentException(option,argv[i]);
01013 image_info->
quality=(
unsigned long) atol(argv[i]);
01014 }
01015
break;
01016 }
01017
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
01018 }
01019
case 's':
01020 {
01021
if (
LocaleCompare(
"sampling-factor",option+1) == 0)
01022 {
01023 (
void)
CloneString(&image_info->
sampling_factor,(
char *) NULL);
01024
if (*option ==
'-')
01025 {
01026 i++;
01027
if (i == (
long) argc)
01028
ThrowCompareException(
OptionError,
"MissingArgument",option);
01029
if (
IsGeometry(argv[i]) ==
MagickFalse)
01030
ThrowCompareInvalidArgumentException(option,argv[i]);
01031 (
void)
CloneString(&image_info->
sampling_factor,argv[i]);
01032 }
01033
break;
01034 }
01035
if (
LocaleCompare(
"size",option+1) == 0)
01036 {
01037 (
void)
CloneString(&image_info->
size,(
char *) NULL);
01038
if (*option ==
'-')
01039 {
01040 i++;
01041
if (i == (
long) argc)
01042
ThrowCompareException(
OptionError,
"MissingArgument",option);
01043
if (
IsGeometry(argv[i]) ==
MagickFalse)
01044
ThrowCompareInvalidArgumentException(option,argv[i]);
01045 (
void)
CloneString(&image_info->
size,argv[i]);
01046 }
01047
break;
01048 }
01049
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
01050 }
01051
case 'v':
01052 {
01053
if (
LocaleCompare(
"verbose",option+1) == 0)
01054 {
01055 image_info->
verbose=(
MagickBooleanType) (*option ==
'-');
01056
break;
01057 }
01058
if (
LocaleCompare(
"version",option+1) == 0)
01059
break;
01060
if (
LocaleCompare(
"virtual-pixel",option+1) == 0)
01061 {
01062
if (*option ==
'-')
01063 {
01064
long
01065 method;
01066
01067 i++;
01068
if (i == (
long) (argc-1))
01069
ThrowCompareException(
OptionError,
"MissingArgument",option);
01070 method=
ParseMagickOption(
MagickVirtualPixelOptions,
MagickFalse,
01071 argv[i]);
01072
if (method < 0)
01073
ThrowCompareException(
OptionError,
01074
"UnrecognizedVirtualPixelMethod",argv[i]);
01075 }
01076
break;
01077 }
01078
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
01079 }
01080
case '?':
01081
break;
01082
default:
01083
ThrowCompareException(
OptionError,
"UnrecognizedOption",option)
01084 }
01085 }
01086 option=argv[i];
01087
if (
LocaleCompare(
"help",option+1) == 0)
01088
CompareUsage();
01089
if (i != (
long) (argc-1))
01090
ThrowCompareException(
OptionError,
"MissingAnImageFilename",argv[i]);
01091
if ((image == (
Image *) NULL) || (reconstruct_image == (
Image *) NULL))
01092
ThrowCompareException(
OptionError,
"MissingAnImageFilename",argv[i]);
01093 status&=
MogrifyImages(image_info,(
int) (i-j),argv+j,&reconstruct_image);
01094
GetImageException(image,exception);
01095 difference_image=
CompareImageChannels(image,reconstruct_image,channel,
01096 metric,&distortion,exception);
01097
if (difference_image != (
Image *) NULL)
01098 {
01099
if (image_info->
verbose !=
MagickFalse)
01100 (
void)
IsImagesEqual(image,reconstruct_image);
01101 difference_image->
error=image->
error;
01102 status&=
WriteImages(image_info,difference_image,argv[argc-1],exception);
01103
DestroyImageList(difference_image);
01104 }
01105
if (metric !=
UndefinedMetric)
01106 (
void) fprintf(stdout,
"%g dB\n",distortion);
01107
DestroyCompare();
01108
return(status != 0 ?
MagickTrue :
MagickFalse);
01109 }
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158 MagickExport MagickBooleanType IsImagesEqual(
Image *image,
01159
const Image *reconstruct_image)
01160 {
01161
IndexPacket
01162 *indexes,
01163 *reconstruct_indexes;
01164
01165
long
01166 y;
01167
01168
MagickBooleanType
01169 status;
01170
01171
MagickRealType
01172 area,
01173 distance,
01174 maximum_error,
01175 mean_error,
01176 mean_error_per_pixel;
01177
01178
register const PixelPacket
01179 *p,
01180 *q;
01181
01182
register long
01183 x;
01184
01185
assert(image != (
Image *) NULL);
01186
assert(image->
signature ==
MagickSignature);
01187
assert(reconstruct_image != (
const Image *) NULL);
01188
assert(reconstruct_image->
signature ==
MagickSignature);
01189
if ((reconstruct_image->
columns != image->
columns) ||
01190 (reconstruct_image->
rows != image->
rows))
01191
ThrowBinaryException(
ImageError,
"ImageSizeDiffers",image->
filename);
01192
if (image->
colorspace != reconstruct_image->
colorspace)
01193
ThrowBinaryException(
ImageError,
"ImageColorspaceDiffers",image->
filename);
01194
if (image->
matte != reconstruct_image->
matte)
01195
ThrowBinaryException(
ImageError,
"ImageOpacityDiffers",image->
filename);
01196 area=0.0;
01197 maximum_error=0.0;
01198 mean_error_per_pixel=0.0;
01199 mean_error=0.0;
01200
for (y=0; y < (
long) image->
rows; y++)
01201 {
01202 p=
AcquireImagePixels(image,0,y,image->
columns,1,&image->
exception);
01203 q=
AcquireImagePixels(reconstruct_image,0,y,reconstruct_image->
columns,1,
01204 &image->
exception);
01205
if ((p == (
const PixelPacket *) NULL) || (q == (
const PixelPacket *) NULL))
01206
break;
01207 indexes=
GetIndexes(image);
01208 reconstruct_indexes=
GetIndexes(reconstruct_image);
01209
for (x=0; x < (
long) image->
columns; x++)
01210 {
01211 distance=fabs(p->
red-(
MagickRealType) q->
red);
01212 mean_error_per_pixel+=distance;
01213 mean_error+=distance*distance;
01214
if (distance > maximum_error)
01215 maximum_error=distance;
01216 area++;
01217 distance=fabs(p->
green-(
MagickRealType) q->
green);
01218 mean_error_per_pixel+=distance;
01219 mean_error+=distance*distance;
01220
if (distance > maximum_error)
01221 maximum_error=distance;
01222 area++;
01223 distance=fabs(p->
blue-(
MagickRealType) q->
blue);
01224 mean_error_per_pixel+=distance;
01225 mean_error+=distance*distance;
01226
if (distance > maximum_error)
01227 maximum_error=distance;
01228 area++;
01229
if (image->
matte !=
MagickFalse)
01230 {
01231 distance=fabs(p->
opacity-(
MagickRealType) q->
opacity);
01232 mean_error_per_pixel+=distance;
01233 mean_error+=distance*distance;
01234
if (distance > maximum_error)
01235 maximum_error=distance;
01236 area++;
01237 }
01238
if (image->
colorspace ==
CMYKColorspace)
01239 {
01240 distance=fabs(indexes[x]-(
MagickRealType) reconstruct_indexes[x]);
01241 mean_error_per_pixel+=distance;
01242 mean_error+=distance*distance;
01243
if (distance > maximum_error)
01244 maximum_error=distance;
01245 area++;
01246 }
01247 p++;
01248 q++;
01249 }
01250 }
01251 image->
error.
mean_error_per_pixel=mean_error_per_pixel/area;
01252 image->
error.
normalized_mean_error=mean_error/area/
MaxRGB/
MaxRGB;
01253 image->
error.
normalized_maximum_error=maximum_error/
MaxRGB;
01254 status=(
MagickBooleanType)
01255 (image->
error.
mean_error_per_pixel == 0.0 ?
MagickTrue :
MagickFalse);
01256
return(status);
01257 }