identify.c revision a403727ea73ef5840a476a3c4614445807f42827
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% John Cristy % 17% September 1994 % 18% % 19% % 20% Copyright 1999-2008 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/* 43 Include declarations. 44*/ 45#include "MagickCore/studio.h" 46#include "MagickCore/annotate.h" 47#include "MagickCore/artifact.h" 48#include "MagickCore/attribute.h" 49#include "MagickCore/blob.h" 50#include "MagickCore/cache.h" 51#include "MagickCore/client.h" 52#include "MagickCore/coder.h" 53#include "MagickCore/color.h" 54#include "MagickCore/configure.h" 55#include "MagickCore/constitute.h" 56#include "MagickCore/decorate.h" 57#include "MagickCore/delegate.h" 58#include "MagickCore/draw.h" 59#include "MagickCore/effect.h" 60#include "MagickCore/exception.h" 61#include "MagickCore/exception-private.h" 62#include "MagickCore/feature.h" 63#include "MagickCore/gem.h" 64#include "MagickCore/geometry.h" 65#include "MagickCore/histogram.h" 66#include "MagickCore/identify.h" 67#include "MagickCore/image.h" 68#include "MagickCore/image-private.h" 69#include "MagickCore/list.h" 70#include "MagickCore/locale_.h" 71#include "MagickCore/log.h" 72#include "MagickCore/magic.h" 73#include "MagickCore/magick.h" 74#include "MagickCore/memory_.h" 75#include "MagickCore/module.h" 76#include "MagickCore/monitor.h" 77#include "MagickCore/montage.h" 78#include "MagickCore/option.h" 79#include "MagickCore/pixel-accessor.h" 80#include "MagickCore/prepress.h" 81#include "MagickCore/profile.h" 82#include "MagickCore/property.h" 83#include "MagickCore/quantize.h" 84#include "MagickCore/quantum.h" 85#include "MagickCore/random_.h" 86#include "MagickCore/registry.h" 87#include "MagickCore/resize.h" 88#include "MagickCore/resource_.h" 89#include "MagickCore/signature.h" 90#include "MagickCore/statistic.h" 91#include "MagickCore/string_.h" 92#include "MagickCore/string-private.h" 93#include "MagickCore/timer.h" 94#include "MagickCore/utility.h" 95#include "MagickCore/version.h" 96#if defined(MAGICKCORE_LCMS_DELEGATE) 97#if defined(MAGICKCORE_HAVE_LCMS_LCMS2_H) 98#include <lcms/lcms2.h> 99#elif defined(MAGICKCORE_HAVE_LCMS2_H) 100#include "lcms2.h" 101#elif defined(MAGICKCORE_HAVE_LCMS_LCMS_H) 102#include <lcms/lcms.h> 103#else 104#include "lcms.h" 105#endif 106#endif 107 108/* 109 Define declarations. 110*/ 111#if defined(MAGICKCORE_LCMS_DELEGATE) 112#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000) 113#define cmsUInt32Number DWORD 114#endif 115#endif 116 117/* 118%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 119% % 120% % 121% % 122% I d e n t i f y I m a g e % 123% % 124% % 125% % 126%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 127% 128% IdentifyImage() identifies an image by printing its attributes to the file. 129% Attributes include the image width, height, size, and others. 130% 131% The format of the IdentifyImage method is: 132% 133% MagickBooleanType IdentifyImage(Image *image,FILE *file, 134% const MagickBooleanType verbose,ExceptionInfo *exception) 135% 136% A description of each parameter follows: 137% 138% o image: the image. 139% 140% o file: the file, typically stdout. 141% 142% o verbose: A value other than zero prints more detailed information 143% about the image. 144% 145% o exception: return any errors or warnings in this structure. 146% 147*/ 148 149static ssize_t PrintChannelFeatures(FILE *file,const ChannelType channel, 150 const char *name,const ChannelFeatures *channel_features) 151{ 152#define PrintFeature(feature) \ 153 GetMagickPrecision(),(feature)[0], \ 154 GetMagickPrecision(),(feature)[1], \ 155 GetMagickPrecision(),(feature)[2], \ 156 GetMagickPrecision(),(feature)[3], \ 157 GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \ 158 159#define FeaturesFormat " %s:\n" \ 160 " Angular Second Moment:\n" \ 161 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 162 " Contrast:\n" \ 163 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 164 " Correlation:\n" \ 165 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 166 " Sum of Squares: Variance:\n" \ 167 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 168 " Inverse Difference Moment:\n" \ 169 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 170 " Sum Average:\n" \ 171 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 172 " Sum Variance:\n" \ 173 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 174 " Sum Entropy:\n" \ 175 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 176 " Entropy:\n" \ 177 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 178 " Difference Variance:\n" \ 179 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 180 " Difference Entropy:\n" \ 181 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 182 " Information Measure of Correlation 1:\n" \ 183 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 184 " Information Measure of Correlation 2:\n" \ 185 " %.*g, %.*g, %.*g, %.*g, %.*g\n" \ 186 " Maximum Correlation Coefficient:\n" \ 187 " %.*g, %.*g, %.*g, %.*g, %.*g\n" 188 189 ssize_t 190 n; 191 192 n=FormatLocaleFile(file,FeaturesFormat,name, 193 PrintFeature(channel_features[channel].angular_second_moment), 194 PrintFeature(channel_features[channel].contrast), 195 PrintFeature(channel_features[channel].correlation), 196 PrintFeature(channel_features[channel].variance_sum_of_squares), 197 PrintFeature(channel_features[channel].inverse_difference_moment), 198 PrintFeature(channel_features[channel].sum_average), 199 PrintFeature(channel_features[channel].sum_variance), 200 PrintFeature(channel_features[channel].sum_entropy), 201 PrintFeature(channel_features[channel].entropy), 202 PrintFeature(channel_features[channel].difference_variance), 203 PrintFeature(channel_features[channel].difference_entropy), 204 PrintFeature(channel_features[channel].measure_of_correlation_1), 205 PrintFeature(channel_features[channel].measure_of_correlation_2), 206 PrintFeature(channel_features[channel].maximum_correlation_coefficient)); 207 return(n); 208} 209 210static ssize_t PrintChannelStatistics(FILE *file,const ChannelType channel, 211 const char *name,const double scale, 212 const ChannelStatistics *channel_statistics) 213{ 214#define StatisticsFormat " %s:\n min: " QuantumFormat \ 215 " (%g)\n max: " QuantumFormat " (%g)\n" \ 216 " mean: %g (%g)\n standard deviation: %g (%g)\n" \ 217 " kurtosis: %g\n skewness: %g\n" 218 219 ssize_t 220 n; 221 222 n=FormatLocaleFile(file,StatisticsFormat,name,ClampToQuantum(scale* 223 channel_statistics[channel].minima),channel_statistics[channel].minima/ 224 (double) QuantumRange,ClampToQuantum(scale* 225 channel_statistics[channel].maxima),channel_statistics[channel].maxima/ 226 (double) QuantumRange,scale*channel_statistics[channel].mean, 227 channel_statistics[channel].mean/(double) QuantumRange,scale* 228 channel_statistics[channel].standard_deviation, 229 channel_statistics[channel].standard_deviation/(double) QuantumRange, 230 channel_statistics[channel].kurtosis,channel_statistics[channel].skewness); 231 return(n); 232} 233 234MagickExport MagickBooleanType IdentifyImage(Image *image,FILE *file, 235 const MagickBooleanType verbose,ExceptionInfo *exception) 236{ 237 char 238 color[MaxTextExtent], 239 format[MaxTextExtent], 240 key[MaxTextExtent]; 241 242 ChannelFeatures 243 *channel_features; 244 245 ChannelStatistics 246 *channel_statistics; 247 248 ColorspaceType 249 colorspace; 250 251 const char 252 *artifact, 253 *name, 254 *property, 255 *registry, 256 *value; 257 258 const MagickInfo 259 *magick_info; 260 261 double 262 elapsed_time, 263 user_time; 264 265 ImageType 266 type; 267 268 MagickBooleanType 269 ping; 270 271 register const Quantum 272 *p; 273 274 register ssize_t 275 i, 276 x; 277 278 size_t 279 distance, 280 scale; 281 282 ssize_t 283 y; 284 285 assert(image != (Image *) NULL); 286 assert(image->signature == MagickSignature); 287 if (image->debug != MagickFalse) 288 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 289 if (file == (FILE *) NULL) 290 file=stdout; 291 *format='\0'; 292 elapsed_time=GetElapsedTime(&image->timer); 293 user_time=GetUserTime(&image->timer); 294 GetTimerInfo(&image->timer); 295 if (verbose == MagickFalse) 296 { 297 /* 298 Display summary info about the image. 299 */ 300 if (*image->magick_filename != '\0') 301 if (LocaleCompare(image->magick_filename,image->filename) != 0) 302 (void) FormatLocaleFile(file,"%s=>",image->magick_filename); 303 if ((GetPreviousImageInList(image) == (Image *) NULL) && 304 (GetNextImageInList(image) == (Image *) NULL) && 305 (image->scene == 0)) 306 (void) FormatLocaleFile(file,"%s ",image->filename); 307 else 308 (void) FormatLocaleFile(file,"%s[%.20g] ",image->filename,(double) 309 image->scene); 310 (void) FormatLocaleFile(file,"%s ",image->magick); 311 if ((image->magick_columns != 0) || (image->magick_rows != 0)) 312 if ((image->magick_columns != image->columns) || 313 (image->magick_rows != image->rows)) 314 (void) FormatLocaleFile(file,"%.20gx%.20g=>",(double) 315 image->magick_columns,(double) image->magick_rows); 316 (void) FormatLocaleFile(file,"%.20gx%.20g ",(double) image->columns, 317 (double) image->rows); 318 if ((image->page.width != 0) || (image->page.height != 0) || 319 (image->page.x != 0) || (image->page.y != 0)) 320 (void) FormatLocaleFile(file,"%.20gx%.20g%+.20g%+.20g ",(double) 321 image->page.width,(double) image->page.height,(double) image->page.x, 322 (double) image->page.y); 323 (void) FormatLocaleFile(file,"%.20g-bit ",(double) image->depth); 324 if (image->type != UndefinedType) 325 (void) FormatLocaleFile(file,"%s ",CommandOptionToMnemonic( 326 MagickTypeOptions,(ssize_t) image->type)); 327 if (image->storage_class == DirectClass) 328 { 329 (void) FormatLocaleFile(file,"DirectClass "); 330 if (image->total_colors != 0) 331 { 332 (void) FormatMagickSize(image->total_colors,MagickFalse,format); 333 (void) FormatLocaleFile(file,"%s ",format); 334 } 335 } 336 else 337 if (image->total_colors <= image->colors) 338 (void) FormatLocaleFile(file,"PseudoClass %.20gc ",(double) 339 image->colors); 340 else 341 (void) FormatLocaleFile(file,"PseudoClass %.20g=>%.20gc ",(double) 342 image->total_colors,(double) image->colors); 343 if (image->error.mean_error_per_pixel != 0.0) 344 (void) FormatLocaleFile(file,"%.20g/%f/%fdb ",(double) 345 (image->error.mean_error_per_pixel+0.5), 346 image->error.normalized_mean_error, 347 image->error.normalized_maximum_error); 348 if (GetBlobSize(image) != 0) 349 { 350 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format); 351 (void) FormatLocaleFile(file,"%s ",format); 352 } 353 (void) FormatLocaleFile(file,"%0.3fu %lu:%02lu.%03lu",user_time, 354 (unsigned long) (elapsed_time/60.0),(unsigned long) floor(fmod( 355 elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time- 356 floor(elapsed_time)))); 357 (void) FormatLocaleFile(file,"\n"); 358 (void) fflush(file); 359 return(ferror(file) != 0 ? MagickFalse : MagickTrue); 360 } 361 /* 362 Display verbose info about the image. 363 */ 364 p=GetVirtualPixels(image,0,0,1,1,exception); 365 ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse; 366 type=GetImageType(image,exception); 367 (void) SignatureImage(image); 368 (void) FormatLocaleFile(file,"Image: %s\n",image->filename); 369 if (*image->magick_filename != '\0') 370 if (LocaleCompare(image->magick_filename,image->filename) != 0) 371 { 372 char 373 filename[MaxTextExtent]; 374 375 GetPathComponent(image->magick_filename,TailPath,filename); 376 (void) FormatLocaleFile(file," Base filename: %s\n",filename); 377 } 378 magick_info=GetMagickInfo(image->magick,exception); 379 if ((magick_info == (const MagickInfo *) NULL) || 380 (*GetMagickDescription(magick_info) == '\0')) 381 (void) FormatLocaleFile(file," Format: %s\n",image->magick); 382 else 383 (void) FormatLocaleFile(file," Format: %s (%s)\n",image->magick, 384 GetMagickDescription(magick_info)); 385 (void) FormatLocaleFile(file," Class: %s\n",CommandOptionToMnemonic( 386 MagickClassOptions,(ssize_t) image->storage_class)); 387 (void) FormatLocaleFile(file," Geometry: %.20gx%.20g%+.20g%+.20g\n",(double) 388 image->columns,(double) image->rows,(double) image->tile_offset.x,(double) 389 image->tile_offset.y); 390 if ((image->magick_columns != 0) || (image->magick_rows != 0)) 391 if ((image->magick_columns != image->columns) || 392 (image->magick_rows != image->rows)) 393 (void) FormatLocaleFile(file," Base geometry: %.20gx%.20g\n",(double) 394 image->magick_columns,(double) image->magick_rows); 395 if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0)) 396 { 397 (void) FormatLocaleFile(file," Resolution: %gx%g\n",image->x_resolution, 398 image->y_resolution); 399 (void) FormatLocaleFile(file," Print size: %gx%g\n",(double) 400 image->columns/image->x_resolution,(double) image->rows/ 401 image->y_resolution); 402 } 403 (void) FormatLocaleFile(file," Units: %s\n",CommandOptionToMnemonic( 404 MagickResolutionOptions,(ssize_t) image->units)); 405 (void) FormatLocaleFile(file," Type: %s\n",CommandOptionToMnemonic( 406 MagickTypeOptions,(ssize_t) type)); 407 if (image->type != UndefinedType) 408 (void) FormatLocaleFile(file," Base type: %s\n",CommandOptionToMnemonic( 409 MagickTypeOptions,(ssize_t) image->type)); 410 (void) FormatLocaleFile(file," Endianess: %s\n",CommandOptionToMnemonic( 411 MagickEndianOptions,(ssize_t) image->endian)); 412 /* 413 Detail channel depth and extrema. 414 */ 415 (void) FormatLocaleFile(file," Colorspace: %s\n",CommandOptionToMnemonic( 416 MagickColorspaceOptions,(ssize_t) image->colorspace)); 417 channel_statistics=(ChannelStatistics *) NULL; 418 channel_features=(ChannelFeatures *) NULL; 419 colorspace=image->colorspace; 420 if (ping == MagickFalse) 421 { 422 size_t 423 depth; 424 425 channel_statistics=GetImageStatistics(image,exception); 426 artifact=GetImageArtifact(image,"identify:features"); 427 if (artifact != (const char *) NULL) 428 { 429 distance=StringToUnsignedLong(artifact); 430 channel_features=GetImageFeatures(image,distance,exception); 431 } 432 depth=GetImageDepth(image,exception); 433 if (image->depth == depth) 434 (void) FormatLocaleFile(file," Depth: %.20g-bit\n",(double) 435 image->depth); 436 else 437 (void) FormatLocaleFile(file," Depth: %.20g/%.20g-bit\n",(double) 438 image->depth,(double) depth); 439 (void) FormatLocaleFile(file," Channel depth:\n"); 440 if (IsImageGray(image,exception) != MagickFalse) 441 colorspace=GRAYColorspace; 442 switch (colorspace) 443 { 444 case RGBColorspace: 445 default: 446 { 447 (void) FormatLocaleFile(file," red: %.20g-bit\n",(double) 448 channel_statistics[RedChannel].depth); 449 (void) FormatLocaleFile(file," green: %.20g-bit\n",(double) 450 channel_statistics[GreenChannel].depth); 451 (void) FormatLocaleFile(file," blue: %.20g-bit\n",(double) 452 channel_statistics[BlueChannel].depth); 453 break; 454 } 455 case CMYKColorspace: 456 { 457 (void) FormatLocaleFile(file," cyan: %.20g-bit\n",(double) 458 channel_statistics[CyanChannel].depth); 459 (void) FormatLocaleFile(file," magenta: %.20g-bit\n",(double) 460 channel_statistics[MagentaChannel].depth); 461 (void) FormatLocaleFile(file," yellow: %.20g-bit\n",(double) 462 channel_statistics[YellowChannel].depth); 463 (void) FormatLocaleFile(file," black: %.20g-bit\n",(double) 464 channel_statistics[BlackChannel].depth); 465 break; 466 } 467 case GRAYColorspace: 468 { 469 (void) FormatLocaleFile(file," gray: %.20g-bit\n",(double) 470 channel_statistics[GrayChannel].depth); 471 break; 472 } 473 } 474 if (image->matte != MagickFalse) 475 (void) FormatLocaleFile(file," alpha: %.20g-bit\n",(double) 476 channel_statistics[OpacityChannel].depth); 477 scale=1; 478 if (image->depth <= MAGICKCORE_QUANTUM_DEPTH) 479 scale=QuantumRange/((size_t) QuantumRange >> ((size_t) 480 MAGICKCORE_QUANTUM_DEPTH-image->depth)); 481 } 482 if (channel_statistics != (ChannelStatistics *) NULL) 483 { 484 (void) FormatLocaleFile(file," Channel statistics:\n"); 485 switch (colorspace) 486 { 487 case RGBColorspace: 488 default: 489 { 490 (void) PrintChannelStatistics(file,RedChannel,"Red",1.0/scale, 491 channel_statistics); 492 (void) PrintChannelStatistics(file,GreenChannel,"Green",1.0/scale, 493 channel_statistics); 494 (void) PrintChannelStatistics(file,BlueChannel,"Blue",1.0/scale, 495 channel_statistics); 496 break; 497 } 498 case CMYKColorspace: 499 { 500 (void) PrintChannelStatistics(file,CyanChannel,"Cyan",1.0/scale, 501 channel_statistics); 502 (void) PrintChannelStatistics(file,MagentaChannel,"Magenta",1.0/scale, 503 channel_statistics); 504 (void) PrintChannelStatistics(file,YellowChannel,"Yellow",1.0/scale, 505 channel_statistics); 506 (void) PrintChannelStatistics(file,BlackChannel,"Black",1.0/scale, 507 channel_statistics); 508 break; 509 } 510 case GRAYColorspace: 511 { 512 (void) PrintChannelStatistics(file,GrayChannel,"Gray",1.0/scale, 513 channel_statistics); 514 break; 515 } 516 } 517 if (image->matte != MagickFalse) 518 (void) PrintChannelStatistics(file,AlphaChannel,"Alpha",1.0/scale, 519 channel_statistics); 520 if (colorspace != GRAYColorspace) 521 { 522 (void) FormatLocaleFile(file," Image statistics:\n"); 523 (void) PrintChannelStatistics(file,CompositeChannels,"Overall",1.0/ 524 scale,channel_statistics); 525 } 526 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( 527 channel_statistics); 528 } 529 if (channel_features != (ChannelFeatures *) NULL) 530 { 531 (void) FormatLocaleFile(file," Channel features (horizontal, vertical, " 532 "left and right diagonals, average):\n"); 533 switch (colorspace) 534 { 535 case RGBColorspace: 536 default: 537 { 538 (void) PrintChannelFeatures(file,RedChannel,"Red",channel_features); 539 (void) PrintChannelFeatures(file,GreenChannel,"Green", 540 channel_features); 541 (void) PrintChannelFeatures(file,BlueChannel,"Blue",channel_features); 542 break; 543 } 544 case CMYKColorspace: 545 { 546 (void) PrintChannelFeatures(file,CyanChannel,"Cyan",channel_features); 547 (void) PrintChannelFeatures(file,MagentaChannel,"Magenta", 548 channel_features); 549 (void) PrintChannelFeatures(file,YellowChannel,"Yellow", 550 channel_features); 551 (void) PrintChannelFeatures(file,BlackChannel,"Black", 552 channel_features); 553 break; 554 } 555 case GRAYColorspace: 556 { 557 (void) PrintChannelFeatures(file,GrayChannel,"Gray",channel_features); 558 break; 559 } 560 } 561 if (image->matte != MagickFalse) 562 (void) PrintChannelFeatures(file,AlphaChannel,"Alpha",channel_features); 563 channel_features=(ChannelFeatures *) RelinquishMagickMemory( 564 channel_features); 565 } 566 if (ping == MagickFalse) 567 { 568 if (image->colorspace == CMYKColorspace) 569 (void) FormatLocaleFile(file," Total ink density: %.0f%%\n",100.0* 570 GetImageTotalInkDensity(image)/(double) QuantumRange); 571 x=0; 572 if (image->matte != MagickFalse) 573 { 574 register const Quantum 575 *p; 576 577 p=(const Quantum *) NULL; 578 for (y=0; y < (ssize_t) image->rows; y++) 579 { 580 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 581 if (p == (const Quantum *) NULL) 582 break; 583 for (x=0; x < (ssize_t) image->columns; x++) 584 { 585 if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha) 586 break; 587 p+=GetPixelChannels(image); 588 } 589 if (x < (ssize_t) image->columns) 590 break; 591 } 592 if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows)) 593 { 594 char 595 tuple[MaxTextExtent]; 596 597 PixelInfo 598 pixel; 599 600 GetPixelInfo(image,&pixel); 601 SetPixelInfo(image,p,&pixel); 602 (void) QueryMagickColorname(image,&pixel,SVGCompliance,tuple, 603 exception); 604 (void) FormatLocaleFile(file," Alpha: %s ",tuple); 605 GetColorTuple(&pixel,MagickTrue,tuple); 606 (void) FormatLocaleFile(file," %s\n",tuple); 607 } 608 } 609 artifact=GetImageArtifact(image,"identify:unique-colors"); 610 if (IsHistogramImage(image,exception) != MagickFalse) 611 { 612 (void) FormatLocaleFile(file," Colors: %.20g\n",(double) 613 GetNumberColors(image,(FILE *) NULL,exception)); 614 (void) FormatLocaleFile(file," Histogram:\n"); 615 (void) GetNumberColors(image,file,exception); 616 } 617 else 618 if ((artifact != (const char *) NULL) && 619 (IsMagickTrue(artifact) != MagickFalse)) 620 (void) FormatLocaleFile(file," Colors: %.20g\n",(double) 621 GetNumberColors(image,(FILE *) NULL,exception)); 622 } 623 if (image->storage_class == PseudoClass) 624 { 625 (void) FormatLocaleFile(file," Colormap: %.20g\n",(double) 626 image->colors); 627 if (image->colors <= 1024) 628 { 629 char 630 color[MaxTextExtent], 631 hex[MaxTextExtent], 632 tuple[MaxTextExtent]; 633 634 PixelInfo 635 pixel; 636 637 register PixelPacket 638 *restrict p; 639 640 GetPixelInfo(image,&pixel); 641 p=image->colormap; 642 for (i=0; i < (ssize_t) image->colors; i++) 643 { 644 SetPixelInfoPacket(image,p,&pixel); 645 (void) CopyMagickString(tuple,"(",MaxTextExtent); 646 ConcatenateColorComponent(&pixel,RedPixelChannel,X11Compliance, 647 tuple); 648 (void) ConcatenateMagickString(tuple,",",MaxTextExtent); 649 ConcatenateColorComponent(&pixel,GreenPixelChannel,X11Compliance, 650 tuple); 651 (void) ConcatenateMagickString(tuple,",",MaxTextExtent); 652 ConcatenateColorComponent(&pixel,BluePixelChannel,X11Compliance, 653 tuple); 654 if (pixel.colorspace == CMYKColorspace) 655 { 656 (void) ConcatenateMagickString(tuple,",",MaxTextExtent); 657 ConcatenateColorComponent(&pixel,BlackPixelChannel, 658 X11Compliance,tuple); 659 } 660 if (pixel.matte != MagickFalse) 661 { 662 (void) ConcatenateMagickString(tuple,",",MaxTextExtent); 663 ConcatenateColorComponent(&pixel,AlphaPixelChannel, 664 X11Compliance,tuple); 665 } 666 (void) ConcatenateMagickString(tuple,")",MaxTextExtent); 667 (void) QueryMagickColorname(image,&pixel,SVGCompliance,color, 668 exception); 669 GetColorTuple(&pixel,MagickTrue,hex); 670 (void) FormatLocaleFile(file," %8ld: %s %s %s\n",(long) i,tuple, 671 hex,color); 672 p++; 673 } 674 } 675 } 676 if (image->error.mean_error_per_pixel != 0.0) 677 (void) FormatLocaleFile(file," Mean error per pixel: %g\n", 678 image->error.mean_error_per_pixel); 679 if (image->error.normalized_mean_error != 0.0) 680 (void) FormatLocaleFile(file," Normalized mean error: %g\n", 681 image->error.normalized_mean_error); 682 if (image->error.normalized_maximum_error != 0.0) 683 (void) FormatLocaleFile(file," Normalized maximum error: %g\n", 684 image->error.normalized_maximum_error); 685 (void) FormatLocaleFile(file," Rendering intent: %s\n", 686 CommandOptionToMnemonic(MagickIntentOptions,(ssize_t) 687 image->rendering_intent)); 688 if (image->gamma != 0.0) 689 (void) FormatLocaleFile(file," Gamma: %g\n",image->gamma); 690 if ((image->chromaticity.red_primary.x != 0.0) || 691 (image->chromaticity.green_primary.x != 0.0) || 692 (image->chromaticity.blue_primary.x != 0.0) || 693 (image->chromaticity.white_point.x != 0.0)) 694 { 695 /* 696 Display image chromaticity. 697 */ 698 (void) FormatLocaleFile(file," Chromaticity:\n"); 699 (void) FormatLocaleFile(file," red primary: (%g,%g)\n", 700 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y); 701 (void) FormatLocaleFile(file," green primary: (%g,%g)\n", 702 image->chromaticity.green_primary.x, 703 image->chromaticity.green_primary.y); 704 (void) FormatLocaleFile(file," blue primary: (%g,%g)\n", 705 image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y); 706 (void) FormatLocaleFile(file," white point: (%g,%g)\n", 707 image->chromaticity.white_point.x,image->chromaticity.white_point.y); 708 } 709 if ((image->extract_info.width*image->extract_info.height) != 0) 710 (void) FormatLocaleFile(file," Tile geometry: %.20gx%.20g%+.20g%+.20g\n", 711 (double) image->extract_info.width,(double) image->extract_info.height, 712 (double) image->extract_info.x,(double) image->extract_info.y); 713 (void) FormatLocaleFile(file," Interlace: %s\n",CommandOptionToMnemonic( 714 MagickInterlaceOptions,(ssize_t) image->interlace)); 715 (void) QueryColorname(image,&image->background_color,SVGCompliance,color, 716 exception); 717 (void) FormatLocaleFile(file," Background color: %s\n",color); 718 (void) QueryColorname(image,&image->border_color,SVGCompliance,color, 719 exception); 720 (void) FormatLocaleFile(file," Border color: %s\n",color); 721 (void) QueryColorname(image,&image->matte_color,SVGCompliance,color, 722 exception); 723 (void) FormatLocaleFile(file," Matte color: %s\n",color); 724 (void) QueryColorname(image,&image->transparent_color,SVGCompliance,color, 725 exception); 726 (void) FormatLocaleFile(file," Transparent color: %s\n",color); 727 (void) FormatLocaleFile(file," Compose: %s\n",CommandOptionToMnemonic( 728 MagickComposeOptions,(ssize_t) image->compose)); 729 if ((image->page.width != 0) || (image->page.height != 0) || 730 (image->page.x != 0) || (image->page.y != 0)) 731 (void) FormatLocaleFile(file," Page geometry: %.20gx%.20g%+.20g%+.20g\n", 732 (double) image->page.width,(double) image->page.height,(double) 733 image->page.x,(double) image->page.y); 734 if ((image->page.x != 0) || (image->page.y != 0)) 735 (void) FormatLocaleFile(file," Origin geometry: %+.20g%+.20g\n",(double) 736 image->page.x,(double) image->page.y); 737 (void) FormatLocaleFile(file," Dispose: %s\n",CommandOptionToMnemonic( 738 MagickDisposeOptions,(ssize_t) image->dispose)); 739 if (image->delay != 0) 740 (void) FormatLocaleFile(file," Delay: %.20gx%.20g\n",(double) image->delay, 741 (double) image->ticks_per_second); 742 if (image->iterations != 1) 743 (void) FormatLocaleFile(file," Iterations: %.20g\n",(double) 744 image->iterations); 745 if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL)) 746 (void) FormatLocaleFile(file," Scene: %.20g of %.20g\n",(double) 747 image->scene,(double) GetImageListLength(image)); 748 else 749 if (image->scene != 0) 750 (void) FormatLocaleFile(file," Scene: %.20g\n",(double) image->scene); 751 (void) FormatLocaleFile(file," Compression: %s\n",CommandOptionToMnemonic( 752 MagickCompressOptions,(ssize_t) image->compression)); 753 if (image->quality != UndefinedCompressionQuality) 754 (void) FormatLocaleFile(file," Quality: %.20g\n",(double) image->quality); 755 (void) FormatLocaleFile(file," Orientation: %s\n",CommandOptionToMnemonic( 756 MagickOrientationOptions,(ssize_t) image->orientation)); 757 if (image->montage != (char *) NULL) 758 (void) FormatLocaleFile(file," Montage: %s\n",image->montage); 759 if (image->directory != (char *) NULL) 760 { 761 Image 762 *tile; 763 764 ImageInfo 765 *image_info; 766 767 register char 768 *p, 769 *q; 770 771 WarningHandler 772 handler; 773 774 /* 775 Display visual image directory. 776 */ 777 image_info=AcquireImageInfo(); 778 (void) CloneString(&image_info->size,"64x64"); 779 (void) FormatLocaleFile(file," Directory:\n"); 780 for (p=image->directory; *p != '\0'; p++) 781 { 782 q=p; 783 while ((*q != '\n') && (*q != '\0')) 784 q++; 785 (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1)); 786 p=q; 787 (void) FormatLocaleFile(file," %s",image_info->filename); 788 handler=SetWarningHandler((WarningHandler) NULL); 789 tile=ReadImage(image_info,exception); 790 (void) SetWarningHandler(handler); 791 if (tile == (Image *) NULL) 792 { 793 (void) FormatLocaleFile(file,"\n"); 794 continue; 795 } 796 (void) FormatLocaleFile(file," %.20gx%.20g %s\n",(double) 797 tile->magick_columns,(double) tile->magick_rows,tile->magick); 798 (void) SignatureImage(tile); 799 ResetImagePropertyIterator(tile); 800 property=GetNextImageProperty(tile); 801 while (property != (const char *) NULL) 802 { 803 (void) FormatLocaleFile(file," %s:\n",property); 804 value=GetImageProperty(tile,property); 805 if (value != (const char *) NULL) 806 (void) FormatLocaleFile(file,"%s\n",value); 807 property=GetNextImageProperty(tile); 808 } 809 tile=DestroyImage(tile); 810 } 811 image_info=DestroyImageInfo(image_info); 812 } 813 (void) GetImageProperty(image,"exif:*"); 814 ResetImagePropertyIterator(image); 815 property=GetNextImageProperty(image); 816 if (property != (const char *) NULL) 817 { 818 /* 819 Display image properties. 820 */ 821 (void) FormatLocaleFile(file," Properties:\n"); 822 while (property != (const char *) NULL) 823 { 824 (void) FormatLocaleFile(file," %s: ",property); 825 value=GetImageProperty(image,property); 826 if (value != (const char *) NULL) 827 (void) FormatLocaleFile(file,"%s\n",value); 828 property=GetNextImageProperty(image); 829 } 830 } 831 (void) FormatLocaleString(key,MaxTextExtent,"8BIM:1999,2998:#1"); 832 value=GetImageProperty(image,key); 833 if (value != (const char *) NULL) 834 { 835 /* 836 Display clipping path. 837 */ 838 (void) FormatLocaleFile(file," Clipping path: "); 839 if (strlen(value) > 80) 840 (void) fputc('\n',file); 841 (void) FormatLocaleFile(file,"%s\n",value); 842 } 843 ResetImageProfileIterator(image); 844 name=GetNextImageProfile(image); 845 if (name != (char *) NULL) 846 { 847 const StringInfo 848 *profile; 849 850 /* 851 Identify image profiles. 852 */ 853 (void) FormatLocaleFile(file," Profiles:\n"); 854 while (name != (char *) NULL) 855 { 856 profile=GetImageProfile(image,name); 857 if (profile == (StringInfo *) NULL) 858 continue; 859 (void) FormatLocaleFile(file," Profile-%s: %.20g bytes\n",name, 860 (double) GetStringInfoLength(profile)); 861#if defined(MAGICKCORE_LCMS_DELEGATE) 862 if ((LocaleCompare(name,"icc") == 0) || 863 (LocaleCompare(name,"icm") == 0)) 864 { 865 cmsHPROFILE 866 icc_profile; 867 868 icc_profile=cmsOpenProfileFromMem(GetStringInfoDatum(profile), 869 (cmsUInt32Number) GetStringInfoLength(profile)); 870 if (icc_profile != (cmsHPROFILE *) NULL) 871 { 872#if defined(LCMS_VERSION) && (LCMS_VERSION < 2000) 873 const char 874 *name; 875 876 name=cmsTakeProductName(icc_profile); 877 if (name != (const char *) NULL) 878 (void) FormatLocaleFile(file," %s\n",name); 879#else 880 char 881 info[MaxTextExtent]; 882 883 (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoDescription, 884 "en","US",info,MaxTextExtent); 885 (void) FormatLocaleFile(file," Description: %s\n",info); 886 (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoManufacturer, 887 "en","US",info,MaxTextExtent); 888 (void) FormatLocaleFile(file," Manufacturer: %s\n",info); 889 (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoModel,"en", 890 "US",info,MaxTextExtent); 891 (void) FormatLocaleFile(file," Model: %s\n",info); 892 (void) cmsGetProfileInfoASCII(icc_profile,cmsInfoCopyright, 893 "en","US",info,MaxTextExtent); 894 (void) FormatLocaleFile(file," Copyright: %s\n",info); 895#endif 896 (void) cmsCloseProfile(icc_profile); 897 } 898 } 899#endif 900 if (LocaleCompare(name,"iptc") == 0) 901 { 902 char 903 *attribute, 904 **attribute_list; 905 906 const char 907 *tag; 908 909 long 910 dataset, 911 record, 912 sentinel; 913 914 register ssize_t 915 j; 916 917 size_t 918 length, 919 profile_length; 920 921 profile_length=GetStringInfoLength(profile); 922 for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length) 923 { 924 length=1; 925 sentinel=GetStringInfoDatum(profile)[i++]; 926 if (sentinel != 0x1c) 927 continue; 928 dataset=GetStringInfoDatum(profile)[i++]; 929 record=GetStringInfoDatum(profile)[i++]; 930 switch (record) 931 { 932 case 5: tag="Image Name"; break; 933 case 7: tag="Edit Status"; break; 934 case 10: tag="Priority"; break; 935 case 15: tag="Category"; break; 936 case 20: tag="Supplemental Category"; break; 937 case 22: tag="Fixture Identifier"; break; 938 case 25: tag="Keyword"; break; 939 case 30: tag="Release Date"; break; 940 case 35: tag="Release Time"; break; 941 case 40: tag="Special Instructions"; break; 942 case 45: tag="Reference Service"; break; 943 case 47: tag="Reference Date"; break; 944 case 50: tag="Reference Number"; break; 945 case 55: tag="Created Date"; break; 946 case 60: tag="Created Time"; break; 947 case 65: tag="Originating Program"; break; 948 case 70: tag="Program Version"; break; 949 case 75: tag="Object Cycle"; break; 950 case 80: tag="Byline"; break; 951 case 85: tag="Byline Title"; break; 952 case 90: tag="City"; break; 953 case 95: tag="Province State"; break; 954 case 100: tag="Country Code"; break; 955 case 101: tag="Country"; break; 956 case 103: tag="Original Transmission Reference"; break; 957 case 105: tag="Headline"; break; 958 case 110: tag="Credit"; break; 959 case 115: tag="Src"; break; 960 case 116: tag="Copyright String"; break; 961 case 120: tag="Caption"; break; 962 case 121: tag="Local Caption"; break; 963 case 122: tag="Caption Writer"; break; 964 case 200: tag="Custom Field 1"; break; 965 case 201: tag="Custom Field 2"; break; 966 case 202: tag="Custom Field 3"; break; 967 case 203: tag="Custom Field 4"; break; 968 case 204: tag="Custom Field 5"; break; 969 case 205: tag="Custom Field 6"; break; 970 case 206: tag="Custom Field 7"; break; 971 case 207: tag="Custom Field 8"; break; 972 case 208: tag="Custom Field 9"; break; 973 case 209: tag="Custom Field 10"; break; 974 case 210: tag="Custom Field 11"; break; 975 case 211: tag="Custom Field 12"; break; 976 case 212: tag="Custom Field 13"; break; 977 case 213: tag="Custom Field 14"; break; 978 case 214: tag="Custom Field 15"; break; 979 case 215: tag="Custom Field 16"; break; 980 case 216: tag="Custom Field 17"; break; 981 case 217: tag="Custom Field 18"; break; 982 case 218: tag="Custom Field 19"; break; 983 case 219: tag="Custom Field 20"; break; 984 default: tag="unknown"; break; 985 } 986 (void) FormatLocaleFile(file," %s[%.20g,%.20g]: ",tag, 987 (double) dataset,(double) record); 988 length=(size_t) (GetStringInfoDatum(profile)[i++] << 8); 989 length|=GetStringInfoDatum(profile)[i++]; 990 attribute=(char *) NULL; 991 if (~length >= (MaxTextExtent-1)) 992 attribute=(char *) AcquireQuantumMemory(length+MaxTextExtent, 993 sizeof(*attribute)); 994 if (attribute != (char *) NULL) 995 { 996 (void) CopyMagickString(attribute,(char *) 997 GetStringInfoDatum(profile)+i,length+1); 998 attribute_list=StringToList(attribute); 999 if (attribute_list != (char **) NULL) 1000 { 1001 for (j=0; attribute_list[j] != (char *) NULL; j++) 1002 { 1003 (void) fputs(attribute_list[j],file); 1004 (void) fputs("\n",file); 1005 attribute_list[j]=(char *) RelinquishMagickMemory( 1006 attribute_list[j]); 1007 } 1008 attribute_list=(char **) RelinquishMagickMemory( 1009 attribute_list); 1010 } 1011 attribute=DestroyString(attribute); 1012 } 1013 } 1014 } 1015 if (image->debug != MagickFalse) 1016 PrintStringInfo(file,name,profile); 1017 name=GetNextImageProfile(image); 1018 } 1019 } 1020 ResetImageArtifactIterator(image); 1021 artifact=GetNextImageArtifact(image); 1022 if (artifact != (const char *) NULL) 1023 { 1024 /* 1025 Display image artifacts. 1026 */ 1027 (void) FormatLocaleFile(file," Artifacts:\n"); 1028 while (artifact != (const char *) NULL) 1029 { 1030 (void) FormatLocaleFile(file," %s: ",artifact); 1031 value=GetImageArtifact(image,artifact); 1032 if (value != (const char *) NULL) 1033 (void) FormatLocaleFile(file,"%s\n",value); 1034 artifact=GetNextImageArtifact(image); 1035 } 1036 } 1037 ResetImageRegistryIterator(); 1038 registry=GetNextImageRegistry(); 1039 if (registry != (const char *) NULL) 1040 { 1041 /* 1042 Display image registry. 1043 */ 1044 (void) FormatLocaleFile(file," Registry:\n"); 1045 while (registry != (const char *) NULL) 1046 { 1047 (void) FormatLocaleFile(file," %s: ",registry); 1048 value=(const char *) GetImageRegistry(StringRegistryType,registry, 1049 exception); 1050 if (value != (const char *) NULL) 1051 (void) FormatLocaleFile(file,"%s\n",value); 1052 registry=GetNextImageRegistry(); 1053 } 1054 } 1055 (void) FormatLocaleFile(file," Tainted: %s\n",CommandOptionToMnemonic( 1056 MagickBooleanOptions,(ssize_t) image->taint)); 1057 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,format); 1058 (void) FormatLocaleFile(file," Filesize: %sB\n",format); 1059 (void) FormatMagickSize((MagickSizeType) image->columns*image->rows, 1060 MagickFalse,format); 1061 (void) FormatLocaleFile(file," Number pixels: %s\n",format); 1062 (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/ 1063 elapsed_time+0.5),MagickFalse,format); 1064 (void) FormatLocaleFile(file," Pixels per second: %s\n",format); 1065 (void) FormatLocaleFile(file," User time: %0.3fu\n",user_time); 1066 (void) FormatLocaleFile(file," Elapsed time: %lu:%02lu.%03lu\n", 1067 (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(elapsed_time, 1068 60.0)),(unsigned long) (1000.0*(elapsed_time-floor(elapsed_time)))); 1069 (void) FormatLocaleFile(file," Version: %s\n",GetMagickVersion((size_t *) 1070 NULL)); 1071 (void) fflush(file); 1072 return(ferror(file) != 0 ? MagickFalse : MagickTrue); 1073} 1074