1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% JJJJJ SSSSS OOO N N % 7% J SS O O NN N % 8% J SSS O O N N N % 9% J J SS O O N NN % 10% JJJ SSSSS OOO N N % 11% % 12% % 13% Write Info About the Image in JSON Format. % 14% % 15% Software Design % 16% Cristy % 17% January 2014 % 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% 37*/ 38 39/* 40 Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/artifact.h" 44#include "MagickCore/attribute.h" 45#include "MagickCore/blob.h" 46#include "MagickCore/blob-private.h" 47#include "MagickCore/cache.h" 48#include "MagickCore/colorspace.h" 49#include "MagickCore/colorspace-private.h" 50#include "MagickCore/constitute.h" 51#include "MagickCore/exception.h" 52#include "MagickCore/exception-private.h" 53#include "MagickCore/feature.h" 54#include "MagickCore/image.h" 55#include "MagickCore/image-private.h" 56#include "MagickCore/list.h" 57#include "MagickCore/magick.h" 58#include "MagickCore/memory_.h" 59#include "MagickCore/monitor.h" 60#include "MagickCore/monitor-private.h" 61#include "MagickCore/option.h" 62#include "MagickCore/pixel.h" 63#include "MagickCore/pixel-accessor.h" 64#include "MagickCore/pixel-private.h" 65#include "MagickCore/prepress.h" 66#include "MagickCore/property.h" 67#include "MagickCore/quantum-private.h" 68#include "MagickCore/registry.h" 69#include "MagickCore/signature.h" 70#include "MagickCore/static.h" 71#include "MagickCore/statistic.h" 72#include "MagickCore/string_.h" 73#include "MagickCore/string-private.h" 74#include "MagickCore/utility.h" 75#include "MagickCore/version.h" 76#include "MagickCore/module.h" 77 78/* 79 Forward declarations. 80*/ 81static MagickBooleanType 82 WriteJSONImage(const ImageInfo *,Image *,ExceptionInfo *); 83 84/* 85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 86% % 87% % 88% % 89% R e g i s t e r J S O N I m a g e % 90% % 91% % 92% % 93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94% 95% RegisterJSONImage() adds attributes for the JSON image format to 96% the list of supported formats. The attributes include the image format 97% tag, a method to read and/or write the format, whether the format 98% supports the saving of more than one frame to the same file or blob, 99% whether the format supports native in-memory I/O, and a brief 100% description of the format. 101% 102% The format of the RegisterJSONImage method is: 103% 104% size_t RegisterJSONImage(void) 105% 106*/ 107ModuleExport size_t RegisterJSONImage(void) 108{ 109 MagickInfo 110 *entry; 111 112 entry=AcquireMagickInfo("JSON","JSON","The image format and characteristics"); 113 entry->encoder=(EncodeImageHandler *) WriteJSONImage; 114 entry->mime_type=ConstantString("application/json"); 115 entry->flags^=CoderBlobSupportFlag; 116 (void) RegisterMagickInfo(entry); 117 return(MagickImageCoderSignature); 118} 119 120/* 121%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 122% % 123% % 124% % 125% U n r e g i s t e r J S O N I m a g e % 126% % 127% % 128% % 129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 130% 131% UnregisterJSONImage() removes format registrations made by the 132% JSON module from the list of supported formats. 133% 134% The format of the UnregisterJSONImage method is: 135% 136% UnregisterJSONImage(void) 137% 138*/ 139ModuleExport void UnregisterJSONImage(void) 140{ 141 (void) UnregisterMagickInfo("JSON"); 142} 143 144/* 145%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 146% % 147% % 148% % 149% W r i t e J S O N I m a g e % 150% % 151% % 152% % 153%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 154% 155% WriteJSONImage writes the image attributes in the JSON format. 156% 157% The format of the WriteJSONImage method is: 158% 159% MagickBooleanType WriteJSONImage(const ImageInfo *image_info, 160% Image *image,ExceptionInfo *exception) 161% 162% A description of each parameter follows. 163% 164% o image_info: the image info. 165% 166% o image: The image. 167% 168% o exception: return any errors or warnings in this structure. 169% 170*/ 171 172static void JsonFormatLocaleFile(FILE *file,const char *format,const char *value) 173{ 174 char 175 *escaped_json; 176 177 register char 178 *q; 179 180 register const char 181 *p; 182 183 size_t 184 length; 185 186 assert(format != (const char *) NULL); 187 if (value == (char *) NULL || *value == '\0') 188 { 189 (void) FormatLocaleFile(file,format,"null"); 190 return; 191 } 192 length=strlen(value)+2; 193 /* 194 Find all the chars that need escaping and increase the dest length counter 195 */ 196 for (p=value; *p != '\0'; p++) 197 { 198 switch (*p) 199 { 200 case '"': 201 case '\b': 202 case '\f': 203 case '\n': 204 case '\r': 205 case '\t': 206 case '\\': 207 if (~length < 1) 208 return; 209 length++; 210 break; 211 default: 212 break; 213 } 214 } 215 escaped_json=(char *) NULL; 216 if (~length >= (MagickPathExtent-1)) 217 escaped_json=(char *) AcquireQuantumMemory(length+MagickPathExtent, 218 sizeof(*escaped_json)); 219 if (escaped_json == (char *) NULL) 220 { 221 (void) FormatLocaleFile(file,format,"null"); 222 return; 223 } 224 q=escaped_json; 225 *q++='"'; 226 for (p=value; *p != '\0'; p++) 227 { 228 switch (*p) 229 { 230 case '"': 231 *q++='\\'; 232 *q++=(*p); 233 break; 234 case '\b': 235 *q++='\\'; 236 *q++='b'; 237 break; 238 case '\f': 239 *q++='\\'; 240 *q++='f'; 241 break; 242 case '\n': 243 *q++='\\'; 244 *q++='n'; 245 break; 246 case '\r': 247 *q++='\\'; 248 *q++='r'; 249 break; 250 case '\t': 251 *q++='\\'; 252 *q++='t'; 253 break; 254 case '\\': 255 *q++='\\'; 256 *q++='\\'; 257 break; 258 default: 259 *q++=(*p); 260 break; 261 } 262 } 263 *q++='"'; 264 *q='\0'; 265 (void) FormatLocaleFile(file,format,escaped_json); 266 (void) DestroyString(escaped_json); 267} 268 269static ChannelStatistics *GetLocationStatistics(const Image *image, 270 const StatisticType type,ExceptionInfo *exception) 271{ 272 ChannelStatistics 273 *channel_statistics; 274 275 register ssize_t 276 i; 277 278 ssize_t 279 y; 280 281 assert(image != (Image *) NULL); 282 assert(image->signature == MagickCoreSignature); 283 if (image->debug != MagickFalse) 284 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 285 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory( 286 MaxPixelChannels+1,sizeof(*channel_statistics)); 287 if (channel_statistics == (ChannelStatistics *) NULL) 288 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 289 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)* 290 sizeof(*channel_statistics)); 291 for (i=0; i <= (ssize_t) MaxPixelChannels; i++) 292 { 293 switch (type) 294 { 295 case MaximumStatistic: 296 default: 297 { 298 channel_statistics[i].maxima=(-MagickMaximumValue); 299 break; 300 } 301 case MinimumStatistic: 302 { 303 channel_statistics[i].minima=MagickMaximumValue; 304 break; 305 } 306 } 307 } 308 for (y=0; y < (ssize_t) image->rows; y++) 309 { 310 register const Quantum 311 *magick_restrict p; 312 313 register ssize_t 314 x; 315 316 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 317 if (p == (const Quantum *) NULL) 318 break; 319 for (x=0; x < (ssize_t) image->columns; x++) 320 { 321 register ssize_t 322 i; 323 324 if (GetPixelReadMask(image,p) == 0) 325 { 326 p+=GetPixelChannels(image); 327 continue; 328 } 329 for (i=0; i < (ssize_t) GetPixelChannels(image); i++) 330 { 331 PixelChannel channel=GetPixelChannelChannel(image,i); 332 PixelTrait traits=GetPixelChannelTraits(image,channel); 333 if (traits == UndefinedPixelTrait) 334 continue; 335 switch (type) 336 { 337 case MaximumStatistic: 338 default: 339 { 340 if ((double) p[i] > channel_statistics[channel].maxima) 341 channel_statistics[channel].maxima=(double) p[i]; 342 break; 343 } 344 case MinimumStatistic: 345 { 346 if ((double) p[i] < channel_statistics[channel].minima) 347 channel_statistics[channel].minima=(double) p[i]; 348 break; 349 } 350 } 351 } 352 p+=GetPixelChannels(image); 353 } 354 } 355 return(channel_statistics); 356} 357 358static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel, 359 const char *name,const MagickBooleanType separator, 360 const ChannelFeatures *channel_features) 361{ 362#define PrintFeature(feature) \ 363 GetMagickPrecision(),(feature)[0], \ 364 GetMagickPrecision(),(feature)[1], \ 365 GetMagickPrecision(),(feature)[2], \ 366 GetMagickPrecision(),(feature)[3], \ 367 GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \ 368 369#define FeaturesFormat " \"%s\": {\n" \ 370 " \"angularSecondMoment\": {\n" \ 371 " \"horizontal\": \"%.*g\",\n" \ 372 " \"vertical\": \"%.*g\",\n" \ 373 " \"leftDiagonal\": \"%.*g\",\n" \ 374 " \"rightDiagonal\": \"%.*g\",\n" \ 375 " \"average\": \"%.*g\"\n" \ 376 " },\n" \ 377 " \"contrast\": {\n" \ 378 " \"horizontal\": \"%.*g\",\n" \ 379 " \"vertical\": \"%.*g\",\n" \ 380 " \"leftDiagonal\": \"%.*g\",\n" \ 381 " \"rightDiagonal\": \"%.*g\",\n" \ 382 " \"average\": \"%.*g\"\n" \ 383 " },\n" \ 384 " \"correlation\": {\n" \ 385 " \"horizontal\": \"%.*g\",\n" \ 386 " \"vertical\": \"%.*g\",\n" \ 387 " \"leftDiagonal\": \"%.*g\",\n" \ 388 " \"rightDiagonal\": \"%.*g\",\n" \ 389 " \"average\": \"%.*g\"\n" \ 390 " },\n" \ 391 " \"sumOfSquaresVariance\": {\n" \ 392 " \"horizontal\": \"%.*g\",\n" \ 393 " \"vertical\": \"%.*g\",\n" \ 394 " \"leftDiagonal\": \"%.*g\",\n" \ 395 " \"rightDiagonal\": \"%.*g\",\n" \ 396 " \"average\": \"%.*g\"\n" \ 397 " },\n" \ 398 " \"inverseDifferenceMoment\": {\n" \ 399 " \"horizontal\": \"%.*g\",\n" \ 400 " \"vertical\": \"%.*g\",\n" \ 401 " \"leftDiagonal\": \"%.*g\",\n" \ 402 " \"rightDiagonal\": \"%.*g\",\n" \ 403 " \"average\": \"%.*g\"\n" \ 404 " },\n" \ 405 " \"sumAverage\": {\n" \ 406 " \"horizontal\": \"%.*g\",\n" \ 407 " \"vertical\": \"%.*g\",\n" \ 408 " \"leftDiagonal\": \"%.*g\",\n" \ 409 " \"rightDiagonal\": \"%.*g\",\n" \ 410 " \"average\": \"%.*g\"\n" \ 411 " },\n" \ 412 " \"sumVariance\": {\n" \ 413 " \"horizontal\": \"%.*g\",\n" \ 414 " \"vertical\": \"%.*g\",\n" \ 415 " \"leftDiagonal\": \"%.*g\",\n" \ 416 " \"rightDiagonal\": \"%.*g\",\n" \ 417 " \"average\": \"%.*g\"\n" \ 418 " },\n" \ 419 " \"sumEntropy\": {\n" \ 420 " \"horizontal\": \"%.*g\",\n" \ 421 " \"vertical\": \"%.*g\",\n" \ 422 " \"leftDiagonal\": \"%.*g\",\n" \ 423 " \"rightDiagonal\": \"%.*g\",\n" \ 424 " \"average\": \"%.*g\"\n" \ 425 " },\n" \ 426 " \"entropy\": {\n" \ 427 " \"horizontal\": \"%.*g\",\n" \ 428 " \"vertical\": \"%.*g\",\n" \ 429 " \"leftDiagonal\": \"%.*g\",\n" \ 430 " \"rightDiagonal\": \"%.*g\",\n" \ 431 " \"average\": \"%.*g\"\n" \ 432 " },\n" \ 433 " \"differenceVariance\": {\n" \ 434 " \"horizontal\": \"%.*g\",\n" \ 435 " \"vertical\": \"%.*g\",\n" \ 436 " \"leftDiagonal\": \"%.*g\",\n" \ 437 " \"rightDiagonal\": \"%.*g\",\n" \ 438 " \"average\": \"%.*g\"\n" \ 439 " },\n" \ 440 " \"differenceEntropy\": {\n" \ 441 " \"horizontal\": \"%.*g\",\n" \ 442 " \"vertical\": \"%.*g\",\n" \ 443 " \"leftDiagonal\": \"%.*g\",\n" \ 444 " \"rightDiagonal\": \"%.*g\",\n" \ 445 " \"average\": \"%.*g\"\n" \ 446 " },\n" \ 447 " \"informationMeasureOfCorrelation1\": {\n" \ 448 " \"horizontal\": \"%.*g\",\n" \ 449 " \"vertical\": \"%.*g\",\n" \ 450 " \"leftDiagonal\": \"%.*g\",\n" \ 451 " \"rightDiagonal\": \"%.*g\",\n" \ 452 " \"average\": \"%.*g\"\n" \ 453 " },\n" \ 454 " \"informationMeasureOfCorrelation2\": {\n" \ 455 " \"horizontal\": \"%.*g\",\n" \ 456 " \"vertical\": \"%.*g\",\n" \ 457 " \"leftDiagonal\": \"%.*g\",\n" \ 458 " \"rightDiagonal\": \"%.*g\",\n" \ 459 " \"average\": \"%.*g\"\n" \ 460 " },\n" \ 461 " \"maximumCorrelationCoefficient\": {\n" \ 462 " \"horizontal\": \"%.*g\",\n" \ 463 " \"vertical\": \"%.*g\",\n" \ 464 " \"leftDiagonal\": \"%.*g\",\n" \ 465 " \"rightDiagonal\": \"%.*g\",\n" \ 466 " \"average\": \"%.*g\"\n" \ 467 " }\n" 468 469 ssize_t 470 n; 471 472 n=FormatLocaleFile(file,FeaturesFormat,name, 473 PrintFeature(channel_features[channel].angular_second_moment), 474 PrintFeature(channel_features[channel].contrast), 475 PrintFeature(channel_features[channel].correlation), 476 PrintFeature(channel_features[channel].variance_sum_of_squares), 477 PrintFeature(channel_features[channel].inverse_difference_moment), 478 PrintFeature(channel_features[channel].sum_average), 479 PrintFeature(channel_features[channel].sum_variance), 480 PrintFeature(channel_features[channel].sum_entropy), 481 PrintFeature(channel_features[channel].entropy), 482 PrintFeature(channel_features[channel].difference_variance), 483 PrintFeature(channel_features[channel].difference_entropy), 484 PrintFeature(channel_features[channel].measure_of_correlation_1), 485 PrintFeature(channel_features[channel].measure_of_correlation_2), 486 PrintFeature(channel_features[channel].maximum_correlation_coefficient)); 487 (void) FormatLocaleFile(file," }"); 488 if (separator != MagickFalse) 489 (void) FormatLocaleFile(file,","); 490 (void) FormatLocaleFile(file,"\n"); 491 return(n); 492} 493 494static ssize_t PrintChannelLocations(FILE *file,const Image *image, 495 const PixelChannel channel,const char *name,const StatisticType type, 496 const size_t max_locations,const MagickBooleanType separator, 497 const ChannelStatistics *channel_statistics) 498{ 499 double 500 target; 501 502 ExceptionInfo 503 *exception; 504 505 ssize_t 506 n, 507 y; 508 509 switch (type) 510 { 511 case MaximumStatistic: 512 default: 513 { 514 target=channel_statistics[channel].maxima; 515 break; 516 } 517 case MinimumStatistic: 518 { 519 target=channel_statistics[channel].minima; 520 break; 521 } 522 } 523 (void) FormatLocaleFile(file," \"%s\": {\n \"intensity\": " 524 "\"%.*g\",\n",name,GetMagickPrecision(),QuantumScale*target); 525 exception=AcquireExceptionInfo(); 526 n=0; 527 for (y=0; y < (ssize_t) image->rows; y++) 528 { 529 register const Quantum 530 *p; 531 532 ssize_t 533 offset, 534 x; 535 536 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 537 if (p == (const Quantum *) NULL) 538 break; 539 for (x=0; x < (ssize_t) image->columns; x++) 540 { 541 MagickBooleanType 542 match; 543 544 PixelTrait traits=GetPixelChannelTraits(image,channel); 545 if (traits == UndefinedPixelTrait) 546 continue; 547 offset=GetPixelChannelOffset(image,channel); 548 match=fabs((double) (p[offset]-target)) < 0.5 ? MagickTrue : MagickFalse; 549 if (match != MagickFalse) 550 { 551 if ((max_locations != 0) && (n >= (ssize_t) max_locations)) 552 break; 553 if (n != 0) 554 (void) FormatLocaleFile(file,",\n"); 555 (void) FormatLocaleFile(file," \"location%.20g\": {\n" 556 " \"x\": %.20g,\n \"y\": %.20g\n" 557 " }",(double) n,(double) x,(double) y); 558 n++; 559 } 560 p+=GetPixelChannels(image); 561 } 562 if (x < (ssize_t) image->columns) 563 break; 564 } 565 (void) FormatLocaleFile(file,"\n }"); 566 if (separator != MagickFalse) 567 (void) FormatLocaleFile(file,","); 568 (void) FormatLocaleFile(file,"\n"); 569 return(n); 570} 571 572static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel, 573 const char *name,const MagickBooleanType separator, 574 const ChannelMoments *channel_moments) 575{ 576 register ssize_t 577 i; 578 579 ssize_t 580 n; 581 582 n=FormatLocaleFile(file," \"%s\": {\n",name); 583 n+=FormatLocaleFile(file," \"centroid\": {\n " 584 " \"x\": \"%.*g\",\n" 585 " \"y\": \"%.*g\"\n },\n", 586 GetMagickPrecision(),channel_moments[channel].centroid.x, 587 GetMagickPrecision(),channel_moments[channel].centroid.y); 588 n+=FormatLocaleFile(file," \"ellipseSemiMajorMinorAxis\": {\n" 589 " \"x\": \"%.*g\",\n" 590 " \"y\": \"%.*g\"\n },\n", 591 GetMagickPrecision(),channel_moments[channel].ellipse_axis.x, 592 GetMagickPrecision(),channel_moments[channel].ellipse_axis.y); 593 n+=FormatLocaleFile(file," \"ellipseAngle\": \"%.*g\",\n", 594 GetMagickPrecision(),channel_moments[channel].ellipse_angle); 595 n+=FormatLocaleFile(file," \"ellipseEccentricity\": \"%.*g\",\n", 596 GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity); 597 n+=FormatLocaleFile(file," \"ellipseIntensity\": \"%.*g\",\n", 598 GetMagickPrecision(),channel_moments[channel].ellipse_intensity); 599 for (i=0; i < 7; i++) 600 n+=FormatLocaleFile(file," \"I%.20g\": \"%.*g\",\n",i+1.0, 601 GetMagickPrecision(),channel_moments[channel].invariant[i]); 602 n+=FormatLocaleFile(file," \"I%.20g\": \"%.*g\"\n",i+1.0, 603 GetMagickPrecision(),channel_moments[channel].invariant[i]); 604 (void) FormatLocaleFile(file," }"); 605 if (separator != MagickFalse) 606 (void) FormatLocaleFile(file,","); 607 (void) FormatLocaleFile(file,"\n"); 608 return(n); 609} 610 611static ssize_t PrintChannelPerceptualHash(FILE *file,const ChannelType channel, 612 const char *name,const MagickBooleanType separator, 613 const ChannelPerceptualHash *channel_phash) 614{ 615 register ssize_t 616 i; 617 618 ssize_t 619 n; 620 621 n=FormatLocaleFile(file," \"%s\": {\n",name); 622 for (i=0; i < 6; i++) 623 n+=FormatLocaleFile(file, 624 " \"PH%.20g\": [ \"%.*g\", \"%.*g\" ],\n",i+1.0, 625 GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i], 626 GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]); 627 n+=FormatLocaleFile(file, 628 " \"PH%.20g\": [ \"%.*g\", \"%.*g\" ]\n",i+1.0, 629 GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i], 630 GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]); 631 (void) FormatLocaleFile(file," }"); 632 if (separator != MagickFalse) 633 (void) FormatLocaleFile(file,","); 634 (void) FormatLocaleFile(file,"\n"); 635 return(n); 636} 637 638static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel, 639 const char *name,const double scale,const MagickBooleanType separator, 640 const ChannelStatistics *channel_statistics) 641{ 642#define StatisticsFormat " \"%s\": {\n \"min\": \"" QuantumFormat \ 643 "\",\n \"max\": \"" QuantumFormat "\",\n" \ 644 " \"mean\": \"%g\",\n \"standardDeviation\": " \ 645 "\"%g\",\n \"kurtosis\": \"%g\",\n \"skewness\": " \ 646 "\"%g\"\n }" 647 648 ssize_t 649 n; 650 651 n=FormatLocaleFile(file,StatisticsFormat,name,ClampToQuantum(scale* 652 channel_statistics[channel].minima),ClampToQuantum(scale* 653 channel_statistics[channel].maxima),scale*channel_statistics[channel].mean, 654 scale*channel_statistics[channel].standard_deviation, 655 channel_statistics[channel].kurtosis,channel_statistics[channel].skewness); 656 if (separator != MagickFalse) 657 (void) FormatLocaleFile(file,","); 658 (void) FormatLocaleFile(file,"\n"); 659 return(n); 660} 661 662static MagickBooleanType EncodeImageAttributes(Image *image,FILE *file, 663 ExceptionInfo *exception) 664{ 665 char 666 color[MagickPathExtent], 667 format[MagickPathExtent], 668 key[MagickPathExtent]; 669 670 ChannelFeatures 671 *channel_features; 672 673 ChannelMoments 674 *channel_moments; 675 676 ChannelPerceptualHash 677 *channel_phash; 678 679 ChannelStatistics 680 *channel_statistics; 681 682 ColorspaceType 683 colorspace; 684 685 const char 686 *artifact, 687 *locate, 688 *name, 689 *property, 690 *registry, 691 *value; 692 693 const MagickInfo 694 *magick_info; 695 696 double 697 elapsed_time, 698 user_time; 699 700 ImageType 701 base_type, 702 type; 703 704 MagickBooleanType 705 ping; 706 707 register const Quantum 708 *p; 709 710 register ssize_t 711 i, 712 x; 713 714 size_t 715 depth, 716 distance, 717 scale; 718 719 ssize_t 720 y; 721 722 assert(image != (Image *) NULL); 723 assert(image->signature == MagickCoreSignature); 724 if (image->debug != MagickFalse) 725 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 726 *format='\0'; 727 elapsed_time=GetElapsedTime(&image->timer); 728 user_time=GetUserTime(&image->timer); 729 GetTimerInfo(&image->timer); 730 p=GetVirtualPixels(image,0,0,1,1,exception); 731 ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse; 732 (void) ping; 733 (void) SignatureImage(image,exception); 734 JsonFormatLocaleFile(file,"{\n \"image\": {\n \"name\": %s,\n", 735 image->filename); 736 if (*image->magick_filename != '\0') 737 if (LocaleCompare(image->magick_filename,image->filename) != 0) 738 { 739 char 740 filename[MagickPathExtent]; 741 742 GetPathComponent(image->magick_filename,TailPath,filename); 743 JsonFormatLocaleFile(file," \"baseName\": %s,\n",filename); 744 } 745 JsonFormatLocaleFile(file," \"format\": %s,\n",image->magick); 746 magick_info=GetMagickInfo(image->magick,exception); 747 if ((magick_info != (const MagickInfo *) NULL) && 748 (GetMagickDescription(magick_info) != (const char *) NULL)) 749 JsonFormatLocaleFile(file," \"formatDescription\": %s,\n", 750 image->magick); 751 if ((magick_info != (const MagickInfo *) NULL) && 752 (GetMagickMimeType(magick_info) != (const char *) NULL)) 753 JsonFormatLocaleFile(file," \"mimeType\": %s,\n",GetMagickMimeType( 754 magick_info)); 755 JsonFormatLocaleFile(file," \"class\": %s,\n",CommandOptionToMnemonic( 756 MagickClassOptions,(ssize_t) image->storage_class)); 757 (void) FormatLocaleFile(file," \"geometry\": {\n" 758 " \"width\": %.20g,\n \"height\": %.20g,\n" 759 " \"x\": %.20g,\n \"y\": %.20g\n },\n", 760 (double) image->columns,(double) image->rows,(double) image->tile_offset.x, 761 (double) image->tile_offset.y); 762 if ((image->magick_columns != 0) || (image->magick_rows != 0)) 763 if ((image->magick_columns != image->columns) || 764 (image->magick_rows != image->rows)) 765 (void) FormatLocaleFile(file," \"baseGeometry\": {\n" 766 " \"width\": %.20g,\n \"height\": %.20g\n },\n", 767 (double) image->magick_columns,(double) image->magick_rows); 768 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0)) 769 { 770 (void) FormatLocaleFile(file," \"resolution\": {\n" 771 " \"x\": %.20g,\n \"y\": %.20g\n },\n", 772 image->resolution.x,image->resolution.y); 773 (void) FormatLocaleFile(file," \"printSize\": {\n" 774 " \"x\": %.20g,\n \"y\": %.20g\n },\n", 775 image->columns/image->resolution.x,(double) image->rows/ 776 image->resolution.y); 777 } 778 JsonFormatLocaleFile(file," \"units\": %s,\n",CommandOptionToMnemonic( 779 MagickResolutionOptions,(ssize_t) image->units)); 780 colorspace=image->colorspace; 781 type=IdentifyImageType(image,exception); 782 if ((type == BilevelType) || (type == GrayscaleType) || 783 (type == GrayscaleAlphaType)) 784 colorspace=GRAYColorspace; 785 JsonFormatLocaleFile(file," \"type\": %s,\n",CommandOptionToMnemonic( 786 MagickTypeOptions,(ssize_t) type)); 787 base_type=GetImageType(image); 788 if (type != base_type) 789 JsonFormatLocaleFile(file," \"baseType\": %s,\n", 790 CommandOptionToMnemonic(MagickTypeOptions,(ssize_t) base_type)); 791 JsonFormatLocaleFile(file," \"endianess\": %s,\n", 792 CommandOptionToMnemonic(MagickEndianOptions,(ssize_t) image->endian)); 793 locate=GetImageArtifact(image,"identify:locate"); 794 if (locate == (const char *) NULL) 795 locate=GetImageArtifact(image,"json:locate"); 796 if (locate != (const char *) NULL) 797 { 798 const char 799 *limit; 800 801 size_t 802 max_locations; 803 804 StatisticType 805 type; 806 807 /* 808 Display minimum, maximum, or mean pixel locations. 809 */ 810 type=(StatisticType) ParseCommandOption(MagickStatisticOptions, 811 MagickFalse,locate); 812 limit=GetImageArtifact(image,"identify:limit"); 813 if (limit == (const char *) NULL) 814 limit=GetImageArtifact(image,"json:limit"); 815 max_locations=0; 816 if (limit != (const char *) NULL) 817 max_locations=StringToUnsignedLong(limit); 818 channel_statistics=GetLocationStatistics(image,type,exception); 819 if (channel_statistics == (ChannelStatistics *) NULL) 820 return(MagickFalse); 821 (void) FormatLocaleFile(file," \"channel%s\": {\n",locate); 822 if (image->alpha_trait != UndefinedPixelTrait) 823 (void) PrintChannelLocations(file,image,AlphaPixelChannel,"Alpha", 824 type,max_locations,MagickTrue,channel_statistics); 825 switch (colorspace) 826 { 827 case RGBColorspace: 828 default: 829 { 830 (void) PrintChannelLocations(file,image,RedPixelChannel,"Red", 831 type,max_locations,MagickTrue,channel_statistics); 832 (void) PrintChannelLocations(file,image,GreenPixelChannel,"Green", 833 type,max_locations,MagickTrue,channel_statistics); 834 (void) PrintChannelLocations(file,image,BluePixelChannel,"Blue", 835 type,max_locations,MagickFalse,channel_statistics); 836 break; 837 } 838 case CMYKColorspace: 839 { 840 (void) PrintChannelLocations(file,image,CyanPixelChannel,"Cyan", 841 type,max_locations,MagickTrue,channel_statistics); 842 (void) PrintChannelLocations(file,image,MagentaPixelChannel,"Magenta", 843 type,max_locations,MagickTrue,channel_statistics); 844 (void) PrintChannelLocations(file,image,YellowPixelChannel,"Yellow", 845 type,max_locations,MagickTrue,channel_statistics); 846 (void) PrintChannelLocations(file,image,BlackPixelChannel,"Black", 847 type,max_locations,MagickFalse,channel_statistics); 848 break; 849 } 850 case GRAYColorspace: 851 { 852 (void) PrintChannelLocations(file,image,GrayPixelChannel,"Gray", 853 type,max_locations,MagickFalse,channel_statistics); 854 break; 855 } 856 } 857 (void) FormatLocaleFile(file," },\n"); 858 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( 859 channel_statistics); 860 } 861 /* 862 Detail channel depth and extrema. 863 */ 864 JsonFormatLocaleFile(file," \"colorspace\": %s,\n", 865 CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t) 866 image->colorspace)); 867 channel_statistics=(ChannelStatistics *) NULL; 868 channel_moments=(ChannelMoments *) NULL; 869 channel_phash=(ChannelPerceptualHash *) NULL; 870 channel_features=(ChannelFeatures *) NULL; 871 scale=1; 872 channel_statistics=GetImageStatistics(image,exception); 873 if (channel_statistics == (ChannelStatistics *) NULL) 874 return(MagickFalse); 875 artifact=GetImageArtifact(image,"identify:moments"); 876 if (artifact == (const char *) NULL) 877 artifact=GetImageArtifact(image,"json:moments"); 878 if (artifact != (const char *) NULL) 879 { 880 channel_moments=GetImageMoments(image,exception); 881 channel_phash=GetImagePerceptualHash(image,exception); 882 } 883 artifact=GetImageArtifact(image,"identify:features"); 884 if (artifact == (const char *) NULL) 885 artifact=GetImageArtifact(image,"json:features"); 886 if (artifact != (const char *) NULL) 887 { 888 distance=StringToUnsignedLong(artifact); 889 channel_features=GetImageFeatures(image,distance,exception); 890 } 891 depth=GetImageDepth(image,exception); 892 (void) FormatLocaleFile(file," \"depth\": %.20g,\n",(double) depth); 893 (void) FormatLocaleFile(file," \"baseDepth\": %.20g,\n",(double) 894 image->depth); 895 (void) FormatLocaleFile(file," \"channelDepth\": {\n"); 896 if (image->alpha_trait != UndefinedPixelTrait) 897 (void) FormatLocaleFile(file," \"alpha\": %.20g,\n",(double) 898 channel_statistics[AlphaPixelChannel].depth); 899 switch (colorspace) 900 { 901 case RGBColorspace: 902 default: 903 { 904 (void) FormatLocaleFile(file," \"red\": %.20g,\n",(double) 905 channel_statistics[RedChannel].depth); 906 (void) FormatLocaleFile(file," \"green\": %.20g,\n",(double) 907 channel_statistics[GreenChannel].depth); 908 (void) FormatLocaleFile(file," \"blue\": %.20g\n",(double) 909 channel_statistics[BlueChannel].depth); 910 break; 911 } 912 case CMYKColorspace: 913 { 914 (void) FormatLocaleFile(file," \"cyan\": %.20g,\n",(double) 915 channel_statistics[CyanChannel].depth); 916 (void) FormatLocaleFile(file," \"magenta\": %.20g,\n",(double) 917 channel_statistics[MagentaChannel].depth); 918 (void) FormatLocaleFile(file," \"yellow\": %.20g,\n",(double) 919 channel_statistics[YellowChannel].depth); 920 (void) FormatLocaleFile(file," \"black\": %.20g\n",(double) 921 channel_statistics[BlackChannel].depth); 922 break; 923 } 924 case GRAYColorspace: 925 { 926 (void) FormatLocaleFile(file," \"gray\": %.20g\n",(double) 927 channel_statistics[GrayChannel].depth); 928 break; 929 } 930 } 931 (void) FormatLocaleFile(file," },\n"); 932 scale=1; 933 if (image->depth <= MAGICKCORE_QUANTUM_DEPTH) 934 scale=QuantumRange/((size_t) QuantumRange >> ((size_t) 935 MAGICKCORE_QUANTUM_DEPTH-image->depth)); 936 if (channel_statistics != (ChannelStatistics *) NULL) 937 { 938 (void) FormatLocaleFile(file," \"pixels\": %.20g,\n", 939 channel_statistics[CompositePixelChannel].area); 940 if (colorspace != GRAYColorspace) 941 { 942 (void) FormatLocaleFile(file," \"imageStatistics\": {\n"); 943 (void) PrintChannelStatistics(file,(PixelChannel) MaxPixelChannels, 944 "Overall",1.0/scale,MagickFalse,channel_statistics); 945 (void) FormatLocaleFile(file," },\n"); 946 } 947 (void) FormatLocaleFile(file," \"channelStatistics\": {\n"); 948 if (image->alpha_trait != UndefinedPixelTrait) 949 (void) PrintChannelStatistics(file,AlphaPixelChannel,"Alpha",1.0/scale, 950 MagickTrue,channel_statistics); 951 switch (colorspace) 952 { 953 case RGBColorspace: 954 default: 955 { 956 (void) PrintChannelStatistics(file,RedPixelChannel,"Red",1.0/scale, 957 MagickTrue,channel_statistics); 958 (void) PrintChannelStatistics(file,GreenPixelChannel,"Green",1.0/ 959 scale,MagickTrue,channel_statistics); 960 (void) PrintChannelStatistics(file,BluePixelChannel,"Blue",1.0/scale, 961 MagickFalse,channel_statistics); 962 break; 963 } 964 case CMYKColorspace: 965 { 966 (void) PrintChannelStatistics(file,CyanPixelChannel,"Cyan",1.0/scale, 967 MagickTrue,channel_statistics); 968 (void) PrintChannelStatistics(file,MagentaPixelChannel,"Magenta",1.0/ 969 scale,MagickTrue,channel_statistics); 970 (void) PrintChannelStatistics(file,YellowPixelChannel,"Yellow",1.0/ 971 scale,MagickTrue,channel_statistics); 972 (void) PrintChannelStatistics(file,BlackPixelChannel,"Black",1.0/ 973 scale,MagickFalse,channel_statistics); 974 break; 975 } 976 case GRAYColorspace: 977 { 978 (void) PrintChannelStatistics(file,GrayPixelChannel,"Gray",1.0/scale, 979 MagickFalse,channel_statistics); 980 break; 981 } 982 } 983 (void) FormatLocaleFile(file," },\n"); 984 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory( 985 channel_statistics); 986 } 987 if (channel_moments != (ChannelMoments *) NULL) 988 { 989 (void) FormatLocaleFile(file," \"channelMoments\": {\n"); 990 if (image->alpha_trait != UndefinedPixelTrait) 991 (void) PrintChannelMoments(file,AlphaPixelChannel,"Alpha",MagickTrue, 992 channel_moments); 993 switch (colorspace) 994 { 995 case RGBColorspace: 996 default: 997 { 998 (void) PrintChannelMoments(file,RedPixelChannel,"Red",MagickTrue, 999 channel_moments); 1000 (void) PrintChannelMoments(file,GreenPixelChannel,"Green",MagickTrue, 1001 channel_moments); 1002 (void) PrintChannelMoments(file,BluePixelChannel,"Blue",MagickFalse, 1003 channel_moments); 1004 break; 1005 } 1006 case CMYKColorspace: 1007 { 1008 (void) PrintChannelMoments(file,CyanPixelChannel,"Cyan",MagickTrue, 1009 channel_moments); 1010 (void) PrintChannelMoments(file,MagentaPixelChannel,"Magenta", 1011 MagickTrue,channel_moments); 1012 (void) PrintChannelMoments(file,YellowPixelChannel,"Yellow", 1013 MagickTrue,channel_moments); 1014 (void) PrintChannelMoments(file,BlackPixelChannel,"Black", 1015 MagickFalse,channel_moments); 1016 break; 1017 } 1018 case GRAYColorspace: 1019 { 1020 (void) PrintChannelMoments(file,GrayPixelChannel,"Gray",MagickFalse, 1021 channel_moments); 1022 break; 1023 } 1024 } 1025 (void) FormatLocaleFile(file," },\n"); 1026 channel_moments=(ChannelMoments *) RelinquishMagickMemory( 1027 channel_moments); 1028 } 1029 if (channel_phash != (ChannelPerceptualHash *) NULL) 1030 { 1031 (void) FormatLocaleFile(file," \"channelPerceptualHash\": {\n"); 1032 if (image->alpha_trait != UndefinedPixelTrait) 1033 (void) PrintChannelPerceptualHash(file,AlphaChannel,"alphaAlpha", 1034 MagickTrue,channel_phash); 1035 (void) PrintChannelPerceptualHash(file,RedChannel,"redHue",MagickTrue, 1036 channel_phash); 1037 (void) PrintChannelPerceptualHash(file,GreenChannel,"greenChroma", 1038 MagickTrue,channel_phash); 1039 (void) PrintChannelPerceptualHash(file,BlueChannel,"blueLuma",MagickFalse, 1040 channel_phash); 1041 (void) FormatLocaleFile(file," },\n"); 1042 channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory( 1043 channel_phash); 1044 } 1045 if (channel_features != (ChannelFeatures *) NULL) 1046 { 1047 (void) FormatLocaleFile(file," \"channelFeatures\": {\n"); 1048 if (image->alpha_trait != UndefinedPixelTrait) 1049 (void) PrintChannelFeatures(file,AlphaPixelChannel,"Alpha",MagickTrue, 1050 channel_features); 1051 switch (colorspace) 1052 { 1053 case RGBColorspace: 1054 default: 1055 { 1056 (void) PrintChannelFeatures(file,RedPixelChannel,"Red",MagickTrue, 1057 channel_features); 1058 (void) PrintChannelFeatures(file,GreenPixelChannel,"Green", 1059 MagickTrue,channel_features); 1060 (void) PrintChannelFeatures(file,BluePixelChannel,"Blue",MagickFalse, 1061 channel_features); 1062 break; 1063 } 1064 case CMYKColorspace: 1065 { 1066 (void) PrintChannelFeatures(file,CyanPixelChannel,"Cyan",MagickTrue, 1067 channel_features); 1068 (void) PrintChannelFeatures(file,MagentaPixelChannel,"Magenta", 1069 MagickTrue,channel_features); 1070 (void) PrintChannelFeatures(file,YellowPixelChannel,"Yellow", 1071 MagickTrue,channel_features); 1072 (void) PrintChannelFeatures(file,BlackPixelChannel,"Black", 1073 MagickFalse,channel_features); 1074 break; 1075 } 1076 case GRAYColorspace: 1077 { 1078 (void) PrintChannelFeatures(file,GrayPixelChannel,"Gray",MagickFalse, 1079 channel_features); 1080 break; 1081 } 1082 } 1083 (void) FormatLocaleFile(file," },\n"); 1084 channel_features=(ChannelFeatures *) RelinquishMagickMemory( 1085 channel_features); 1086 } 1087 if (image->colorspace == CMYKColorspace) 1088 (void) FormatLocaleFile(file," \"totalInkDensity\": \"%.*g%%\",\n", 1089 GetMagickPrecision(),100.0*GetImageTotalInkDensity(image,exception)/ 1090 (double) QuantumRange); 1091 x=0; 1092 if (image->alpha_trait != UndefinedPixelTrait) 1093 { 1094 register const Quantum 1095 *p; 1096 1097 p=(const Quantum *) NULL; 1098 for (y=0; y < (ssize_t) image->rows; y++) 1099 { 1100 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1101 if (p == (const Quantum *) NULL) 1102 break; 1103 for (x=0; x < (ssize_t) image->columns; x++) 1104 { 1105 if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha) 1106 break; 1107 p+=GetPixelChannels(image); 1108 } 1109 if (x < (ssize_t) image->columns) 1110 break; 1111 } 1112 if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows)) 1113 { 1114 PixelInfo 1115 pixel; 1116 1117 GetPixelInfo(image,&pixel); 1118 GetPixelInfoPixel(image,p,&pixel); 1119 GetColorTuple(&pixel,MagickTrue,color); 1120 (void) FormatLocaleFile(file," \"alpha\": \"%s\",\n",color); 1121 } 1122 } 1123 if (image->storage_class == PseudoClass) 1124 { 1125 register PixelInfo 1126 *magick_restrict p; 1127 1128 (void) FormatLocaleFile(file," \"colormapEntries\": %.20g,\n", 1129 (double) image->colors); 1130 (void) FormatLocaleFile(file," \"colormap\": [\n "); 1131 p=image->colormap; 1132 for (i=0; i < (ssize_t) image->colors; i++) 1133 { 1134 GetColorTuple(p,MagickTrue,color); 1135 (void) FormatLocaleFile(file,"\"%s\"",color); 1136 if (i < (ssize_t) (image->colors-1)) 1137 (void) FormatLocaleFile(file,","); 1138 if (((i+1) % 5) == 0) 1139 (void) FormatLocaleFile(file,"\n "); 1140 p++; 1141 } 1142 (void) FormatLocaleFile(file,"\n ],\n"); 1143 } 1144 if (image->error.mean_error_per_pixel != 0.0) 1145 (void) FormatLocaleFile(file," \"meanErrorPerPixel\": \"%g\",\n", 1146 image->error.mean_error_per_pixel); 1147 if (image->error.normalized_mean_error != 0.0) 1148 (void) FormatLocaleFile(file," \"normalizedMeanError\": \"%g\",\n", 1149 image->error.normalized_mean_error); 1150 if (image->error.normalized_maximum_error != 0.0) 1151 (void) FormatLocaleFile(file," \"normalizedMaximumError\": \"%g\",\n", 1152 image->error.normalized_maximum_error); 1153 JsonFormatLocaleFile(file," \"renderingIntent\": %s,\n", 1154 CommandOptionToMnemonic(MagickIntentOptions,(ssize_t) 1155 image->rendering_intent)); 1156 if (image->gamma != 0.0) 1157 (void) FormatLocaleFile(file," \"gamma\": %g,\n",image->gamma); 1158 if ((image->chromaticity.red_primary.x != 0.0) || 1159 (image->chromaticity.green_primary.x != 0.0) || 1160 (image->chromaticity.blue_primary.x != 0.0) || 1161 (image->chromaticity.white_point.x != 0.0)) 1162 { 1163 /* 1164 Display image chromaticity. 1165 */ 1166 (void) FormatLocaleFile(file," \"chromaticity\": {\n"); 1167 (void) FormatLocaleFile(file," \"redPrimary\": {\n" 1168 " \"x\": %g,\n \"y\": %g\n },\n", 1169 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y); 1170 (void) FormatLocaleFile(file," \"greenPrimary\": {\n" 1171 " \"x\": %g,\n \"y\": %g\n },\n", 1172 image->chromaticity.green_primary.x, 1173 image->chromaticity.green_primary.y); 1174 (void) FormatLocaleFile(file," \"bluePrimary\": {\n" 1175 " \"x\": %g,\n \"y\": %g\n },\n", 1176 image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y); 1177 (void) FormatLocaleFile(file," \"whitePrimary\": {\n" 1178 " \"x\": %g,\n \"y\": %g\n }\n", 1179 image->chromaticity.white_point.x,image->chromaticity.white_point.y); 1180 (void) FormatLocaleFile(file," },\n"); 1181 } 1182 if ((image->extract_info.width*image->extract_info.height) != 0) 1183 (void) FormatLocaleFile(file," \"tileGeometry\": {\n" 1184 " \"width\": %.20g,\n \"height\": %.20g,\n" 1185 " \"x\": %.20g,\n \"y\": %.20g\n },\n", 1186 (double) image->extract_info.width,(double) image->extract_info.height, 1187 (double) image->extract_info.x,(double) image->extract_info.y); 1188 GetColorTuple(&image->alpha_color,MagickTrue,color); 1189 (void) FormatLocaleFile(file," \"alphaColor\": \"%s\",\n",color); 1190 GetColorTuple(&image->background_color,MagickTrue,color); 1191 (void) FormatLocaleFile(file," \"backgroundColor\": \"%s\",\n",color); 1192 GetColorTuple(&image->border_color,MagickTrue,color); 1193 (void) FormatLocaleFile(file," \"borderColor\": \"%s\",\n",color); 1194 GetColorTuple(&image->transparent_color,MagickTrue,color); 1195 (void) FormatLocaleFile(file," \"transparentColor\": \"%s\",\n",color); 1196 JsonFormatLocaleFile(file," \"interlace\": %s,\n",CommandOptionToMnemonic( 1197 MagickInterlaceOptions,(ssize_t) image->interlace)); 1198 JsonFormatLocaleFile(file," \"intensity\": %s,\n",CommandOptionToMnemonic( 1199 MagickPixelIntensityOptions,(ssize_t) image->intensity)); 1200 JsonFormatLocaleFile(file," \"compose\": %s,\n", 1201 CommandOptionToMnemonic(MagickComposeOptions,(ssize_t) image->compose)); 1202 if ((image->page.width != 0) || (image->page.height != 0) || 1203 (image->page.x != 0) || (image->page.y != 0)) 1204 (void) FormatLocaleFile(file," \"pageGeometry\": {\n" 1205 " \"width\": %.20g,\n \"height\": %.20g,\n" 1206 " \"x\": %.20g,\n \"y\": %.20g\n },\n", 1207 (double) image->page.width,(double) image->page.height, 1208 (double) image->page.x,(double) image->page.y); 1209 if ((image->page.x != 0) || (image->page.y != 0)) 1210 (void) FormatLocaleFile(file," \"originGeometry\": %+.20g%+.20g\n", 1211 (double) image->page.x,(double) image->page.y); 1212 JsonFormatLocaleFile(file," \"dispose\": %s,\n", 1213 CommandOptionToMnemonic(MagickDisposeOptions,(ssize_t) image->dispose)); 1214 if (image->delay != 0) 1215 (void) FormatLocaleFile(file," \"delay\": \"%.20gx%.20g\"\n", 1216 (double) image->delay,(double) image->ticks_per_second); 1217 if (image->iterations != 1) 1218 (void) FormatLocaleFile(file," \"iterations\": %.20g,\n",(double) 1219 image->iterations); 1220 if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL)) 1221 (void) FormatLocaleFile(file," \"scene\": %.20g\n \"scenes\": " 1222 "%.20g\n",(double) image->scene,(double) GetImageListLength(image)); 1223 else 1224 if (image->scene != 0) 1225 (void) FormatLocaleFile(file," \"scene\": %.20g,\n",(double) 1226 image->scene); 1227 JsonFormatLocaleFile(file," \"compression\": %s,\n", 1228 CommandOptionToMnemonic(MagickCompressOptions,(ssize_t) 1229 image->compression)); 1230 if (image->quality != UndefinedCompressionQuality) 1231 (void) FormatLocaleFile(file," \"quality\": %.20g,\n",(double) 1232 image->quality); 1233 JsonFormatLocaleFile(file," \"orientation\": %s,\n", 1234 CommandOptionToMnemonic(MagickOrientationOptions,(ssize_t) 1235 image->orientation)); 1236 if (image->montage != (char *) NULL) 1237 JsonFormatLocaleFile(file," \"montage\": \"%s\",\n",image->montage); 1238 if (image->directory != (char *) NULL) 1239 { 1240 Image 1241 *tile; 1242 1243 ImageInfo 1244 *image_info; 1245 1246 register char 1247 *p, 1248 *q; 1249 1250 WarningHandler 1251 handler; 1252 1253 /* 1254 Display visual image directory. 1255 */ 1256 image_info=AcquireImageInfo(); 1257 (void) CloneString(&image_info->size,"64x64"); 1258 (void) FormatLocaleFile(file," \"montageDirectory\": ["); 1259 p=image->directory; 1260 while (*p != '\0') 1261 { 1262 q=p; 1263 while ((*q != '\n') && (*q != '\0')) 1264 q++; 1265 (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1)); 1266 p=q+1; 1267 JsonFormatLocaleFile(file,"{\n \"name\": %s", 1268 image_info->filename); 1269 handler=SetWarningHandler((WarningHandler) NULL); 1270 tile=ReadImage(image_info,exception); 1271 (void) SetWarningHandler(handler); 1272 if (tile == (Image *) NULL) 1273 { 1274 (void) FormatLocaleFile(file," }"); 1275 continue; 1276 } 1277 (void) FormatLocaleFile(file,",\n \"info\": \"%.20gx%.20g %s\"", 1278 (double) tile->magick_columns,(double) tile->magick_rows, 1279 tile->magick); 1280 (void) SignatureImage(tile,exception); 1281 ResetImagePropertyIterator(tile); 1282 property=GetNextImageProperty(tile); 1283 while (property != (const char *) NULL) 1284 { 1285 JsonFormatLocaleFile(file,",\n %s: ",property); 1286 value=GetImageProperty(tile,property,exception); 1287 JsonFormatLocaleFile(file,"%s",value); 1288 property=GetNextImageProperty(tile); 1289 } 1290 tile=DestroyImage(tile); 1291 if (*p != '\0') 1292 (void) FormatLocaleFile(file,"\n },"); 1293 else 1294 (void) FormatLocaleFile(file,"\n }"); 1295 } 1296 (void) FormatLocaleFile(file,"],\n"); 1297 image_info=DestroyImageInfo(image_info); 1298 } 1299 (void) GetImageProperty(image,"exif:*",exception); 1300 (void) GetImageProperty(image,"icc:*",exception); 1301 (void) GetImageProperty(image,"iptc:*",exception); 1302 (void) GetImageProperty(image,"xmp:*",exception); 1303 ResetImagePropertyIterator(image); 1304 property=GetNextImageProperty(image); 1305 if (property != (const char *) NULL) 1306 { 1307 size_t 1308 n; 1309 1310 /* 1311 Display image properties. 1312 */ 1313 n=0; 1314 (void) FormatLocaleFile(file," \"properties\": {\n"); 1315 while (property != (const char *) NULL) 1316 { 1317 if (n++ != 0) 1318 (void) FormatLocaleFile(file,",\n"); 1319 JsonFormatLocaleFile(file," %s: ",property); 1320 value=GetImageProperty(image,property,exception); 1321 JsonFormatLocaleFile(file,"%s",value); 1322 property=GetNextImageProperty(image); 1323 } 1324 (void) FormatLocaleFile(file,"\n },\n"); 1325 } 1326 (void) FormatLocaleString(key,MagickPathExtent,"8BIM:1999,2998:#1"); 1327 value=GetImageProperty(image,key,exception); 1328 if (value != (const char *) NULL) 1329 { 1330 /* 1331 Display clipping path. 1332 */ 1333 (void) FormatLocaleFile(file," \"clipping path\": {\n"); 1334 JsonFormatLocaleFile(file,"%s\n",value); 1335 (void) FormatLocaleFile(file," },\n"); 1336 } 1337 ResetImageProfileIterator(image); 1338 name=GetNextImageProfile(image); 1339 if (name != (char *) NULL) 1340 { 1341 const StringInfo 1342 *profile; 1343 1344 size_t 1345 n; 1346 1347 /* 1348 Identify image profiles. 1349 */ 1350 n=0; 1351 (void) FormatLocaleFile(file," \"profiles\": {\n"); 1352 while (name != (char *) NULL) 1353 { 1354 profile=GetImageProfile(image,name); 1355 if (profile == (StringInfo *) NULL) 1356 continue; 1357 if (n++ != 0) 1358 (void) FormatLocaleFile(file,",\n"); 1359 JsonFormatLocaleFile(file," %s: {\n",name); 1360 if (LocaleCompare(name,"iptc") == 0) 1361 { 1362 char 1363 *attribute, 1364 **attribute_list; 1365 1366 const char 1367 *tag; 1368 1369 long 1370 dataset, 1371 record, 1372 sentinel; 1373 1374 register ssize_t 1375 j; 1376 1377 size_t 1378 length, 1379 profile_length; 1380 1381 profile_length=GetStringInfoLength(profile); 1382 for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length) 1383 { 1384 length=1; 1385 sentinel=GetStringInfoDatum(profile)[i++]; 1386 if (sentinel != 0x1c) 1387 continue; 1388 dataset=GetStringInfoDatum(profile)[i++]; 1389 record=GetStringInfoDatum(profile)[i++]; 1390 switch (record) 1391 { 1392 case 5: tag="Image Name"; break; 1393 case 7: tag="Edit Status"; break; 1394 case 10: tag="Priority"; break; 1395 case 15: tag="Category"; break; 1396 case 20: tag="Supplemental Category"; break; 1397 case 22: tag="Fixture Identifier"; break; 1398 case 25: tag="Keyword"; break; 1399 case 30: tag="Release Date"; break; 1400 case 35: tag="Release Time"; break; 1401 case 40: tag="Special Instructions"; break; 1402 case 45: tag="Reference Service"; break; 1403 case 47: tag="Reference Date"; break; 1404 case 50: tag="Reference Number"; break; 1405 case 55: tag="Created Date"; break; 1406 case 60: tag="Created Time"; break; 1407 case 65: tag="Originating Program"; break; 1408 case 70: tag="Program Version"; break; 1409 case 75: tag="Object Cycle"; break; 1410 case 80: tag="Byline"; break; 1411 case 85: tag="Byline Title"; break; 1412 case 90: tag="City"; break; 1413 case 92: tag="Sub-Location"; break; 1414 case 95: tag="Province State"; break; 1415 case 100: tag="Country Code"; break; 1416 case 101: tag="Country"; break; 1417 case 103: tag="Original Transmission Reference"; break; 1418 case 105: tag="Headline"; break; 1419 case 110: tag="Credit"; break; 1420 case 115: tag="Src"; break; 1421 case 116: tag="Copyright String"; break; 1422 case 120: tag="Caption"; break; 1423 case 121: tag="Local Caption"; break; 1424 case 122: tag="Caption Writer"; break; 1425 case 200: tag="Custom Field 1"; break; 1426 case 201: tag="Custom Field 2"; break; 1427 case 202: tag="Custom Field 3"; break; 1428 case 203: tag="Custom Field 4"; break; 1429 case 204: tag="Custom Field 5"; break; 1430 case 205: tag="Custom Field 6"; break; 1431 case 206: tag="Custom Field 7"; break; 1432 case 207: tag="Custom Field 8"; break; 1433 case 208: tag="Custom Field 9"; break; 1434 case 209: tag="Custom Field 10"; break; 1435 case 210: tag="Custom Field 11"; break; 1436 case 211: tag="Custom Field 12"; break; 1437 case 212: tag="Custom Field 13"; break; 1438 case 213: tag="Custom Field 14"; break; 1439 case 214: tag="Custom Field 15"; break; 1440 case 215: tag="Custom Field 16"; break; 1441 case 216: tag="Custom Field 17"; break; 1442 case 217: tag="Custom Field 18"; break; 1443 case 218: tag="Custom Field 19"; break; 1444 case 219: tag="Custom Field 20"; break; 1445 default: tag="unknown"; break; 1446 } 1447 (void) FormatLocaleFile(file," %s[%.20g,%.20g]: ",tag, 1448 (double) dataset,(double) record); 1449 length=(size_t) (GetStringInfoDatum(profile)[i++] << 8); 1450 length|=GetStringInfoDatum(profile)[i++]; 1451 attribute=(char *) NULL; 1452 if (~length >= (MagickPathExtent-1)) 1453 attribute=(char *) AcquireQuantumMemory(length+MagickPathExtent, 1454 sizeof(*attribute)); 1455 if (attribute != (char *) NULL) 1456 { 1457 (void) CopyMagickString(attribute,(char *) 1458 GetStringInfoDatum(profile)+i,length+1); 1459 attribute_list=StringToList(attribute); 1460 if (attribute_list != (char **) NULL) 1461 { 1462 (void) FormatLocaleFile(file,"["); 1463 for (j=0; attribute_list[j] != (char *) NULL; j++) 1464 { 1465 if (j != 0) 1466 (void) FormatLocaleFile(file,","); 1467 JsonFormatLocaleFile(file,"%s",attribute_list[j]); 1468 attribute_list[j]=(char *) RelinquishMagickMemory( 1469 attribute_list[j]); 1470 } 1471 (void) FormatLocaleFile(file,"],"); 1472 attribute_list=(char **) RelinquishMagickMemory( 1473 attribute_list); 1474 } 1475 else 1476 (void) FormatLocaleFile(file,"null,"); 1477 attribute=DestroyString(attribute); 1478 } 1479 else 1480 (void) FormatLocaleFile(file,"null,"); 1481 } 1482 } 1483 (void) FormatLocaleFile(file," \"length\": \"%.20g\"",(double) 1484 GetStringInfoLength(profile)); 1485 (void) FormatLocaleFile(file,"\n }"); 1486 name=GetNextImageProfile(image); 1487 } 1488 (void) FormatLocaleFile(file,"\n },\n"); 1489 } 1490 ResetImageArtifactIterator(image); 1491 artifact=GetNextImageArtifact(image); 1492 if (artifact != (const char *) NULL) 1493 { 1494 ssize_t 1495 n; 1496 1497 /* 1498 Display image artifacts. 1499 */ 1500 n=0; 1501 (void) FormatLocaleFile(file," \"artifacts\": {\n"); 1502 while (artifact != (const char *) NULL) 1503 { 1504 if (n++ != 0) 1505 (void) FormatLocaleFile(file,",\n"); 1506 JsonFormatLocaleFile(file," %s: ",artifact); 1507 value=GetImageArtifact(image,artifact); 1508 JsonFormatLocaleFile(file,"%s",value); 1509 artifact=GetNextImageArtifact(image); 1510 } 1511 (void) FormatLocaleFile(file,"\n },\n"); 1512 } 1513 ResetImageRegistryIterator(); 1514 registry=GetNextImageRegistry(); 1515 if (registry != (const char *) NULL) 1516 { 1517 ssize_t 1518 n; 1519 1520 /* 1521 Display image registry. 1522 */ 1523 (void) FormatLocaleFile(file," \"registry\": {\n"); 1524 n=0; 1525 while (registry != (const char *) NULL) 1526 { 1527 if (n++ != 0) 1528 (void) FormatLocaleFile(file,",\n"); 1529 JsonFormatLocaleFile(file," %s: ",registry); 1530 value=(const char *) GetImageRegistry(StringRegistryType,registry, 1531 exception); 1532 JsonFormatLocaleFile(file,"%s",value); 1533 registry=GetNextImageRegistry(); 1534 } 1535 (void) FormatLocaleFile(file," },\n"); 1536 } 1537 (void) FormatLocaleFile(file," \"tainted\": %s,\n", 1538 image->taint != MagickFalse ? "true" : "false"); 1539 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",MagickPathExtent, 1540 format); 1541 JsonFormatLocaleFile(file," \"filesize\": %s,\n",format); 1542 (void) FormatMagickSize((MagickSizeType) image->columns*image->rows, 1543 MagickFalse,"B",MagickPathExtent,format); 1544 if (strlen(format) > 1) 1545 format[strlen(format)-1]='\0'; 1546 JsonFormatLocaleFile(file," \"numberPixels\": %s,\n",format); 1547 (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/ 1548 elapsed_time+0.5),MagickFalse,"B",MagickPathExtent,format); 1549 JsonFormatLocaleFile(file," \"pixelsPerSecond\": %s,\n",format); 1550 (void) FormatLocaleFile(file," \"userTime\": \"%0.3fu\",\n",user_time); 1551 (void) FormatLocaleFile(file," \"elapsedTime\": \"%lu:%02lu.%03lu\",\n", 1552 (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod( 1553 elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor( 1554 elapsed_time)))); 1555 JsonFormatLocaleFile(file," \"version\": %s\n", 1556 GetMagickVersion((size_t *) NULL)); 1557 (void) FormatLocaleFile(file," }\n}\n"); 1558 (void) fflush(file); 1559 return(ferror(file) != 0 ? MagickFalse : MagickTrue); 1560} 1561 1562static MagickBooleanType WriteJSONImage(const ImageInfo *image_info, 1563 Image *image,ExceptionInfo *exception) 1564{ 1565 FILE 1566 *file; 1567 1568 MagickBooleanType 1569 status; 1570 1571 MagickOffsetType 1572 scene; 1573 1574 /* 1575 Open output image file. 1576 */ 1577 assert(image_info != (const ImageInfo *) NULL); 1578 assert(image_info->signature == MagickCoreSignature); 1579 assert(image != (Image *) NULL); 1580 assert(image->signature == MagickCoreSignature); 1581 if (image->debug != MagickFalse) 1582 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1583 status=OpenBlob(image_info,image,WriteBlobMode,exception); 1584 if (status == MagickFalse) 1585 return(status); 1586 file=GetBlobFileHandle(image); 1587 if (file == (FILE *) NULL) 1588 file=stdout; 1589 scene=0; 1590 do 1591 { 1592 WriteBlobString(image,"["); 1593 image->magick_columns=image->columns; 1594 image->magick_rows=image->rows; 1595 EncodeImageAttributes(image,file,exception); 1596 if (GetNextImageInList(image) == (Image *) NULL) 1597 { 1598 WriteBlobString(image,"]"); 1599 break; 1600 } 1601 WriteBlobString(image,",\n"); 1602 image=SyncNextImageInList(image); 1603 status=SetImageProgress(image,SaveImagesTag,scene++, 1604 GetImageListLength(image)); 1605 if (status == MagickFalse) 1606 break; 1607 } while (image_info->adjoin != MagickFalse); 1608 (void) CloseBlob(image); 1609 return(MagickTrue); 1610} 1611