1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % IIIII DDDD EEEEE N N TTTTT IIIII FFFFF Y Y % 7 % I D D E NN N T I F Y Y % 8 % I D D EEE N N N T I FFF Y % 9 % I D D E N NN T I F Y % 10 % IIIII DDDD EEEEE N N T IIIII F Y % 11 % % 12 % % 13 % Identify an Image Format and Characteristics. % 14 % % 15 % Software Design % 16 % Cristy % 17 % September 1994 % 18 % % 19 % % 20 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 21 % dedicated to making software imaging solutions freely available. % 22 % % 23 % You may not use this file except in compliance with the License. You may % 24 % obtain a copy of the License at % 25 % % 26 % http://www.imagemagick.org/script/license.php % 27 % % 28 % Unless required by applicable law or agreed to in writing, software % 29 % distributed under the License is distributed on an "AS IS" BASIS, % 30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 31 % See the License for the specific language governing permissions and % 32 % limitations under the License. % 33 % % 34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 % 36 % Identify describes the format and characteristics of one or more image 37 % files. It will also report if an image is incomplete or corrupt. 38 % 39 % 40 */ 41 42 /* 44 Include declarations. 45 */ 46 #include "MagickCore/studio.h" 47 #include "MagickCore/annotate.h" 48 #include "MagickCore/artifact.h" 49 #include "MagickCore/attribute.h" 50 #include "MagickCore/blob.h" 51 #include "MagickCore/cache.h" 52 #include "MagickCore/client.h" 53 #include "MagickCore/coder.h" 54 #include "MagickCore/color.h" 55 #include "MagickCore/configure.h" 56 #include "MagickCore/constitute.h" 57 #include "MagickCore/decorate.h" 58 #include "MagickCore/delegate.h" 59 #include "MagickCore/draw.h" 60 #include "MagickCore/effect.h" 61 #include "MagickCore/exception.h" 62 #include "MagickCore/exception-private.h" 63 #include "MagickCore/feature.h" 64 #include "MagickCore/gem.h" 65 #include "MagickCore/geometry.h" 66 #include "MagickCore/histogram.h" 67 #include "MagickCore/identify.h" 68 #include "MagickCore/image.h" 69 #include "MagickCore/image-private.h" 70 #include "MagickCore/list.h" 71 #include "MagickCore/locale_.h" 72 #include "MagickCore/log.h" 73 #include "MagickCore/magic.h" 74 #include "MagickCore/magick.h" 75 #include "MagickCore/memory_.h" 76 #include "MagickCore/module.h" 77 #include "MagickCore/monitor.h" 78 #include "MagickCore/montage.h" 79 #include "MagickCore/option.h" 80 #include "MagickCore/pixel-accessor.h" 81 #include "MagickCore/prepress.h" 82 #include "MagickCore/profile.h" 83 #include "MagickCore/property.h" 84 #include "MagickCore/quantize.h" 85 #include "MagickCore/quantum.h" 86 #include "MagickCore/random_.h" 87 #include "MagickCore/registry.h" 88 #include "MagickCore/resize.h" 89 #include "MagickCore/resource_.h" 90 #include "MagickCore/signature.h" 91 #include "MagickCore/statistic.h" 92 #include "MagickCore/string_.h" 93 #include "MagickCore/string-private.h" 94 #include "MagickCore/timer.h" 95 #include "MagickCore/token.h" 96 #include "MagickCore/utility.h" 97 #include "MagickCore/utility-private.h" 98 #include "MagickCore/version.h" 99 100 /* 102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 103 % % 104 % % 105 % % 106 % I d e n t i f y I m a g e % 107 % % 108 % % 109 % % 110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 111 % 112 % IdentifyImage() identifies an image by printing its attributes to the file. 113 % Attributes include the image width, height, size, and others. 114 % 115 % The format of the IdentifyImage method is: 116 % 117 % MagickBooleanType IdentifyImage(Image *image,FILE *file, 118 % const MagickBooleanType verbose,ExceptionInfo *exception) 119 % 120 % A description of each parameter follows: 121 % 122 % o image: the image. 123 % 124 % o file: the file, typically stdout. 125 % 126 % o verbose: A value other than zero prints more detailed information 127 % about the image. 128 % 129 % o exception: return any errors or warnings in this structure. 130 % 131 */ 132 133 static ChannelStatistics *GetLocationStatistics(const Image *image, 134 const StatisticType type,ExceptionInfo *exception) 135 { 136 ChannelStatistics 137 *channel_statistics; 138 139 register ssize_t 140 i; 141 142 ssize_t 143 y; 144 145 assert(image != (Image *) NULL); 146 assert(image->signature == MagickCoreSignature); 147 if (image->debug != MagickFalse) 148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 149 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory( 150 MaxPixelChannels+1,sizeof(*channel_statistics)); 151 if (channel_statistics == (ChannelStatistics *) NULL) 152 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 153 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)* 154 sizeof(*channel_statistics)); 155 for (i=0; i <= (ssize_t) MaxPixelChannels; i++) 156 { 157 switch (type) 158 { 159 case MaximumStatistic: 160 default: 161 { 162 channel_statistics[i].maxima=(-MagickMaximumValue); 163 break; 164 } 165 case MinimumStatistic: 166 { 167 channel_statistics[i].minima=MagickMaximumValue; 168 break; 169 } 170 } 171 } 172 for (y=0; y < (ssize_t) image->rows; y++) 173 { 174 register const Quantum 175 *magick_restrict p; 176 177 register ssize_t 178 x; 179 180 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 181 if (p == (const Quantum *) NULL) 182 break; 183 for (x=0; x < (ssize_t) image->columns; x++) 184 { 185 register ssize_t 186 i; 187 188 if (GetPixelReadMask(image,p) == 0) 189 { 190 p+=GetPixelChannels(image); 191 continue; 192 } 193 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 194 { 195 PixelChannel channel=GetPixelChannelChannel(image,i); 196 PixelTrait traits=GetPixelChannelTraits(image,channel); 197 if (traits == UndefinedPixelTrait) 198 continue; 199 switch (type) 200 { 201 case MaximumStatistic: 202 default: 203 { 204 if ((double) p[i] > channel_statistics[channel].maxima) 205 channel_statistics[channel].maxima=(double) p[i]; 206 break; 207 } 208 case MinimumStatistic: 209 { 210 if ((double) p[i] < channel_statistics[channel].minima) 211 channel_statistics[channel].minima=(double) p[i]; 212 break; 213 } 214 } 215 } 216 p+=GetPixelChannels(image); 217 } 218 } 219 return(channel_statistics); 220 } 221 222 static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel, 223 const char *name,const ChannelFeatures *channel_features) 224 { 225 #define PrintFeature(feature) \ 226 GetMagickPrecision(),(feature)[0], \ 227 GetMagickPrecision(),(feature)[1], \ 228 GetMagickPrecision(),(feature)[2], \ 229 GetMagickPrecision(),(feature)[3], \ 230 GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \ 231 232 #define FeaturesFormat " %s:\n" \ 233 " Angular Second Moment:\n" \ 234 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 235 " Contrast:\n" \ 236 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 237 " Correlation:\n" \ 238 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 239 " Sum of Squares Variance:\n" \ 240 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 241 " Inverse Difference Moment:\n" \ 242 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 243 " Sum Average:\n" \ 244 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 245 " Sum Variance:\n" \ 246 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 247 " Sum Entropy:\n" \ 248 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 249 " Entropy:\n" \ 250 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 251 " Difference Variance:\n" \ 252 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 253 " Difference Entropy:\n" \ 254 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 255 " Information Measure of Correlation 1:\n" \ 256 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 257 " Information Measure of Correlation 2:\n" \ 258 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 259 " Maximum Correlation Coefficient:\n" \ 260 " %.*g, %.*g, %.*g, %.*g, %.*g\n" 261 262 ssize_t 263 n; 264 265 n=FormatLocaleFile(file,FeaturesFormat,name, 266 PrintFeature(channel_features[channel].angular_second_moment), 267 PrintFeature(channel_features[channel].contrast), 268 PrintFeature(channel_features[channel].correlation), 269 PrintFeature(channel_features[channel].variance_sum_of_squares), 270 PrintFeature(channel_features[channel].inverse_difference_moment), 271 PrintFeature(channel_features[channel].sum_average), 272 PrintFeature(channel_features[channel].sum_variance), 273 PrintFeature(channel_features[channel].sum_entropy), 274 PrintFeature(channel_features[channel].entropy), 275 PrintFeature(channel_features[channel].difference_variance), 276 PrintFeature(channel_features[channel].difference_entropy), 277 PrintFeature(channel_features[channel].measure_of_correlation_1), 278 PrintFeature(channel_features[channel].measure_of_correlation_2), 279 PrintFeature(channel_features[channel].maximum_correlation_coefficient)); 280 return(n); 281 } 282 283 static ssize_t PrintChannelLocations(FILE *file,const Image *image, 284 const PixelChannel channel,const char *name,const StatisticType type, 285 const size_t max_locations,const ChannelStatistics *channel_statistics) 286 { 287 double 288 target; 289 290 ExceptionInfo 291 *exception; 292 293 ssize_t 294 n, 295 y; 296 297 switch (type) 298 { 299 case MaximumStatistic: 300 default: 301 { 302 target=channel_statistics[channel].maxima; 303 break; 304 } 305 case MinimumStatistic: 306 { 307 target=channel_statistics[channel].minima; 308 break; 309 } 310 } 311 (void) FormatLocaleFile(file," %s: %.*g (%.*g)",name,GetMagickPrecision(), 312 target,GetMagickPrecision(),QuantumScale*target); 313 exception=AcquireExceptionInfo(); 314 n=0; 315 for (y=0; y < (ssize_t) image->rows; y++) 316 { 317 register const Quantum 318 *p; 319 320 ssize_t 321 offset, 322 x; 323 324 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 325 if (p == (const Quantum *) NULL) 326 break; 327 for (x=0; x < (ssize_t) image->columns; x++) 328 { 329 MagickBooleanType 330 match; 331 332 PixelTrait traits=GetPixelChannelTraits(image,channel); 333 if (traits == UndefinedPixelTrait) 334 continue; 335 offset=GetPixelChannelOffset(image,channel); 336 match=fabs((double) (p[offset]-target)) < 0.5 ? MagickTrue : MagickFalse; 337 if (match != MagickFalse) 338 { 339 if ((max_locations != 0) && (n >= (ssize_t) max_locations)) 340 break; 341 (void) FormatLocaleFile(file," %.20g,%.20g",(double) x,(double) y); 342 n++; 343 } 344 p+=GetPixelChannels(image); 345 } 346 if (x < (ssize_t) image->columns) 347 break; 348 } 349 (void) FormatLocaleFile(file,"\n"); 350 return(n); 351 } 352 353 static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel, 354 const char *name,const double scale,const ChannelMoments *channel_moments) 355 { 356 double 357 powers[MaximumNumberOfImageMoments] = 358 { 1.0, 2.0, 3.0, 3.0, 6.0, 4.0, 6.0, 4.0 }; 359 360 register ssize_t 361 i; 362 363 ssize_t 364 n; 365 366 n=FormatLocaleFile(file," %s:\n",name); 367 n+=FormatLocaleFile(file," Centroid: %.*g,%.*g\n", 368 GetMagickPrecision(),channel_moments[channel].centroid.x, 369 GetMagickPrecision(),channel_moments[channel].centroid.y); 370 n+=FormatLocaleFile(file," Ellipse Semi-Major/Minor axis: %.*g,%.*g\n", 371 GetMagickPrecision(),channel_moments[channel].ellipse_axis.x, 372 GetMagickPrecision(),channel_moments[channel].ellipse_axis.y); 373 n+=FormatLocaleFile(file," Ellipse angle: %.*g\n", 374 GetMagickPrecision(),channel_moments[channel].ellipse_angle); 375 n+=FormatLocaleFile(file," Ellipse eccentricity: %.*g\n", 376 GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity); 377 n+=FormatLocaleFile(file," Ellipse intensity: %.*g (%.*g)\n", 378 GetMagickPrecision(),pow(scale,powers[0])* 379 channel_moments[channel].ellipse_intensity,GetMagickPrecision(), 380 channel_moments[channel].ellipse_intensity); 381 for (i=0; i < MaximumNumberOfImageMoments; i++) 382 n+=FormatLocaleFile(file," I%.20g: %.*g (%.*g)\n",i+1.0, 383 GetMagickPrecision(),channel_moments[channel].invariant[i]/pow(scale, 384 powers[i]),GetMagickPrecision(),channel_moments[channel].invariant[i]); 385 return(n); 386 } 387 388 static ssize_t PrintChannelPerceptualHash(FILE *file,const PixelChannel channel, 389 const char *name,const ChannelPerceptualHash *channel_phash) 390 { 391 register ssize_t 392 i; 393 394 ssize_t 395 n; 396 397 n=FormatLocaleFile(file," %s:\n",name); 398 for (i=0; i < MaximumNumberOfPerceptualHashes; i++) 399 n+=FormatLocaleFile(file," PH%.20g: %.*g, %.*g\n",i+1.0, 400 GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i], 401 GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]); 402 return(n); 403 } 404 405 static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel, 406 const char *name,const double scale, 407 const ChannelStatistics *channel_statistics) 408 { 409 #define StatisticsFormat " %s:\n min: " QuantumFormat \ 410 " (%g)\n max: " QuantumFormat " (%g)\n" \ 411 " mean: %g (%g)\n standard deviation: %g (%g)\n" \ 412 " kurtosis: %g\n skewness: %g\n entropy: %g\n" 413 414 ssize_t 415 n; 416 417 n=FormatLocaleFile(file,StatisticsFormat,name,ClampToQuantum((MagickRealType) 418 (scale*channel_statistics[channel].minima)), 419 channel_statistics[channel].minima/(double) QuantumRange,ClampToQuantum( 420 (MagickRealType) (scale*channel_statistics[channel].maxima)), 421 channel_statistics[channel].maxima/(double) QuantumRange,scale* 422 channel_statistics[channel].mean,channel_statistics[channel].mean/(double) 423 QuantumRange,scale*channel_statistics[channel].standard_deviation, 424 channel_statistics[channel].standard_deviation/(double) QuantumRange, 425 channel_statistics[channel].kurtosis,channel_statistics[channel].skewness, 426 channel_statistics[channel].entropy); 427 return(n); 428 } 429 430 MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file, 431 const MagickBooleanType verbose,ExceptionInfo *exception) 432 { 433 char 434 color[MagickPathExtent], 435 format[MagickPathExtent], 436 key[MagickPathExtent]; 437 438 ChannelFeatures 439 *channel_features; 440 441 ChannelMoments 442 *channel_moments; 443 444 ChannelPerceptualHash 445 *channel_phash; 446 447 ChannelStatistics 448 *channel_statistics; 449 450 ColorspaceType 451 colorspace; 452 453 const char 454 *artifact, 455 *locate, 456 *name, 457 *property, 458 *registry, 459 *value; 460 461 const MagickInfo 462 *magick_info; 463 464 double 465 elapsed_time, 466 scale, 467 user_time; 468 469 ImageType 470 base_type, 471 type; 472 473 MagickBooleanType 474 ping; 475 476 register const Quantum 477 *p; 478 479 register ssize_t 480 i, 481 x; 482 483 size_t 484 distance; 485 486 ssize_t 487 y; 488 489 assert(image != (Image *) NULL); 490 assert(image->signature == MagickCoreSignature); 491 if (image->debug != MagickFalse) 492 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 493 if (file == (FILE *) NULL) 494 file=stdout; 495 colorspace=image->colorspace; 496 type=IdentifyImageType(image,exception); 497 if ((type == BilevelType) || (type == GrayscaleType) || 498 (type == GrayscaleAlphaType)) 499 colorspace=GRAYColorspace; 500 locate=GetImageArtifact(image,"identify:locate"); 501 if (locate != (const char *) NULL) 502 { 503 const char 504 *limit; 505 506 size_t 507 max_locations; 508 509 StatisticType 510 type; 511 512 /* 513 Display minimum, maximum, or mean pixel locations. 514 */ 515 type=(StatisticType) ParseCommandOption(MagickStatisticOptions, 516 MagickFalse,locate); 517 limit=GetImageArtifact(image,"identify:limit"); 518 max_locations=0; 519 if (limit != (const char *) NULL) 520 max_locations=StringToUnsignedLong(limit); 521 channel_statistics=GetLocationStatistics(image,type,exception); 522 if (channel_statistics == (ChannelStatistics *) NULL) 523 return(MagickFalse); 524 (void) FormatLocaleFile(file,"Channel %s locations:\n",locate); 525 switch (colorspace) 526 { 527 case RGBColorspace: 528 default: 529 { 530 (void) PrintChannelLocations(file,image,RedPixelChannel,"Red", 531 type,max_locations,channel_statistics); 532 (void) PrintChannelLocations(file,image,GreenPixelChannel,"Green", 533 type,max_locations,channel_statistics); 534 (void) PrintChannelLocations(file,image,BluePixelChannel,"Blue", 535 type,max_locations,channel_statistics); 536 break; 537 } 538 case CMYKColorspace: 539 { 540 (void) PrintChannelLocations(file,image,CyanPixelChannel,"Cyan", 541 type,max_locations,channel_statistics); 542 (void) PrintChannelLocations(file,image,MagentaPixelChannel,"Magenta", 543 type,max_locations,channel_statistics); 544 (void) PrintChannelLocations(file,image,YellowPixelChannel,"Yellow", 545 type,max_locations,channel_statistics); 546 (void) PrintChannelLocations(file,image,BlackPixelChannel,"Black", 547 type,max_locations,channel_statistics); 548 break; 549 } 550 case GRAYColorspace: 551 { 552 (void) PrintChannelLocations(file,image,GrayPixelChannel,"Gray", 553 type,max_locations,channel_statistics); 554 break; 555 } 556 } 557 if (image->alpha_trait != UndefinedPixelTrait) 558 (void) PrintChannelLocations(file,image,AlphaPixelChannel,"Alpha", 559 type,max_locations,channel_statistics); 560 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( 561 channel_statistics); 562 return(ferror(file) != 0 ? MagickFalse : MagickTrue); 563 } 564 *format='\0'; 565 elapsed_time=GetElapsedTime(&image->timer); 566 user_time=GetUserTime(&image->timer); 567 GetTimerInfo(&image->timer); 568 if (verbose == MagickFalse) 569 { 570 /* 571 Display summary info about the image. 572 */ 573 if (*image->magick_filename != '\0') 574 if (LocaleCompare(image->magick_filename,image->filename) != 0) 575 (void) FormatLocaleFile(file,"%s=>",image->magick_filename); 576 if ((GetPreviousImageInList(image) == (Image *) NULL) && 577 (GetNextImageInList(image) == (Image *) NULL) && 578 (image->scene == 0)) 579 (void) FormatLocaleFile(file,"%s ",image->filename); 580 else 581 (void) FormatLocaleFile(file,"%s[%.20g] ",image->filename,(double) 582 image->scene); 583 (void) FormatLocaleFile(file,"%s ",image->magick); 584 if ((image->magick_columns != 0) || (image->magick_rows != 0)) 585 if ((image->magick_columns != image->columns) || 586 (image->magick_rows != image->rows)) 587 (void) FormatLocaleFile(file,"%.20gx%.20g=>",(double) 588 image->magick_columns,(double) image->magick_rows); 589 (void) FormatLocaleFile(file,"%.20gx%.20g ",(double) image->columns, 590 (double) image->rows); 591 if ((image->page.width != 0) || (image->page.height != 0) || 592 (image->page.x != 0) || (image->page.y != 0)) 593 (void) FormatLocaleFile(file,"%.20gx%.20g%+.20g%+.20g ",(double) 594 image->page.width,(double) image->page.height,(double) image->page.x, 595 (double) image->page.y); 596 (void) FormatLocaleFile(file,"%.20g-bit ",(double) image->depth); 597 if (image->type != UndefinedType) 598 (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic( 599 MagickTypeOptions,(ssize_t) image->type)); 600 if (image->colorspace != UndefinedColorspace) 601 (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic( 602 MagickColorspaceOptions,(ssize_t) image->colorspace)); 603 if (image->storage_class == DirectClass) 604 { 605 if (image->total_colors != 0) 606 { 607 (void) FormatMagickSize(image->total_colors,MagickFalse,"B", 608 MagickPathExtent,format); 609 (void) FormatLocaleFile(file,"%s ",format); 610 } 611 } 612 else 613 if (image->total_colors <= image->colors) 614 (void) FormatLocaleFile(file,"%.20gc ",(double) 615 image->colors); 616 else 617 (void) FormatLocaleFile(file,"%.20g=>%.20gc ",(double) 618 image->total_colors,(double) image->colors); 619 if (image->error.mean_error_per_pixel != 0.0) 620 (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double) 621 (image->error.mean_error_per_pixel+0.5), 622 image->error.normalized_mean_error, 623 image->error.normalized_maximum_error); 624 if (GetBlobSize(image) != 0) 625 { 626 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B", 627 MagickPathExtent,format); 628 (void) FormatLocaleFile(file,"%s ",format); 629 } 630 (void) FormatLocaleFile(file,"%0.3fu %lu:%02lu.%03lu",user_time, 631 (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod( 632 elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time- 633 floor(elapsed_time)))); 634 (void) FormatLocaleFile(file,"\n"); 635 (void) fflush(file); 636 return(ferror(file) != 0 ? MagickFalse : MagickTrue); 637 } 638 /* 639 Display verbose info about the image. 640 */ 641 p=GetVirtualPixels(image,0,0,1,1,exception); 642 ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse; 643 (void) SignatureImage(image,exception); 644 (void) FormatLocaleFile(file,"Image: %s\n",image->filename); 645 if (*image->magick_filename != '\0') 646 if (LocaleCompare(image->magick_filename,image->filename) != 0) 647 { 648 char 649 filename[MagickPathExtent]; 650 651 GetPathComponent(image->magick_filename,TailPath,filename); 652 (void) FormatLocaleFile(file," Base filename: %s\n",filename); 653 } 654 magick_info=GetMagickInfo(image->magick,exception); 655 if ((magick_info == (const MagickInfo *) NULL) || 656 (GetMagickDescription(magick_info) == (const char *) NULL)) 657 (void) FormatLocaleFile(file," Format: %s\n",image->magick); 658 else 659 (void) FormatLocaleFile(file," Format: %s (%s)\n",image->magick, 660 GetMagickDescription(magick_info)); 661 if ((magick_info != (const MagickInfo *) NULL) && 662 (GetMagickMimeType(magick_info) != (const char *) NULL)) 663 (void) FormatLocaleFile(file," Mime type: %s\n",GetMagickMimeType( 664 magick_info)); 665 (void) FormatLocaleFile(file," Class: %s\n",CommandOptionToMnemonic( 666 MagickClassOptions,(ssize_t) image->storage_class)); 667 (void) FormatLocaleFile(file," Geometry: %.20gx%.20g%+.20g%+.20g\n",(double) 668 image->columns,(double) image->rows,(double) image->tile_offset.x,(double) 669 image->tile_offset.y); 670 if ((image->magick_columns != 0) || (image->magick_rows != 0)) 671 if ((image->magick_columns != image->columns) || 672 (image->magick_rows != image->rows)) 673 (void) FormatLocaleFile(file," Base geometry: %.20gx%.20g\n",(double) 674 image->magick_columns,(double) image->magick_rows); 675 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0)) 676 { 677 (void) FormatLocaleFile(file," Resolution: %gx%g\n",image->resolution.x, 678 image->resolution.y); 679 (void) FormatLocaleFile(file," Print size: %gx%g\n",(double) 680 image->columns/image->resolution.x,(double) image->rows/ 681 image->resolution.y); 682 } 683 (void) FormatLocaleFile(file," Units: %s\n",CommandOptionToMnemonic( 684 MagickResolutionOptions,(ssize_t) image->units)); 685 (void) FormatLocaleFile(file," Type: %s\n",CommandOptionToMnemonic( 686 MagickTypeOptions,(ssize_t) type)); 687 base_type=GetImageType(image); 688 if (type != base_type) 689 (void) FormatLocaleFile(file," Base type: %s\n",CommandOptionToMnemonic( 690 MagickTypeOptions,(ssize_t) base_type)); 691 (void) FormatLocaleFile(file," Endianess: %s\n",CommandOptionToMnemonic( 692 MagickEndianOptions,(ssize_t) image->endian)); 693 /* 694 Detail channel depth and extrema. 695 */ 696 (void) FormatLocaleFile(file," Colorspace: %s\n",CommandOptionToMnemonic( 697 MagickColorspaceOptions,(ssize_t) image->colorspace)); 698 channel_statistics=(ChannelStatistics *) NULL; 699 channel_moments=(ChannelMoments *) NULL; 700 channel_phash=(ChannelPerceptualHash *) NULL; 701 channel_features=(ChannelFeatures *) NULL; 702 scale=1.0; 703 if (ping == MagickFalse) 704 { 705 size_t 706 depth; 707 708 channel_statistics=GetImageStatistics(image,exception); 709 if (channel_statistics == (ChannelStatistics *) NULL) 710 return(MagickFalse); 711 artifact=GetImageArtifact(image,"identify:moments"); 712 if (artifact != (const char *) NULL) 713 { 714 channel_moments=GetImageMoments(image,exception); 715 channel_phash=GetImagePerceptualHash(image,exception); 716 } 717 artifact=GetImageArtifact(image,"identify:features"); 718 if (artifact != (const char *) NULL) 719 { 720 distance=StringToUnsignedLong(artifact); 721 channel_features=GetImageFeatures(image,distance,exception); 722 } 723 depth=GetImageDepth(image,exception); 724 if (image->depth == depth) 725 (void) FormatLocaleFile(file," Depth: %.20g-bit\n",(double) 726 image->depth); 727 else 728 (void) FormatLocaleFile(file," Depth: %.20g/%.20g-bit\n",(double) 729 image->depth,(double) depth); 730 (void) FormatLocaleFile(file," Channel depth:\n"); 731 switch (colorspace) 732 { 733 case RGBColorspace: 734 default: 735 { 736 (void) FormatLocaleFile(file," Red: %.20g-bit\n",(double) 737 channel_statistics[RedPixelChannel].depth); 738 (void) FormatLocaleFile(file," Green: %.20g-bit\n",(double) 739 channel_statistics[GreenPixelChannel].depth); 740 (void) FormatLocaleFile(file," Blue: %.20g-bit\n",(double) 741 channel_statistics[BluePixelChannel].depth); 742 break; 743 } 744 case CMYKColorspace: 745 { 746 (void) FormatLocaleFile(file," Cyan: %.20g-bit\n",(double) 747 channel_statistics[CyanPixelChannel].depth); 748 (void) FormatLocaleFile(file," Magenta: %.20g-bit\n",(double) 749 channel_statistics[MagentaPixelChannel].depth); 750 (void) FormatLocaleFile(file," Yellow: %.20g-bit\n",(double) 751 channel_statistics[YellowPixelChannel].depth); 752 (void) FormatLocaleFile(file," Black: %.20g-bit\n",(double) 753 channel_statistics[BlackPixelChannel].depth); 754 break; 755 } 756 case GRAYColorspace: 757 { 758 (void) FormatLocaleFile(file," Gray: %.20g-bit\n",(double) 759 channel_statistics[GrayPixelChannel].depth); 760 break; 761 } 762 } 763 if (image->alpha_trait != UndefinedPixelTrait) 764 (void) FormatLocaleFile(file," Alpha: %.20g-bit\n",(double) 765 channel_statistics[AlphaPixelChannel].depth); 766 scale=1.0; 767 if (image->depth <= MAGICKCORE_QUANTUM_DEPTH) 768 scale=(double) QuantumRange/((size_t) QuantumRange >> ((size_t) 769 MAGICKCORE_QUANTUM_DEPTH-image->depth)); 770 } 771 if (channel_statistics != (ChannelStatistics *) NULL) 772 { 773 (void) FormatLocaleFile(file," Channel statistics:\n"); 774 (void) FormatLocaleFile(file," Pixels: %.20g\n",(double) 775 image->columns*image->rows); 776 switch (colorspace) 777 { 778 case RGBColorspace: 779 default: 780 { 781 (void) PrintChannelStatistics(file,RedPixelChannel,"Red",1.0/ 782 scale,channel_statistics); 783 (void) PrintChannelStatistics(file,GreenPixelChannel,"Green",1.0/ 784 scale,channel_statistics); 785 (void) PrintChannelStatistics(file,BluePixelChannel,"Blue",1.0/ 786 scale,channel_statistics); 787 break; 788 } 789 case CMYKColorspace: 790 { 791 (void) PrintChannelStatistics(file,CyanPixelChannel,"Cyan",1.0/ 792 scale,channel_statistics); 793 (void) PrintChannelStatistics(file,MagentaPixelChannel,"Magenta",1.0/ 794 scale,channel_statistics); 795 (void) PrintChannelStatistics(file,YellowPixelChannel,"Yellow",1.0/ 796 scale,channel_statistics); 797 (void) PrintChannelStatistics(file,BlackPixelChannel,"Black",1.0/ 798 scale,channel_statistics); 799 break; 800 } 801 case GRAYColorspace: 802 { 803 (void) PrintChannelStatistics(file,GrayPixelChannel,"Gray",1.0/ 804 scale,channel_statistics); 805 break; 806 } 807 } 808 if (image->alpha_trait != UndefinedPixelTrait) 809 (void) PrintChannelStatistics(file,AlphaPixelChannel,"Alpha",1.0/ 810 scale,channel_statistics); 811 if (colorspace != GRAYColorspace) 812 { 813 (void) FormatLocaleFile(file," Image statistics:\n"); 814 (void) PrintChannelStatistics(file,(PixelChannel) MaxPixelChannels, 815 "Overall",1.0/scale,channel_statistics); 816 } 817 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( 818 channel_statistics); 819 } 820 if (channel_moments != (ChannelMoments *) NULL) 821 { 822 scale=(double) ((1UL << image->depth)-1); 823 (void) FormatLocaleFile(file," Channel moments:\n"); 824 switch (colorspace) 825 { 826 case RGBColorspace: 827 default: 828 { 829 (void) PrintChannelMoments(file,RedPixelChannel,"Red",scale, 830 channel_moments); 831 (void) PrintChannelMoments(file,GreenPixelChannel,"Green",scale, 832 channel_moments); 833 (void) PrintChannelMoments(file,BluePixelChannel,"Blue",scale, 834 channel_moments); 835 break; 836 } 837 case CMYKColorspace: 838 { 839 (void) PrintChannelMoments(file,CyanPixelChannel,"Cyan",scale, 840 channel_moments); 841 (void) PrintChannelMoments(file,MagentaPixelChannel,"Magenta",scale, 842 channel_moments); 843 (void) PrintChannelMoments(file,YellowPixelChannel,"Yellow",scale, 844 channel_moments); 845 (void) PrintChannelMoments(file,BlackPixelChannel,"Black",scale, 846 channel_moments); 847 break; 848 } 849 case GRAYColorspace: 850 { 851 (void) PrintChannelMoments(file,GrayPixelChannel,"Gray",scale, 852 channel_moments); 853 break; 854 } 855 } 856 if (image->alpha_trait != UndefinedPixelTrait) 857 (void) PrintChannelMoments(file,AlphaPixelChannel,"Alpha",scale, 858 channel_moments); 859 if (colorspace != GRAYColorspace) 860 { 861 (void) FormatLocaleFile(file," Image moments:\n"); 862 (void) PrintChannelMoments(file,(PixelChannel) MaxPixelChannels, 863 "Overall",scale,channel_moments); 864 } 865 channel_moments=(ChannelMoments *) RelinquishMagickMemory( 866 channel_moments); 867 } 868 if (channel_phash != (ChannelPerceptualHash *) NULL) 869 { 870 (void) FormatLocaleFile(file," Channel perceptual hash:\n"); 871 (void) PrintChannelPerceptualHash(file,RedPixelChannel,"Red, Hue", 872 channel_phash); 873 (void) PrintChannelPerceptualHash(file,GreenPixelChannel,"Green, Chroma", 874 channel_phash); 875 (void) PrintChannelPerceptualHash(file,BluePixelChannel,"Blue, Luma", 876 channel_phash); 877 if (image->alpha_trait != UndefinedPixelTrait) 878 (void) PrintChannelPerceptualHash(file,AlphaPixelChannel,"Alpha, Alpha", 879 channel_phash); 880 channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory( 881 channel_phash); 882 } 883 if (channel_features != (ChannelFeatures *) NULL) 884 { 885 (void) FormatLocaleFile(file," Channel features (horizontal, vertical, " 886 "left and right diagonals, average):\n"); 887 switch (colorspace) 888 { 889 case RGBColorspace: 890 default: 891 { 892 (void) PrintChannelFeatures(file,RedPixelChannel,"Red", 893 channel_features); 894 (void) PrintChannelFeatures(file,GreenPixelChannel,"Green", 895 channel_features); 896 (void) PrintChannelFeatures(file,BluePixelChannel,"Blue", 897 channel_features); 898 break; 899 } 900 case CMYKColorspace: 901 { 902 (void) PrintChannelFeatures(file,CyanPixelChannel,"Cyan", 903 channel_features); 904 (void) PrintChannelFeatures(file,MagentaPixelChannel,"Magenta", 905 channel_features); 906 (void) PrintChannelFeatures(file,YellowPixelChannel,"Yellow", 907 channel_features); 908 (void) PrintChannelFeatures(file,BlackPixelChannel,"Black", 909 channel_features); 910 break; 911 } 912 case GRAYColorspace: 913 { 914 (void) PrintChannelFeatures(file,GrayPixelChannel,"Gray", 915 channel_features); 916 break; 917 } 918 } 919 if (image->alpha_trait != UndefinedPixelTrait) 920 (void) PrintChannelFeatures(file,AlphaPixelChannel,"Alpha", 921 channel_features); 922 channel_features=(ChannelFeatures *) RelinquishMagickMemory( 923 channel_features); 924 } 925 if (ping == MagickFalse) 926 { 927 if (image->colorspace == CMYKColorspace) 928 (void) FormatLocaleFile(file," Total ink density: %*g%%\n", 929 GetMagickPrecision(),100.0*GetImageTotalInkDensity(image,exception)/ 930 (double) QuantumRange); 931 x=0; 932 if (image->alpha_trait != UndefinedPixelTrait) 933 { 934 register const Quantum 935 *p; 936 937 p=(const Quantum *) NULL; 938 for (y=0; y < (ssize_t) image->rows; y++) 939 { 940 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 941 if (p == (const Quantum *) NULL) 942 break; 943 for (x=0; x < (ssize_t) image->columns; x++) 944 { 945 if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha) 946 break; 947 p+=GetPixelChannels(image); 948 } 949 if (x < (ssize_t) image->columns) 950 break; 951 } 952 if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows)) 953 { 954 char 955 tuple[MagickPathExtent]; 956 957 PixelInfo 958 pixel; 959 960 GetPixelInfo(image,&pixel); 961 GetPixelInfoPixel(image,p,&pixel); 962 (void) QueryColorname(image,&pixel,SVGCompliance,tuple, 963 exception); 964 (void) FormatLocaleFile(file," Alpha: %s ",tuple); 965 GetColorTuple(&pixel,MagickTrue,tuple); 966 (void) FormatLocaleFile(file," %s\n",tuple); 967 } 968 } 969 if (IsHistogramImage(image,exception) != MagickFalse) 970 { 971 (void) FormatLocaleFile(file," Colors: %.20g\n",(double) 972 GetNumberColors(image,(FILE *) NULL,exception)); 973 (void) FormatLocaleFile(file," Histogram:\n"); 974 (void) GetNumberColors(image,file,exception); 975 } 976 else 977 { 978 artifact=GetImageArtifact(image,"identify:unique-colors"); 979 if (IsStringTrue(artifact) != MagickFalse) 980 (void) FormatLocaleFile(file," Colors: %.20g\n",(double) 981 GetNumberColors(image,(FILE *) NULL,exception)); 982 } 983 } 984 if (image->storage_class == PseudoClass) 985 { 986 (void) FormatLocaleFile(file," Colormap entries: %.20g\n",(double) 987 image->colors); 988 (void) FormatLocaleFile(file," Colormap:\n"); 989 if (image->colors <= 1024) 990 { 991 char 992 color[MagickPathExtent], 993 hex[MagickPathExtent], 994 tuple[MagickPathExtent]; 995 996 PixelInfo 997 pixel; 998 999 register PixelInfo 1000 *magick_restrict p; 1001 1002 GetPixelInfo(image,&pixel); 1003 p=image->colormap; 1004 for (i=0; i < (ssize_t) image->colors; i++) 1005 { 1006 pixel=(*p); 1007 (void) CopyMagickString(tuple,"(",MagickPathExtent); 1008 ConcatenateColorComponent(&pixel,RedPixelChannel,X11Compliance, 1009 tuple); 1010 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 1011 ConcatenateColorComponent(&pixel,GreenPixelChannel,X11Compliance, 1012 tuple); 1013 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 1014 ConcatenateColorComponent(&pixel,BluePixelChannel,X11Compliance, 1015 tuple); 1016 if (pixel.colorspace == CMYKColorspace) 1017 { 1018 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 1019 ConcatenateColorComponent(&pixel,BlackPixelChannel, 1020 X11Compliance,tuple); 1021 } 1022 if (pixel.alpha_trait != UndefinedPixelTrait) 1023 { 1024 (void) ConcatenateMagickString(tuple,",",MagickPathExtent); 1025 ConcatenateColorComponent(&pixel,AlphaPixelChannel, 1026 X11Compliance,tuple); 1027 } 1028 (void) ConcatenateMagickString(tuple,")",MagickPathExtent); 1029 (void) QueryColorname(image,&pixel,SVGCompliance,color, 1030 exception); 1031 GetColorTuple(&pixel,MagickTrue,hex); 1032 (void) FormatLocaleFile(file," %8ld: %s %s %s\n",(long) i,tuple, 1033 hex,color); 1034 p++; 1035 } 1036 } 1037 } 1038 if (image->error.mean_error_per_pixel != 0.0) 1039 (void) FormatLocaleFile(file," Mean error per pixel: %g\n", 1040 image->error.mean_error_per_pixel); 1041 if (image->error.normalized_mean_error != 0.0) 1042 (void) FormatLocaleFile(file," Normalized mean error: %g\n", 1043 image->error.normalized_mean_error); 1044 if (image->error.normalized_maximum_error != 0.0) 1045 (void) FormatLocaleFile(file," Normalized maximum error: %g\n", 1046 image->error.normalized_maximum_error); 1047 (void) FormatLocaleFile(file," Rendering intent: %s\n", 1048 CommandOptionToMnemonic(MagickIntentOptions,(ssize_t) 1049 image->rendering_intent)); 1050 if (image->gamma != 0.0) 1051 (void) FormatLocaleFile(file," Gamma: %g\n",image->gamma); 1052 if ((image->chromaticity.red_primary.x != 0.0) || 1053 (image->chromaticity.green_primary.x != 0.0) || 1054 (image->chromaticity.blue_primary.x != 0.0) || 1055 (image->chromaticity.white_point.x != 0.0)) 1056 { 1057 /* 1058 Display image chromaticity. 1059 */ 1060 (void) FormatLocaleFile(file," Chromaticity:\n"); 1061 (void) FormatLocaleFile(file," red primary: (%g,%g)\n", 1062 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y); 1063 (void) FormatLocaleFile(file," green primary: (%g,%g)\n", 1064 image->chromaticity.green_primary.x, 1065 image->chromaticity.green_primary.y); 1066 (void) FormatLocaleFile(file," blue primary: (%g,%g)\n", 1067 image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y); 1068 (void) FormatLocaleFile(file," white point: (%g,%g)\n", 1069 image->chromaticity.white_point.x,image->chromaticity.white_point.y); 1070 } 1071 if ((image->extract_info.width*image->extract_info.height) != 0) 1072 (void) FormatLocaleFile(file," Tile geometry: %.20gx%.20g%+.20g%+.20g\n", 1073 (double) image->extract_info.width,(double) image->extract_info.height, 1074 (double) image->extract_info.x,(double) image->extract_info.y); 1075 (void) QueryColorname(image,&image->alpha_color,SVGCompliance,color, 1076 exception); 1077 (void) FormatLocaleFile(file," Alpha color: %s\n",color); 1078 (void) QueryColorname(image,&image->background_color,SVGCompliance,color, 1079 exception); 1080 (void) FormatLocaleFile(file," Background color: %s\n",color); 1081 (void) QueryColorname(image,&image->border_color,SVGCompliance,color, 1082 exception); 1083 (void) FormatLocaleFile(file," Border color: %s\n",color); 1084 (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color, 1085 exception); 1086 (void) FormatLocaleFile(file," Transparent color: %s\n",color); 1087 (void) FormatLocaleFile(file," Interlace: %s\n",CommandOptionToMnemonic( 1088 MagickInterlaceOptions,(ssize_t) image->interlace)); 1089 (void) FormatLocaleFile(file," Intensity: %s\n",CommandOptionToMnemonic( 1090 MagickPixelIntensityOptions,(ssize_t) image->intensity)); 1091 (void) FormatLocaleFile(file," Compose: %s\n",CommandOptionToMnemonic( 1092 MagickComposeOptions,(ssize_t) image->compose)); 1093 if ((image->page.width != 0) || (image->page.height != 0) || 1094 (image->page.x != 0) || (image->page.y != 0)) 1095 (void) FormatLocaleFile(file," Page geometry: %.20gx%.20g%+.20g%+.20g\n", 1096 (double) image->page.width,(double) image->page.height,(double) 1097 image->page.x,(double) image->page.y); 1098 if ((image->page.x != 0) || (image->page.y != 0)) 1099 (void) FormatLocaleFile(file," Origin geometry: %+.20g%+.20g\n",(double) 1100 image->page.x,(double) image->page.y); 1101 (void) FormatLocaleFile(file," Dispose: %s\n",CommandOptionToMnemonic( 1102 MagickDisposeOptions,(ssize_t) image->dispose)); 1103 if (image->delay != 0) 1104 (void) FormatLocaleFile(file," Delay: %.20gx%.20g\n",(double) image->delay, 1105 (double) image->ticks_per_second); 1106 if (image->iterations != 1) 1107 (void) FormatLocaleFile(file," Iterations: %.20g\n",(double) 1108 image->iterations); 1109 if (image->duration != 0) 1110 (void) FormatLocaleFile(file," Duration: %.20g\n",(double) 1111 image->duration); 1112 if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL)) 1113 (void) FormatLocaleFile(file," Scene: %.20g of %.20g\n",(double) 1114 image->scene,(double) GetImageListLength(image)); 1115 else 1116 if (image->scene != 0) 1117 (void) FormatLocaleFile(file," Scene: %.20g\n",(double) image->scene); 1118 (void) FormatLocaleFile(file," Compression: %s\n",CommandOptionToMnemonic( 1119 MagickCompressOptions,(ssize_t) image->compression)); 1120 if (image->quality != UndefinedCompressionQuality) 1121 (void) FormatLocaleFile(file," Quality: %.20g\n",(double) image->quality); 1122 (void) FormatLocaleFile(file," Orientation: %s\n",CommandOptionToMnemonic( 1123 MagickOrientationOptions,(ssize_t) image->orientation)); 1124 if (image->montage != (char *) NULL) 1125 (void) FormatLocaleFile(file," Montage: %s\n",image->montage); 1126 if (image->directory != (char *) NULL) 1127 { 1128 Image 1129 *tile; 1130 1131 ImageInfo 1132 *image_info; 1133 1134 register char 1135 *p, 1136 *q; 1137 1138 WarningHandler 1139 handler; 1140 1141 /* 1142 Display visual image directory. 1143 */ 1144 image_info=AcquireImageInfo(); 1145 (void) CloneString(&image_info->size,"64x64"); 1146 (void) FormatLocaleFile(file," Directory:\n"); 1147 for (p=image->directory; *p != '\0'; p++) 1148 { 1149 q=p; 1150 while ((*q != '\n') && (*q != '\0')) 1151 q++; 1152 (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1)); 1153 p=q; 1154 (void) FormatLocaleFile(file," %s",image_info->filename); 1155 handler=SetWarningHandler((WarningHandler) NULL); 1156 tile=ReadImage(image_info,exception); 1157 (void) SetWarningHandler(handler); 1158 if (tile == (Image *) NULL) 1159 { 1160 (void) FormatLocaleFile(file,"\n"); 1161 continue; 1162 } 1163 (void) FormatLocaleFile(file," %.20gx%.20g %s\n",(double) 1164 tile->magick_columns,(double) tile->magick_rows,tile->magick); 1165 (void) SignatureImage(tile,exception); 1166 ResetImagePropertyIterator(tile); 1167 property=GetNextImageProperty(tile); 1168 while (property != (const char *) NULL) 1169 { 1170 (void) FormatLocaleFile(file," %s:\n",property); 1171 value=GetImageProperty(tile,property,exception); 1172 if (value != (const char *) NULL) 1173 (void) FormatLocaleFile(file,"%s\n",value); 1174 property=GetNextImageProperty(tile); 1175 } 1176 tile=DestroyImage(tile); 1177 } 1178 image_info=DestroyImageInfo(image_info); 1179 } 1180 (void) GetImageProperty(image,"exif:*",exception); 1181 (void) GetImageProperty(image,"icc:*",exception); 1182 (void) GetImageProperty(image,"iptc:*",exception); 1183 (void) GetImageProperty(image,"xmp:*",exception); 1184 ResetImagePropertyIterator(image); 1185 property=GetNextImageProperty(image); 1186 if (property != (const char *) NULL) 1187 { 1188 /* 1189 Display image properties. 1190 */ 1191 (void) FormatLocaleFile(file," Properties:\n"); 1192 while (property != (const char *) NULL) 1193 { 1194 (void) FormatLocaleFile(file," %s: ",property); 1195 value=GetImageProperty(image,property,exception); 1196 if (value != (const char *) NULL) 1197 (void) FormatLocaleFile(file,"%s\n",value); 1198 property=GetNextImageProperty(image); 1199 } 1200 } 1201 (void) FormatLocaleString(key,MagickPathExtent,"8BIM:1999,2998:#1"); 1202 value=GetImageProperty(image,key,exception); 1203 if (value != (const char *) NULL) 1204 { 1205 /* 1206 Display clipping path. 1207 */ 1208 (void) FormatLocaleFile(file," Clipping path: "); 1209 if (strlen(value) > 80) 1210 (void) fputc('\n',file); 1211 (void) FormatLocaleFile(file,"%s\n",value); 1212 } 1213 ResetImageProfileIterator(image); 1214 name=GetNextImageProfile(image); 1215 if (name != (char *) NULL) 1216 { 1217 const StringInfo 1218 *profile; 1219 1220 /* 1221 Identify image profiles. 1222 */ 1223 (void) FormatLocaleFile(file," Profiles:\n"); 1224 while (name != (char *) NULL) 1225 { 1226 profile=GetImageProfile(image,name); 1227 if (profile == (StringInfo *) NULL) 1228 continue; 1229 (void) FormatLocaleFile(file," Profile-%s: %.20g bytes\n",name, 1230 (double) GetStringInfoLength(profile)); 1231 if (LocaleCompare(name,"iptc") == 0) 1232 { 1233 char 1234 *attribute, 1235 **attribute_list; 1236 1237 const char 1238 *tag; 1239 1240 long 1241 dataset, 1242 record, 1243 sentinel; 1244 1245 register ssize_t 1246 j; 1247 1248 size_t 1249 length, 1250 profile_length; 1251 1252 profile_length=GetStringInfoLength(profile); 1253 for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length) 1254 { 1255 length=1; 1256 sentinel=GetStringInfoDatum(profile)[i++]; 1257 if (sentinel != 0x1c) 1258 continue; 1259 dataset=GetStringInfoDatum(profile)[i++]; 1260 record=GetStringInfoDatum(profile)[i++]; 1261 switch (record) 1262 { 1263 case 5: tag="Image Name"; break; 1264 case 7: tag="Edit Status"; break; 1265 case 10: tag="Priority"; break; 1266 case 15: tag="Category"; break; 1267 case 20: tag="Supplemental Category"; break; 1268 case 22: tag="Fixture Identifier"; break; 1269 case 25: tag="Keyword"; break; 1270 case 30: tag="Release Date"; break; 1271 case 35: tag="Release Time"; break; 1272 case 40: tag="Special Instructions"; break; 1273 case 45: tag="Reference Service"; break; 1274 case 47: tag="Reference Date"; break; 1275 case 50: tag="Reference Number"; break; 1276 case 55: tag="Created Date"; break; 1277 case 60: tag="Created Time"; break; 1278 case 65: tag="Originating Program"; break; 1279 case 70: tag="Program Version"; break; 1280 case 75: tag="Object Cycle"; break; 1281 case 80: tag="Byline"; break; 1282 case 85: tag="Byline Title"; break; 1283 case 90: tag="City"; break; 1284 case 92: tag="Sub-Location"; break; 1285 case 95: tag="Province State"; break; 1286 case 100: tag="Country Code"; break; 1287 case 101: tag="Country"; break; 1288 case 103: tag="Original Transmission Reference"; break; 1289 case 105: tag="Headline"; break; 1290 case 110: tag="Credit"; break; 1291 case 115: tag="Src"; break; 1292 case 116: tag="Copyright String"; break; 1293 case 120: tag="Caption"; break; 1294 case 121: tag="Local Caption"; break; 1295 case 122: tag="Caption Writer"; break; 1296 case 200: tag="Custom Field 1"; break; 1297 case 201: tag="Custom Field 2"; break; 1298 case 202: tag="Custom Field 3"; break; 1299 case 203: tag="Custom Field 4"; break; 1300 case 204: tag="Custom Field 5"; break; 1301 case 205: tag="Custom Field 6"; break; 1302 case 206: tag="Custom Field 7"; break; 1303 case 207: tag="Custom Field 8"; break; 1304 case 208: tag="Custom Field 9"; break; 1305 case 209: tag="Custom Field 10"; break; 1306 case 210: tag="Custom Field 11"; break; 1307 case 211: tag="Custom Field 12"; break; 1308 case 212: tag="Custom Field 13"; break; 1309 case 213: tag="Custom Field 14"; break; 1310 case 214: tag="Custom Field 15"; break; 1311 case 215: tag="Custom Field 16"; break; 1312 case 216: tag="Custom Field 17"; break; 1313 case 217: tag="Custom Field 18"; break; 1314 case 218: tag="Custom Field 19"; break; 1315 case 219: tag="Custom Field 20"; break; 1316 default: tag="unknown"; break; 1317 } 1318 (void) FormatLocaleFile(file," %s[%.20g,%.20g]: ",tag, 1319 (double) dataset,(double) record); 1320 length=(size_t) (GetStringInfoDatum(profile)[i++] << 8); 1321 length|=GetStringInfoDatum(profile)[i++]; 1322 attribute=(char *) NULL; 1323 if (~length >= (MagickPathExtent-1)) 1324 attribute=(char *) AcquireQuantumMemory(length+MagickPathExtent, 1325 sizeof(*attribute)); 1326 if (attribute != (char *) NULL) 1327 { 1328 (void) CopyMagickString(attribute,(char *) 1329 GetStringInfoDatum(profile)+i,length+1); 1330 attribute_list=StringToList(attribute); 1331 if (attribute_list != (char **) NULL) 1332 { 1333 for (j=0; attribute_list[j] != (char *) NULL; j++) 1334 { 1335 (void) fputs(attribute_list[j],file); 1336 (void) fputs("\n",file); 1337 attribute_list[j]=(char *) RelinquishMagickMemory( 1338 attribute_list[j]); 1339 } 1340 attribute_list=(char **) RelinquishMagickMemory( 1341 attribute_list); 1342 } 1343 attribute=DestroyString(attribute); 1344 } 1345 } 1346 } 1347 if (image->debug != MagickFalse) 1348 PrintStringInfo(file,name,profile); 1349 name=GetNextImageProfile(image); 1350 } 1351 } 1352 ResetImageArtifactIterator(image); 1353 artifact=GetNextImageArtifact(image); 1354 if (artifact != (const char *) NULL) 1355 { 1356 /* 1357 Display image artifacts. 1358 */ 1359 (void) FormatLocaleFile(file," Artifacts:\n"); 1360 while (artifact != (const char *) NULL) 1361 { 1362 (void) FormatLocaleFile(file," %s: ",artifact); 1363 value=GetImageArtifact(image,artifact); 1364 if (value != (const char *) NULL) 1365 (void) FormatLocaleFile(file,"%s\n",value); 1366 artifact=GetNextImageArtifact(image); 1367 } 1368 } 1369 ResetImageRegistryIterator(); 1370 registry=GetNextImageRegistry(); 1371 if (registry != (const char *) NULL) 1372 { 1373 /* 1374 Display image registry. 1375 */ 1376 (void) FormatLocaleFile(file," Registry:\n"); 1377 while (registry != (const char *) NULL) 1378 { 1379 (void) FormatLocaleFile(file," %s: ",registry); 1380 value=(const char *) GetImageRegistry(StringRegistryType,registry, 1381 exception); 1382 if (value != (const char *) NULL) 1383 (void) FormatLocaleFile(file,"%s\n",value); 1384 registry=GetNextImageRegistry(); 1385 } 1386 } 1387 (void) FormatLocaleFile(file," Tainted: %s\n",CommandOptionToMnemonic( 1388 MagickBooleanOptions,(ssize_t) image->taint)); 1389 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",MagickPathExtent, 1390 format); 1391 (void) FormatLocaleFile(file," Filesize: %s\n",format); 1392 (void) FormatMagickSize((MagickSizeType) image->columns*image->rows, 1393 MagickFalse,"B",MagickPathExtent,format); 1394 if (strlen(format) > 1) 1395 format[strlen(format)-1]='\0'; 1396 (void) FormatLocaleFile(file," Number pixels: %s\n",format); 1397 (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/ 1398 elapsed_time+0.5),MagickFalse,"B",MagickPathExtent,format); 1399 (void) FormatLocaleFile(file," Pixels per second: %s\n",format); 1400 (void) FormatLocaleFile(file," User time: %0.3fu\n",user_time); 1401 (void) FormatLocaleFile(file," Elapsed time: %lu:%02lu.%03lu\n", 1402 (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(elapsed_time, 1403 60.0)),(unsigned long) (1000.0*(elapsed_time-floor(elapsed_time)))); 1404 (void) FormatLocaleFile(file," Version: %s\n",GetMagickVersion((size_t *) 1405 NULL)); 1406 (void) fflush(file); 1407 return(ferror(file) != 0 ? MagickFalse : MagickTrue); 1408 } 1409