blob: 404e68c741c92b204f11abe27bb3b69b0bf12753 [file] [log] [blame]
cristy3f07aa32014-01-18 01:16:33 +00001/*
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% %
cristyb56bb242014-11-25 17:12:48 +000020% Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
cristy3f07aa32014-01-18 01:16:33 +000021% 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"
cristy9e818982014-01-18 14:54:37 +000044#include "MagickCore/attribute.h"
cristy3f07aa32014-01-18 01:16:33 +000045#include "MagickCore/blob.h"
46#include "MagickCore/blob-private.h"
cristy9e818982014-01-18 14:54:37 +000047#include "MagickCore/cache.h"
cristy43602772014-01-29 14:07:29 +000048#include "MagickCore/colorspace.h"
49#include "MagickCore/colorspace-private.h"
cristy9e818982014-01-18 14:54:37 +000050#include "MagickCore/constitute.h"
cristy3f07aa32014-01-18 01:16:33 +000051#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
cristy9e818982014-01-18 14:54:37 +000053#include "MagickCore/feature.h"
cristy3f07aa32014-01-18 01:16:33 +000054#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"
cristy43602772014-01-29 14:07:29 +000062#include "MagickCore/pixel.h"
cristy9e818982014-01-18 14:54:37 +000063#include "MagickCore/pixel-accessor.h"
cristy43602772014-01-29 14:07:29 +000064#include "MagickCore/pixel-private.h"
cristy9e818982014-01-18 14:54:37 +000065#include "MagickCore/prepress.h"
cristy3f07aa32014-01-18 01:16:33 +000066#include "MagickCore/property.h"
cristy43602772014-01-29 14:07:29 +000067#include "MagickCore/quantum-private.h"
cristy9e818982014-01-18 14:54:37 +000068#include "MagickCore/registry.h"
cristy9e818982014-01-18 14:54:37 +000069#include "MagickCore/signature.h"
cristy43602772014-01-29 14:07:29 +000070#include "MagickCore/static.h"
cristy9e818982014-01-18 14:54:37 +000071#include "MagickCore/statistic.h"
cristy3f07aa32014-01-18 01:16:33 +000072#include "MagickCore/string_.h"
cristy9e818982014-01-18 14:54:37 +000073#include "MagickCore/string-private.h"
cristy3f07aa32014-01-18 01:16:33 +000074#include "MagickCore/utility.h"
cristy9e818982014-01-18 14:54:37 +000075#include "MagickCore/version.h"
cristy43602772014-01-29 14:07:29 +000076#include "MagickCore/module.h"
cristy3f07aa32014-01-18 01:16:33 +000077
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
cristye1c94d92015-06-28 12:16:33 +0000112 entry=AcquireMagickInfo("JSON","JSON","The image format and characteristics");
cristy3f07aa32014-01-18 01:16:33 +0000113 entry->encoder=(EncodeImageHandler *) WriteJSONImage;
dirk08e9a112015-02-22 01:51:41 +0000114 entry->flags^=CoderBlobSupportFlag;
cristy3f07aa32014-01-18 01:16:33 +0000115 (void) RegisterMagickInfo(entry);
116 return(MagickImageCoderSignature);
117}
118
119/*
120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121% %
122% %
123% %
124% U n r e g i s t e r J S O N I m a g e %
125% %
126% %
127% %
128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
129%
130% UnregisterJSONImage() removes format registrations made by the
131% JSON module from the list of supported formats.
132%
133% The format of the UnregisterJSONImage method is:
134%
135% UnregisterJSONImage(void)
136%
137*/
138ModuleExport void UnregisterJSONImage(void)
139{
140 (void) UnregisterMagickInfo("JSON");
141}
142
143/*
144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145% %
146% %
147% %
148% W r i t e J S O N I m a g e %
149% %
150% %
151% %
152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153%
154% WriteJSONImage writes the image attributes in the JSON format.
155%
156% The format of the WriteJSONImage method is:
157%
158% MagickBooleanType WriteJSONImage(const ImageInfo *image_info,
159% Image *image,ExceptionInfo *exception)
160%
161% A description of each parameter follows.
162%
163% o image_info: the image info.
164%
165% o image: The image.
166%
167% o exception: return any errors or warnings in this structure.
168%
169*/
cristy9e818982014-01-18 14:54:37 +0000170
dirk6c316f22015-06-27 15:44:29 +0000171static void JsonFormatLocaleFile(FILE *file,const char *format,const char *value)
172{
173 char
174 *escaped_json;
175
176 register char
177 *q;
178
179 register const char
180 *p;
181
182 size_t
183 length;
184
185 assert(format != (const char *) NULL);
186 if (value == (char *) NULL || *value == '\0')
187 {
188 (void) FormatLocaleFile(file,format,"null");
189 return;
190 }
191 length=strlen(value)+2;
192 /*
193 Find all the chars that need escaping and increase the dest length counter
194 */
195 for (p=value; *p != '\0'; p++)
196 {
197 switch (*p)
198 {
199 case '"':
200 case '\b':
201 case '\f':
202 case '\n':
203 case '\r':
204 case '\t':
205 case '\\':
206 if (~length < 1)
207 return;
208 length++;
209 break;
210 default:
211 break;
212 }
213 }
214 escaped_json=(char *) NULL;
215 if (~length >= (MagickPathExtent-1))
216 escaped_json=(char *) AcquireQuantumMemory(length+MagickPathExtent,
217 sizeof(*escaped_json));
218 if (escaped_json == (char *) NULL)
219 {
220 (void) FormatLocaleFile(file,format,"null");
221 return;
222 }
223 q=escaped_json;
224 *q++='"';
225 for (p=value; *p != '\0'; p++)
226 {
227 switch (*p)
228 {
229 case '"':
230 *q++='\\';
231 *q++=(*p);
232 break;
233 case '\b':
234 *q++='\\';
235 *q++='b';
236 break;
237 case '\f':
238 *q++='\\';
239 *q++='f';
240 break;
241 case '\n':
242 *q++='\\';
243 *q++='n';
244 break;
245 case '\r':
246 *q++='\\';
247 *q++='r';
248 break;
249 case '\t':
250 *q++='\\';
251 *q++='t';
252 break;
253 case '\\':
254 *q++='\\';
255 *q++='\\';
256 break;
257 default:
258 *q++=(*p);
259 break;
260 }
261 }
262 *q++='"';
263 *q='\0';
264 (void) FormatLocaleFile(file,format,escaped_json);
265 (void) DestroyString(escaped_json);
266}
267
cristy9e818982014-01-18 14:54:37 +0000268static ChannelStatistics *GetLocationStatistics(const Image *image,
269 const StatisticType type,ExceptionInfo *exception)
270{
271 ChannelStatistics
272 *channel_statistics;
273
274 register ssize_t
275 i;
276
277 ssize_t
278 y;
279
280 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000281 assert(image->signature == MagickCoreSignature);
cristy9e818982014-01-18 14:54:37 +0000282 if (image->debug != MagickFalse)
283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
284 channel_statistics=(ChannelStatistics *) AcquireQuantumMemory(
285 MaxPixelChannels+1,sizeof(*channel_statistics));
286 if (channel_statistics == (ChannelStatistics *) NULL)
287 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
288 (void) ResetMagickMemory(channel_statistics,0,(MaxPixelChannels+1)*
289 sizeof(*channel_statistics));
290 for (i=0; i <= (ssize_t) MaxPixelChannels; i++)
291 {
292 switch (type)
293 {
294 case MaximumStatistic:
295 default:
296 {
cristyfe181a72014-02-02 21:17:43 +0000297 channel_statistics[i].maxima=(-MagickMaximumValue);
cristy9e818982014-01-18 14:54:37 +0000298 break;
299 }
300 case MinimumStatistic:
301 {
cristyfe181a72014-02-02 21:17:43 +0000302 channel_statistics[i].minima=MagickMaximumValue;
cristy9e818982014-01-18 14:54:37 +0000303 break;
304 }
305 }
306 }
307 for (y=0; y < (ssize_t) image->rows; y++)
308 {
309 register const Quantum
310 *restrict p;
311
312 register ssize_t
313 x;
314
315 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
316 if (p == (const Quantum *) NULL)
317 break;
318 for (x=0; x < (ssize_t) image->columns; x++)
319 {
320 register ssize_t
321 i;
322
323 if (GetPixelReadMask(image,p) == 0)
324 {
325 p+=GetPixelChannels(image);
326 continue;
327 }
328 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
329 {
330 PixelChannel channel=GetPixelChannelChannel(image,i);
331 PixelTrait traits=GetPixelChannelTraits(image,channel);
332 if (traits == UndefinedPixelTrait)
333 continue;
334 switch (type)
335 {
336 case MaximumStatistic:
337 default:
338 {
339 if ((double) p[i] > channel_statistics[channel].maxima)
340 channel_statistics[channel].maxima=(double) p[i];
341 break;
342 }
343 case MinimumStatistic:
344 {
345 if ((double) p[i] < channel_statistics[channel].minima)
346 channel_statistics[channel].minima=(double) p[i];
347 break;
348 }
349 }
350 }
351 p+=GetPixelChannels(image);
352 }
353 }
354 return(channel_statistics);
355}
356
357static ssize_t PrintChannelFeatures(FILE *file,const PixelChannel channel,
dirk6c316f22015-06-27 15:44:29 +0000358 const char *name,const MagickBooleanType separator,
359 const ChannelFeatures *channel_features)
cristy9e818982014-01-18 14:54:37 +0000360{
361#define PrintFeature(feature) \
362 GetMagickPrecision(),(feature)[0], \
363 GetMagickPrecision(),(feature)[1], \
364 GetMagickPrecision(),(feature)[2], \
365 GetMagickPrecision(),(feature)[3], \
366 GetMagickPrecision(),((feature)[0]+(feature)[1]+(feature)[2]+(feature)[3])/4.0 \
367
dirk6c316f22015-06-27 15:44:29 +0000368#define FeaturesFormat " \"%s\": {\n" \
369 " \"angularSecondMoment\": {\n" \
370 " \"horizontal\": \"%.*g\",\n" \
371 " \"vertical\": \"%.*g\",\n" \
372 " \"leftDiagonal\": \"%.*g\",\n" \
373 " \"rightDiagonal\": \"%.*g\",\n" \
374 " \"average\": \"%.*g\"\n" \
375 " },\n" \
376 " \"contrast\": {\n" \
377 " \"horizontal\": \"%.*g\",\n" \
378 " \"vertical\": \"%.*g\",\n" \
379 " \"leftDiagonal\": \"%.*g\",\n" \
380 " \"rightDiagonal\": \"%.*g\",\n" \
381 " \"average\": \"%.*g\"\n" \
382 " },\n" \
383 " \"correlation\": {\n" \
384 " \"horizontal\": \"%.*g\",\n" \
385 " \"vertical\": \"%.*g\",\n" \
386 " \"leftDiagonal\": \"%.*g\",\n" \
387 " \"rightDiagonal\": \"%.*g\",\n" \
388 " \"average\": \"%.*g\"\n" \
389 " },\n" \
390 " \"sumOfSquaresVariance\": {\n" \
391 " \"horizontal\": \"%.*g\",\n" \
392 " \"vertical\": \"%.*g\",\n" \
393 " \"leftDiagonal\": \"%.*g\",\n" \
394 " \"rightDiagonal\": \"%.*g\",\n" \
395 " \"average\": \"%.*g\"\n" \
396 " },\n" \
397 " \"inverseDifferenceMoment\": {\n" \
398 " \"horizontal\": \"%.*g\",\n" \
399 " \"vertical\": \"%.*g\",\n" \
400 " \"leftDiagonal\": \"%.*g\",\n" \
401 " \"rightDiagonal\": \"%.*g\",\n" \
402 " \"average\": \"%.*g\"\n" \
403 " },\n" \
404 " \"sumAverage\": {\n" \
405 " \"horizontal\": \"%.*g\",\n" \
406 " \"vertical\": \"%.*g\",\n" \
407 " \"leftDiagonal\": \"%.*g\",\n" \
408 " \"rightDiagonal\": \"%.*g\",\n" \
409 " \"average\": \"%.*g\"\n" \
410 " },\n" \
411 " \"sumVariance\": {\n" \
412 " \"horizontal\": \"%.*g\",\n" \
413 " \"vertical\": \"%.*g\",\n" \
414 " \"leftDiagonal\": \"%.*g\",\n" \
415 " \"rightDiagonal\": \"%.*g\",\n" \
416 " \"average\": \"%.*g\"\n" \
417 " },\n" \
418 " \"sumEntropy\": {\n" \
419 " \"horizontal\": \"%.*g\",\n" \
420 " \"vertical\": \"%.*g\",\n" \
421 " \"leftDiagonal\": \"%.*g\",\n" \
422 " \"rightDiagonal\": \"%.*g\",\n" \
423 " \"average\": \"%.*g\"\n" \
424 " },\n" \
425 " \"entropy\": {\n" \
426 " \"horizontal\": \"%.*g\",\n" \
427 " \"vertical\": \"%.*g\",\n" \
428 " \"leftDiagonal\": \"%.*g\",\n" \
429 " \"rightDiagonal\": \"%.*g\",\n" \
430 " \"average\": \"%.*g\"\n" \
431 " },\n" \
432 " \"differenceVariance\": {\n" \
433 " \"horizontal\": \"%.*g\",\n" \
434 " \"vertical\": \"%.*g\",\n" \
435 " \"leftDiagonal\": \"%.*g\",\n" \
436 " \"rightDiagonal\": \"%.*g\",\n" \
437 " \"average\": \"%.*g\"\n" \
438 " },\n" \
439 " \"differenceEntropy\": {\n" \
440 " \"horizontal\": \"%.*g\",\n" \
441 " \"vertical\": \"%.*g\",\n" \
442 " \"leftDiagonal\": \"%.*g\",\n" \
443 " \"rightDiagonal\": \"%.*g\",\n" \
444 " \"average\": \"%.*g\"\n" \
445 " },\n" \
446 " \"informationMeasureOfCorrelation1\": {\n" \
447 " \"horizontal\": \"%.*g\",\n" \
448 " \"vertical\": \"%.*g\",\n" \
449 " \"leftDiagonal\": \"%.*g\",\n" \
450 " \"rightDiagonal\": \"%.*g\",\n" \
451 " \"average\": \"%.*g\"\n" \
452 " },\n" \
453 " \"informationMeasureOfCorrelation2\": {\n" \
454 " \"horizontal\": \"%.*g\",\n" \
455 " \"vertical\": \"%.*g\",\n" \
456 " \"leftDiagonal\": \"%.*g\",\n" \
457 " \"rightDiagonal\": \"%.*g\",\n" \
458 " \"average\": \"%.*g\"\n" \
459 " },\n" \
460 " \"maximumCorrelationCoefficient\": {\n" \
461 " \"horizontal\": \"%.*g\",\n" \
462 " \"vertical\": \"%.*g\",\n" \
463 " \"leftDiagonal\": \"%.*g\",\n" \
464 " \"rightDiagonal\": \"%.*g\",\n" \
465 " \"average\": \"%.*g\"\n" \
466 " }\n"
cristy9e818982014-01-18 14:54:37 +0000467
468 ssize_t
469 n;
470
471 n=FormatLocaleFile(file,FeaturesFormat,name,
472 PrintFeature(channel_features[channel].angular_second_moment),
473 PrintFeature(channel_features[channel].contrast),
474 PrintFeature(channel_features[channel].correlation),
475 PrintFeature(channel_features[channel].variance_sum_of_squares),
476 PrintFeature(channel_features[channel].inverse_difference_moment),
477 PrintFeature(channel_features[channel].sum_average),
478 PrintFeature(channel_features[channel].sum_variance),
479 PrintFeature(channel_features[channel].sum_entropy),
480 PrintFeature(channel_features[channel].entropy),
481 PrintFeature(channel_features[channel].difference_variance),
482 PrintFeature(channel_features[channel].difference_entropy),
483 PrintFeature(channel_features[channel].measure_of_correlation_1),
484 PrintFeature(channel_features[channel].measure_of_correlation_2),
485 PrintFeature(channel_features[channel].maximum_correlation_coefficient));
dirk6c316f22015-06-27 15:44:29 +0000486 (void) FormatLocaleFile(file," }");
487 if (separator != MagickFalse)
488 (void) FormatLocaleFile(file,",");
489 (void) FormatLocaleFile(file,"\n");
cristy9e818982014-01-18 14:54:37 +0000490 return(n);
491}
492
493static ssize_t PrintChannelLocations(FILE *file,const Image *image,
494 const PixelChannel channel,const char *name,const StatisticType type,
dirk6c316f22015-06-27 15:44:29 +0000495 const size_t max_locations,const MagickBooleanType separator,
496 const ChannelStatistics *channel_statistics)
cristy9e818982014-01-18 14:54:37 +0000497{
498 double
499 target;
500
501 ExceptionInfo
502 *exception;
503
504 ssize_t
505 n,
506 y;
507
508 switch (type)
509 {
510 case MaximumStatistic:
511 default:
512 {
513 target=channel_statistics[channel].maxima;
514 break;
515 }
516 case MinimumStatistic:
517 {
518 target=channel_statistics[channel].minima;
519 break;
520 }
521 }
dirk6c316f22015-06-27 15:44:29 +0000522 (void) FormatLocaleFile(file," \"%s\": {\n \"intensity\": "
523 "\"%.*g\",\n",name,GetMagickPrecision(),QuantumScale*target);
cristy9e818982014-01-18 14:54:37 +0000524 exception=AcquireExceptionInfo();
525 n=0;
526 for (y=0; y < (ssize_t) image->rows; y++)
527 {
528 register const Quantum
529 *p;
530
531 ssize_t
532 offset,
533 x;
534
535 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
536 if (p == (const Quantum *) NULL)
537 break;
538 for (x=0; x < (ssize_t) image->columns; x++)
539 {
540 MagickBooleanType
541 match;
542
543 PixelTrait traits=GetPixelChannelTraits(image,channel);
544 if (traits == UndefinedPixelTrait)
545 continue;
546 offset=GetPixelChannelOffset(image,channel);
cristy3bdd9252014-12-21 20:01:43 +0000547 match=fabs((double) (p[offset]-target)) < 0.5 ? MagickTrue : MagickFalse;
cristy9e818982014-01-18 14:54:37 +0000548 if (match != MagickFalse)
549 {
550 if ((max_locations != 0) && (n >= (ssize_t) max_locations))
551 break;
dirk6c316f22015-06-27 15:44:29 +0000552 if (n != 0)
553 (void) FormatLocaleFile(file,",\n");
554 (void) FormatLocaleFile(file," \"location%.20g\": {\n"
555 " \"x\": %.20g,\n \"y\": %.20g\n"
556 " }",(double) n,(double) x,(double) y);
cristy9e818982014-01-18 14:54:37 +0000557 n++;
558 }
559 p+=GetPixelChannels(image);
560 }
561 if (x < (ssize_t) image->columns)
562 break;
563 }
dirk6c316f22015-06-27 15:44:29 +0000564 (void) FormatLocaleFile(file,"\n }");
565 if (separator != MagickFalse)
566 (void) FormatLocaleFile(file,",");
cristy9e818982014-01-18 14:54:37 +0000567 (void) FormatLocaleFile(file,"\n");
568 return(n);
569}
570
571static ssize_t PrintChannelMoments(FILE *file,const PixelChannel channel,
dirk6c316f22015-06-27 15:44:29 +0000572 const char *name,const MagickBooleanType separator,
573 const ChannelMoments *channel_moments)
cristy9e818982014-01-18 14:54:37 +0000574{
575 register ssize_t
576 i;
577
578 ssize_t
579 n;
580
dirk6c316f22015-06-27 15:44:29 +0000581 n=FormatLocaleFile(file," \"%s\": {\n",name);
582 n+=FormatLocaleFile(file," \"centroid\": {\n "
583 " \"x\": \"%.*g\",\n"
584 " \"y\": \"%.*g\"\n },\n",
cristy9e818982014-01-18 14:54:37 +0000585 GetMagickPrecision(),channel_moments[channel].centroid.x,
586 GetMagickPrecision(),channel_moments[channel].centroid.y);
dirk6c316f22015-06-27 15:44:29 +0000587 n+=FormatLocaleFile(file," \"ellipseSemiMajorMinorAxis\": {\n"
588 " \"x\": \"%.*g\",\n"
589 " \"y\": \"%.*g\"\n },\n",
cristy9e818982014-01-18 14:54:37 +0000590 GetMagickPrecision(),channel_moments[channel].ellipse_axis.x,
591 GetMagickPrecision(),channel_moments[channel].ellipse_axis.y);
dirk6c316f22015-06-27 15:44:29 +0000592 n+=FormatLocaleFile(file," \"ellipseAngle\": \"%.*g\",\n",
cristy9e818982014-01-18 14:54:37 +0000593 GetMagickPrecision(),channel_moments[channel].ellipse_angle);
dirk6c316f22015-06-27 15:44:29 +0000594 n+=FormatLocaleFile(file," \"ellipseEccentricity\": \"%.*g\",\n",
cristy9e818982014-01-18 14:54:37 +0000595 GetMagickPrecision(),channel_moments[channel].ellipse_eccentricity);
dirk6c316f22015-06-27 15:44:29 +0000596 n+=FormatLocaleFile(file," \"ellipseIntensity\": \"%.*g\",\n",
cristy9e818982014-01-18 14:54:37 +0000597 GetMagickPrecision(),channel_moments[channel].ellipse_intensity);
dirk6c316f22015-06-27 15:44:29 +0000598 for (i=0; i < 7; i++)
599 n+=FormatLocaleFile(file," \"I%.20g\": \"%.*g\",\n",i+1.0,
600 GetMagickPrecision(),channel_moments[channel].invariant[i]);
601 n+=FormatLocaleFile(file," \"I%.20g\": \"%.*g\"\n",i+1.0,
602 GetMagickPrecision(),channel_moments[channel].invariant[i]);
603 (void) FormatLocaleFile(file," }");
604 if (separator != MagickFalse)
605 (void) FormatLocaleFile(file,",");
606 (void) FormatLocaleFile(file,"\n");
cristy9e818982014-01-18 14:54:37 +0000607 return(n);
608}
609
cristydc395172014-02-23 01:33:36 +0000610static ssize_t PrintChannelPerceptualHash(FILE *file,const ChannelType channel,
611 const char *name,const MagickBooleanType separator,
612 const ChannelPerceptualHash *channel_phash)
613{
614 register ssize_t
615 i;
616
617 ssize_t
618 n;
619
620 n=FormatLocaleFile(file," \"%s\": {\n",name);
cristy79a41dc2014-02-23 21:42:49 +0000621 for (i=0; i < 6; i++)
cristydc395172014-02-23 01:33:36 +0000622 n+=FormatLocaleFile(file,
cristyff4072b2014-02-23 21:47:32 +0000623 " \"PH%.20g\": [ \"%.*g\", \"%.*g\" ],\n",i+1.0,
cristyc0187622014-09-06 00:45:58 +0000624 GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i],
625 GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]);
cristydc395172014-02-23 01:33:36 +0000626 n+=FormatLocaleFile(file,
cristyff4072b2014-02-23 21:47:32 +0000627 " \"PH%.20g\": [ \"%.*g\", \"%.*g\" ]\n",i+1.0,
cristyc0187622014-09-06 00:45:58 +0000628 GetMagickPrecision(),channel_phash[channel].srgb_hu_phash[i],
629 GetMagickPrecision(),channel_phash[channel].hclp_hu_phash[i]);
cristydc395172014-02-23 01:33:36 +0000630 (void) FormatLocaleFile(file," }");
631 if (separator != MagickFalse)
632 (void) FormatLocaleFile(file,",");
633 (void) FormatLocaleFile(file,"\n");
634 return(n);
635}
636
cristy9e818982014-01-18 14:54:37 +0000637static ssize_t PrintChannelStatistics(FILE *file,const PixelChannel channel,
dirk6c316f22015-06-27 15:44:29 +0000638 const char *name,const double scale,const MagickBooleanType separator,
cristy9e818982014-01-18 14:54:37 +0000639 const ChannelStatistics *channel_statistics)
640{
dirk6c316f22015-06-27 15:44:29 +0000641#define StatisticsFormat " \"%s\": {\n \"min\": \"" QuantumFormat \
642 "\",\n \"max\": \"" QuantumFormat "\",\n" \
643 " \"mean\": \"%g\",\n \"standardDeviation\": " \
644 "\"%g\",\n \"kurtosis\": \"%g\",\n \"skewness\": " \
645 "\"%g\"\n }"
cristy9e818982014-01-18 14:54:37 +0000646
647 ssize_t
648 n;
649
650 n=FormatLocaleFile(file,StatisticsFormat,name,ClampToQuantum(scale*
cristye1c94d92015-06-28 12:16:33 +0000651 channel_statistics[channel].minima),ClampToQuantum(scale*
652 channel_statistics[channel].maxima),scale*channel_statistics[channel].mean,
653 scale*channel_statistics[channel].standard_deviation,
cristy9e818982014-01-18 14:54:37 +0000654 channel_statistics[channel].kurtosis,channel_statistics[channel].skewness);
dirk6c316f22015-06-27 15:44:29 +0000655 if (separator != MagickFalse)
cristye1c94d92015-06-28 12:16:33 +0000656 (void) FormatLocaleFile(file,",");
dirk6c316f22015-06-27 15:44:29 +0000657 (void) FormatLocaleFile(file,"\n");
cristy9e818982014-01-18 14:54:37 +0000658 return(n);
659}
660
661static MagickBooleanType EncodeImageAttributes(Image *image,FILE *file,
662 ExceptionInfo *exception)
663{
cristy9e818982014-01-18 14:54:37 +0000664 char
cristy151b66d2015-04-15 10:50:31 +0000665 color[MagickPathExtent],
666 format[MagickPathExtent],
667 key[MagickPathExtent];
cristy9e818982014-01-18 14:54:37 +0000668
669 ChannelFeatures
670 *channel_features;
671
672 ChannelMoments
673 *channel_moments;
674
cristydc395172014-02-23 01:33:36 +0000675 ChannelPerceptualHash
676 *channel_phash;
677
cristy9e818982014-01-18 14:54:37 +0000678 ChannelStatistics
679 *channel_statistics;
680
681 ColorspaceType
682 colorspace;
683
684 const char
685 *artifact,
686 *locate,
687 *name,
688 *property,
689 *registry,
690 *value;
691
692 const MagickInfo
693 *magick_info;
694
695 double
696 elapsed_time,
697 user_time;
698
699 ImageType
dirkab4f0bb2015-07-25 11:46:32 +0000700 base_type,
cristy9e818982014-01-18 14:54:37 +0000701 type;
702
703 MagickBooleanType
704 ping;
705
706 register const Quantum
707 *p;
708
709 register ssize_t
710 i,
711 x;
712
713 size_t
dirk6c316f22015-06-27 15:44:29 +0000714 depth,
cristy9e818982014-01-18 14:54:37 +0000715 distance,
716 scale;
717
718 ssize_t
719 y;
720
721 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000722 assert(image->signature == MagickCoreSignature);
cristy9e818982014-01-18 14:54:37 +0000723 if (image->debug != MagickFalse)
724 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristya10f7442014-01-19 18:32:15 +0000725 *format='\0';
726 elapsed_time=GetElapsedTime(&image->timer);
727 user_time=GetUserTime(&image->timer);
728 GetTimerInfo(&image->timer);
729 p=GetVirtualPixels(image,0,0,1,1,exception);
730 ping=p == (const Quantum *) NULL ? MagickTrue : MagickFalse;
cristye1c94d92015-06-28 12:16:33 +0000731 (void) ping;
cristya10f7442014-01-19 18:32:15 +0000732 (void) SignatureImage(image,exception);
dirk6c316f22015-06-27 15:44:29 +0000733 JsonFormatLocaleFile(file,"{\n \"image\": {\n \"name\": %s,\n",
734 image->filename);
cristya10f7442014-01-19 18:32:15 +0000735 if (*image->magick_filename != '\0')
736 if (LocaleCompare(image->magick_filename,image->filename) != 0)
737 {
738 char
cristy151b66d2015-04-15 10:50:31 +0000739 filename[MagickPathExtent];
cristya10f7442014-01-19 18:32:15 +0000740
741 GetPathComponent(image->magick_filename,TailPath,filename);
dirk6c316f22015-06-27 15:44:29 +0000742 JsonFormatLocaleFile(file," \"baseName\": %s,\n",filename);
cristya10f7442014-01-19 18:32:15 +0000743 }
dirk6c316f22015-06-27 15:44:29 +0000744 JsonFormatLocaleFile(file," \"format\": %s,\n",image->magick);
cristya10f7442014-01-19 18:32:15 +0000745 magick_info=GetMagickInfo(image->magick,exception);
dirk6c316f22015-06-27 15:44:29 +0000746 if ((magick_info != (const MagickInfo *) NULL) &&
747 (GetMagickDescription(magick_info) != (const char *) NULL))
748 JsonFormatLocaleFile(file," \"formatDescription\": %s,\n",
749 image->magick);
cristy12bcd3d2015-01-28 00:54:23 +0000750 if ((magick_info != (const MagickInfo *) NULL) &&
cristya10f7442014-01-19 18:32:15 +0000751 (GetMagickMimeType(magick_info) != (const char *) NULL))
dirk6c316f22015-06-27 15:44:29 +0000752 JsonFormatLocaleFile(file," \"mimeType\": %s,\n",GetMagickMimeType(
cristya10f7442014-01-19 18:32:15 +0000753 magick_info));
dirk6c316f22015-06-27 15:44:29 +0000754 JsonFormatLocaleFile(file," \"class\": %s,\n",CommandOptionToMnemonic(
cristya10f7442014-01-19 18:32:15 +0000755 MagickClassOptions,(ssize_t) image->storage_class));
dirk6c316f22015-06-27 15:44:29 +0000756 (void) FormatLocaleFile(file," \"geometry\": {\n"
757 " \"width\": %.20g,\n \"height\": %.20g,\n"
758 " \"x\": %.20g,\n \"y\": %.20g\n },\n",
759 (double) image->columns,(double) image->rows,(double) image->tile_offset.x,
760 (double) image->tile_offset.y);
cristya10f7442014-01-19 18:32:15 +0000761 if ((image->magick_columns != 0) || (image->magick_rows != 0))
762 if ((image->magick_columns != image->columns) ||
763 (image->magick_rows != image->rows))
dirk6c316f22015-06-27 15:44:29 +0000764 (void) FormatLocaleFile(file," \"baseGeometry\": {\n"
765 " \"width\": %.20g,\n \"height\": %.20g\n },\n",
766 (double) image->magick_columns,(double) image->magick_rows);
cristya10f7442014-01-19 18:32:15 +0000767 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
768 {
dirk6c316f22015-06-27 15:44:29 +0000769 (void) FormatLocaleFile(file," \"resolution\": {\n"
770 " \"x\": %.20g,\n \"y\": %.20g\n },\n",
771 image->resolution.x,image->resolution.y);
772 (void) FormatLocaleFile(file," \"printSize\": {\n"
773 " \"x\": %.20g,\n \"y\": %.20g\n },\n",
cristya10f7442014-01-19 18:32:15 +0000774 image->columns/image->resolution.x,(double) image->rows/
775 image->resolution.y);
776 }
dirk6c316f22015-06-27 15:44:29 +0000777 JsonFormatLocaleFile(file," \"units\": %s,\n",CommandOptionToMnemonic(
cristya10f7442014-01-19 18:32:15 +0000778 MagickResolutionOptions,(ssize_t) image->units));
dirkab4f0bb2015-07-25 11:46:32 +0000779 colorspace=image->colorspace;
780 type=IdentifyImageType(image,exception);
781 if ((type == BilevelType) || (type == GrayscaleType) ||
782 (type == GrayscaleAlphaType))
783 colorspace=GRAYColorspace;
dirk6c316f22015-06-27 15:44:29 +0000784 JsonFormatLocaleFile(file," \"type\": %s,\n",CommandOptionToMnemonic(
cristya10f7442014-01-19 18:32:15 +0000785 MagickTypeOptions,(ssize_t) type));
dirkab4f0bb2015-07-25 11:46:32 +0000786 base_type=GetImageType(image);
787 if (type != base_type)
dirk6c316f22015-06-27 15:44:29 +0000788 JsonFormatLocaleFile(file," \"baseType\": %s,\n",
dirkab4f0bb2015-07-25 11:46:32 +0000789 CommandOptionToMnemonic(MagickTypeOptions,(ssize_t) base_type));
dirk6c316f22015-06-27 15:44:29 +0000790 JsonFormatLocaleFile(file," \"endianess\": %s,\n",
791 CommandOptionToMnemonic(MagickEndianOptions,(ssize_t) image->endian));
cristy9e818982014-01-18 14:54:37 +0000792 locate=GetImageArtifact(image,"identify:locate");
cristy3e583dd2014-01-19 14:11:51 +0000793 if (locate == (const char *) NULL)
794 locate=GetImageArtifact(image,"json:locate");
cristy9e818982014-01-18 14:54:37 +0000795 if (locate != (const char *) NULL)
796 {
797 const char
798 *limit;
799
800 size_t
801 max_locations;
802
803 StatisticType
804 type;
805
806 /*
807 Display minimum, maximum, or mean pixel locations.
808 */
809 type=(StatisticType) ParseCommandOption(MagickStatisticOptions,
810 MagickFalse,locate);
811 limit=GetImageArtifact(image,"identify:limit");
cristy3e583dd2014-01-19 14:11:51 +0000812 if (limit == (const char *) NULL)
813 limit=GetImageArtifact(image,"json:limit");
cristy9e818982014-01-18 14:54:37 +0000814 max_locations=0;
815 if (limit != (const char *) NULL)
816 max_locations=StringToUnsignedLong(limit);
817 channel_statistics=GetLocationStatistics(image,type,exception);
818 if (channel_statistics == (ChannelStatistics *) NULL)
819 return(MagickFalse);
dirk6c316f22015-06-27 15:44:29 +0000820 (void) FormatLocaleFile(file," \"channel%s\": {\n",locate);
821 if (image->alpha_trait != UndefinedPixelTrait)
822 (void) PrintChannelLocations(file,image,AlphaPixelChannel,"Alpha",
823 type,max_locations,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000824 switch (colorspace)
825 {
826 case RGBColorspace:
827 default:
828 {
829 (void) PrintChannelLocations(file,image,RedPixelChannel,"Red",
dirk6c316f22015-06-27 15:44:29 +0000830 type,max_locations,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000831 (void) PrintChannelLocations(file,image,GreenPixelChannel,"Green",
dirk6c316f22015-06-27 15:44:29 +0000832 type,max_locations,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000833 (void) PrintChannelLocations(file,image,BluePixelChannel,"Blue",
dirk6c316f22015-06-27 15:44:29 +0000834 type,max_locations,MagickFalse,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000835 break;
836 }
837 case CMYKColorspace:
838 {
839 (void) PrintChannelLocations(file,image,CyanPixelChannel,"Cyan",
dirk6c316f22015-06-27 15:44:29 +0000840 type,max_locations,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000841 (void) PrintChannelLocations(file,image,MagentaPixelChannel,"Magenta",
dirk6c316f22015-06-27 15:44:29 +0000842 type,max_locations,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000843 (void) PrintChannelLocations(file,image,YellowPixelChannel,"Yellow",
dirk6c316f22015-06-27 15:44:29 +0000844 type,max_locations,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000845 (void) PrintChannelLocations(file,image,BlackPixelChannel,"Black",
dirk6c316f22015-06-27 15:44:29 +0000846 type,max_locations,MagickFalse,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000847 break;
848 }
849 case GRAYColorspace:
850 {
851 (void) PrintChannelLocations(file,image,GrayPixelChannel,"Gray",
dirk6c316f22015-06-27 15:44:29 +0000852 type,max_locations,MagickFalse,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000853 break;
854 }
855 }
dirk6c316f22015-06-27 15:44:29 +0000856 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +0000857 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
858 channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000859 }
cristy9e818982014-01-18 14:54:37 +0000860 /*
861 Detail channel depth and extrema.
862 */
dirk6c316f22015-06-27 15:44:29 +0000863 JsonFormatLocaleFile(file," \"colorspace\": %s,\n",
864 CommandOptionToMnemonic(MagickColorspaceOptions,(ssize_t)
865 image->colorspace));
cristy9e818982014-01-18 14:54:37 +0000866 channel_statistics=(ChannelStatistics *) NULL;
867 channel_moments=(ChannelMoments *) NULL;
cristydc395172014-02-23 01:33:36 +0000868 channel_phash=(ChannelPerceptualHash *) NULL;
cristy9e818982014-01-18 14:54:37 +0000869 channel_features=(ChannelFeatures *) NULL;
cristy9e818982014-01-18 14:54:37 +0000870 scale=1;
dirk6c316f22015-06-27 15:44:29 +0000871 channel_statistics=GetImageStatistics(image,exception);
872 if (channel_statistics == (ChannelStatistics *) NULL)
873 return(MagickFalse);
874 artifact=GetImageArtifact(image,"identify:moments");
875 if (artifact == (const char *) NULL)
876 artifact=GetImageArtifact(image,"json:moments");
877 if (artifact != (const char *) NULL)
cristy9e818982014-01-18 14:54:37 +0000878 {
dirk6c316f22015-06-27 15:44:29 +0000879 channel_moments=GetImageMoments(image,exception);
880 channel_phash=GetImagePerceptualHash(image,exception);
cristy9e818982014-01-18 14:54:37 +0000881 }
dirk6c316f22015-06-27 15:44:29 +0000882 artifact=GetImageArtifact(image,"identify:features");
883 if (artifact == (const char *) NULL)
884 artifact=GetImageArtifact(image,"json:features");
885 if (artifact != (const char *) NULL)
886 {
887 distance=StringToUnsignedLong(artifact);
888 channel_features=GetImageFeatures(image,distance,exception);
889 }
890 depth=GetImageDepth(image,exception);
891 (void) FormatLocaleFile(file," \"depth\": %.20g,\n",(double) depth);
892 (void) FormatLocaleFile(file," \"baseDepth\": %.20g,\n",(double)
893 image->depth);
894 (void) FormatLocaleFile(file," \"channelDepth\": {\n");
dirk6c316f22015-06-27 15:44:29 +0000895 if (image->alpha_trait != UndefinedPixelTrait)
896 (void) FormatLocaleFile(file," \"alpha\": %.20g,\n",(double)
897 channel_statistics[AlphaPixelChannel].depth);
898 switch (colorspace)
899 {
900 case RGBColorspace:
901 default:
902 {
903 (void) FormatLocaleFile(file," \"red\": %.20g,\n",(double)
904 channel_statistics[RedChannel].depth);
905 (void) FormatLocaleFile(file," \"green\": %.20g,\n",(double)
906 channel_statistics[GreenChannel].depth);
907 (void) FormatLocaleFile(file," \"blue\": %.20g\n",(double)
908 channel_statistics[BlueChannel].depth);
909 break;
910 }
911 case CMYKColorspace:
912 {
913 (void) FormatLocaleFile(file," \"cyan\": %.20g,\n",(double)
914 channel_statistics[CyanChannel].depth);
915 (void) FormatLocaleFile(file," \"magenta\": %.20g,\n",(double)
916 channel_statistics[MagentaChannel].depth);
917 (void) FormatLocaleFile(file," \"yellow\": %.20g,\n",(double)
918 channel_statistics[YellowChannel].depth);
919 (void) FormatLocaleFile(file," \"black\": %.20g\n",(double)
920 channel_statistics[BlackChannel].depth);
921 break;
922 }
923 case GRAYColorspace:
924 {
925 (void) FormatLocaleFile(file," \"gray\": %.20g\n",(double)
926 channel_statistics[GrayChannel].depth);
927 break;
928 }
929 }
930 (void) FormatLocaleFile(file," },\n");
931 scale=1;
932 if (image->depth <= MAGICKCORE_QUANTUM_DEPTH)
933 scale=QuantumRange/((size_t) QuantumRange >> ((size_t)
934 MAGICKCORE_QUANTUM_DEPTH-image->depth));
cristy9e818982014-01-18 14:54:37 +0000935 if (channel_statistics != (ChannelStatistics *) NULL)
936 {
dirk6c316f22015-06-27 15:44:29 +0000937 (void) FormatLocaleFile(file," \"pixels\": %.20g,\n",
cristy9e818982014-01-18 14:54:37 +0000938 channel_statistics[CompositePixelChannel].area);
dirk6c316f22015-06-27 15:44:29 +0000939 if (colorspace != GRAYColorspace)
940 {
941 (void) FormatLocaleFile(file," \"imageStatistics\": {\n");
942 (void) PrintChannelStatistics(file,(PixelChannel) MaxPixelChannels,
943 "Overall",1.0/scale,MagickFalse,channel_statistics);
944 (void) FormatLocaleFile(file," },\n");
945 }
946 (void) FormatLocaleFile(file," \"channelStatistics\": {\n");
947 if (image->alpha_trait != UndefinedPixelTrait)
948 (void) PrintChannelStatistics(file,AlphaPixelChannel,"Alpha",1.0/scale,
949 MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000950 switch (colorspace)
951 {
952 case RGBColorspace:
953 default:
954 {
dirk6c316f22015-06-27 15:44:29 +0000955 (void) PrintChannelStatistics(file,RedPixelChannel,"Red",1.0/scale,
956 MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000957 (void) PrintChannelStatistics(file,GreenPixelChannel,"Green",1.0/
dirk6c316f22015-06-27 15:44:29 +0000958 scale,MagickTrue,channel_statistics);
959 (void) PrintChannelStatistics(file,BluePixelChannel,"Blue",1.0/scale,
960 MagickFalse,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000961 break;
962 }
963 case CMYKColorspace:
964 {
dirk6c316f22015-06-27 15:44:29 +0000965 (void) PrintChannelStatistics(file,CyanPixelChannel,"Cyan",1.0/scale,
966 MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000967 (void) PrintChannelStatistics(file,MagentaPixelChannel,"Magenta",1.0/
dirk6c316f22015-06-27 15:44:29 +0000968 scale,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000969 (void) PrintChannelStatistics(file,YellowPixelChannel,"Yellow",1.0/
dirk6c316f22015-06-27 15:44:29 +0000970 scale,MagickTrue,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000971 (void) PrintChannelStatistics(file,BlackPixelChannel,"Black",1.0/
dirk6c316f22015-06-27 15:44:29 +0000972 scale,MagickFalse,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000973 break;
974 }
975 case GRAYColorspace:
976 {
dirk6c316f22015-06-27 15:44:29 +0000977 (void) PrintChannelStatistics(file,GrayPixelChannel,"Gray",1.0/scale,
978 MagickFalse,channel_statistics);
cristy9e818982014-01-18 14:54:37 +0000979 break;
980 }
981 }
dirk6c316f22015-06-27 15:44:29 +0000982 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +0000983 channel_statistics=(ChannelStatistics *) RelinquishMagickMemory(
984 channel_statistics);
985 }
986 if (channel_moments != (ChannelMoments *) NULL)
987 {
dirk6c316f22015-06-27 15:44:29 +0000988 (void) FormatLocaleFile(file," \"channelMoments\": {\n");
989 if (image->alpha_trait != UndefinedPixelTrait)
990 (void) PrintChannelMoments(file,AlphaPixelChannel,"Alpha",MagickTrue,
991 channel_moments);
cristy9e818982014-01-18 14:54:37 +0000992 switch (colorspace)
993 {
994 case RGBColorspace:
995 default:
996 {
dirk6c316f22015-06-27 15:44:29 +0000997 (void) PrintChannelMoments(file,RedPixelChannel,"Red",MagickTrue,
cristy9e818982014-01-18 14:54:37 +0000998 channel_moments);
dirk6c316f22015-06-27 15:44:29 +0000999 (void) PrintChannelMoments(file,GreenPixelChannel,"Green",MagickTrue,
cristy9e818982014-01-18 14:54:37 +00001000 channel_moments);
dirk6c316f22015-06-27 15:44:29 +00001001 (void) PrintChannelMoments(file,BluePixelChannel,"Blue",MagickFalse,
cristy9e818982014-01-18 14:54:37 +00001002 channel_moments);
1003 break;
1004 }
1005 case CMYKColorspace:
1006 {
dirk6c316f22015-06-27 15:44:29 +00001007 (void) PrintChannelMoments(file,CyanPixelChannel,"Cyan",MagickTrue,
cristy9e818982014-01-18 14:54:37 +00001008 channel_moments);
1009 (void) PrintChannelMoments(file,MagentaPixelChannel,"Magenta",
dirk6c316f22015-06-27 15:44:29 +00001010 MagickTrue,channel_moments);
cristy9e818982014-01-18 14:54:37 +00001011 (void) PrintChannelMoments(file,YellowPixelChannel,"Yellow",
dirk6c316f22015-06-27 15:44:29 +00001012 MagickTrue,channel_moments);
cristy9e818982014-01-18 14:54:37 +00001013 (void) PrintChannelMoments(file,BlackPixelChannel,"Black",
dirk6c316f22015-06-27 15:44:29 +00001014 MagickFalse,channel_moments);
cristy9e818982014-01-18 14:54:37 +00001015 break;
1016 }
1017 case GRAYColorspace:
1018 {
dirk6c316f22015-06-27 15:44:29 +00001019 (void) PrintChannelMoments(file,GrayPixelChannel,"Gray",MagickFalse,
cristy9e818982014-01-18 14:54:37 +00001020 channel_moments);
1021 break;
1022 }
1023 }
dirk6c316f22015-06-27 15:44:29 +00001024 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +00001025 channel_moments=(ChannelMoments *) RelinquishMagickMemory(
1026 channel_moments);
1027 }
cristydc395172014-02-23 01:33:36 +00001028 if (channel_phash != (ChannelPerceptualHash *) NULL)
1029 {
1030 (void) FormatLocaleFile(file," \"channelPerceptualHash\": {\n");
cristy17f11b02014-12-20 19:37:04 +00001031 if (image->alpha_trait != UndefinedPixelTrait)
cristydc395172014-02-23 01:33:36 +00001032 (void) PrintChannelPerceptualHash(file,AlphaChannel,"alphaAlpha",
1033 MagickTrue,channel_phash);
1034 (void) PrintChannelPerceptualHash(file,RedChannel,"redHue",MagickTrue,
1035 channel_phash);
1036 (void) PrintChannelPerceptualHash(file,GreenChannel,"greenChroma",
1037 MagickTrue,channel_phash);
1038 (void) PrintChannelPerceptualHash(file,BlueChannel,"blueLuma",MagickFalse,
1039 channel_phash);
1040 (void) FormatLocaleFile(file," },\n");
1041 channel_phash=(ChannelPerceptualHash *) RelinquishMagickMemory(
1042 channel_phash);
1043 }
cristy9e818982014-01-18 14:54:37 +00001044 if (channel_features != (ChannelFeatures *) NULL)
1045 {
dirk6c316f22015-06-27 15:44:29 +00001046 (void) FormatLocaleFile(file," \"channelFeatures\": {\n");
1047 if (image->alpha_trait != UndefinedPixelTrait)
1048 (void) PrintChannelFeatures(file,AlphaPixelChannel,"Alpha",MagickTrue,
1049 channel_features);
cristy9e818982014-01-18 14:54:37 +00001050 switch (colorspace)
1051 {
1052 case RGBColorspace:
1053 default:
1054 {
dirk6c316f22015-06-27 15:44:29 +00001055 (void) PrintChannelFeatures(file,RedPixelChannel,"Red",MagickTrue,
cristy9e818982014-01-18 14:54:37 +00001056 channel_features);
1057 (void) PrintChannelFeatures(file,GreenPixelChannel,"Green",
dirk6c316f22015-06-27 15:44:29 +00001058 MagickTrue,channel_features);
1059 (void) PrintChannelFeatures(file,BluePixelChannel,"Blue",MagickFalse,
cristy9e818982014-01-18 14:54:37 +00001060 channel_features);
1061 break;
1062 }
1063 case CMYKColorspace:
1064 {
dirk6c316f22015-06-27 15:44:29 +00001065 (void) PrintChannelFeatures(file,CyanPixelChannel,"Cyan",MagickTrue,
cristy9e818982014-01-18 14:54:37 +00001066 channel_features);
1067 (void) PrintChannelFeatures(file,MagentaPixelChannel,"Magenta",
dirk6c316f22015-06-27 15:44:29 +00001068 MagickTrue,channel_features);
cristy9e818982014-01-18 14:54:37 +00001069 (void) PrintChannelFeatures(file,YellowPixelChannel,"Yellow",
dirk6c316f22015-06-27 15:44:29 +00001070 MagickTrue,channel_features);
cristy9e818982014-01-18 14:54:37 +00001071 (void) PrintChannelFeatures(file,BlackPixelChannel,"Black",
dirk6c316f22015-06-27 15:44:29 +00001072 MagickFalse,channel_features);
cristy9e818982014-01-18 14:54:37 +00001073 break;
1074 }
1075 case GRAYColorspace:
1076 {
dirk6c316f22015-06-27 15:44:29 +00001077 (void) PrintChannelFeatures(file,GrayPixelChannel,"Gray",MagickFalse,
cristy9e818982014-01-18 14:54:37 +00001078 channel_features);
1079 break;
1080 }
1081 }
dirk6c316f22015-06-27 15:44:29 +00001082 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +00001083 channel_features=(ChannelFeatures *) RelinquishMagickMemory(
1084 channel_features);
1085 }
dirk6c316f22015-06-27 15:44:29 +00001086 if (image->colorspace == CMYKColorspace)
1087 (void) FormatLocaleFile(file," \"totalInkDensity\": \"%.*g%%\",\n",
cristye1c94d92015-06-28 12:16:33 +00001088 GetMagickPrecision(),100.0*GetImageTotalInkDensity(image,exception)/
1089 (double) QuantumRange);
dirk6c316f22015-06-27 15:44:29 +00001090 x=0;
1091 if (image->alpha_trait != UndefinedPixelTrait)
1092 {
1093 register const Quantum
1094 *p;
1095
1096 p=(const Quantum *) NULL;
1097 for (y=0; y < (ssize_t) image->rows; y++)
cristy9e818982014-01-18 14:54:37 +00001098 {
dirk6c316f22015-06-27 15:44:29 +00001099 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1100 if (p == (const Quantum *) NULL)
1101 break;
1102 for (x=0; x < (ssize_t) image->columns; x++)
cristy9e818982014-01-18 14:54:37 +00001103 {
dirk6c316f22015-06-27 15:44:29 +00001104 if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha)
cristy9e818982014-01-18 14:54:37 +00001105 break;
dirk6c316f22015-06-27 15:44:29 +00001106 p+=GetPixelChannels(image);
cristy9e818982014-01-18 14:54:37 +00001107 }
dirk6c316f22015-06-27 15:44:29 +00001108 if (x < (ssize_t) image->columns)
1109 break;
cristy9e818982014-01-18 14:54:37 +00001110 }
dirk6c316f22015-06-27 15:44:29 +00001111 if ((x < (ssize_t) image->columns) || (y < (ssize_t) image->rows))
1112 {
1113 PixelInfo
1114 pixel;
1115
1116 GetPixelInfo(image,&pixel);
1117 GetPixelInfoPixel(image,p,&pixel);
1118 GetColorTuple(&pixel,MagickTrue,color);
1119 (void) FormatLocaleFile(file," \"alpha\": \"%s\",\n",color);
1120 }
1121 }
cristy9e818982014-01-18 14:54:37 +00001122 if (image->storage_class == PseudoClass)
1123 {
dirk6c316f22015-06-27 15:44:29 +00001124 register PixelInfo
1125 *restrict p;
cristy9e818982014-01-18 14:54:37 +00001126
dirk6c316f22015-06-27 15:44:29 +00001127 (void) FormatLocaleFile(file," \"colormapEntries\": %.20g,\n",
1128 (double) image->colors);
1129 (void) FormatLocaleFile(file," \"colormap\": [\n ");
1130 p=image->colormap;
1131 for (i=0; i < (ssize_t) image->colors; i++)
1132 {
1133 GetColorTuple(p,MagickTrue,color);
1134 (void) FormatLocaleFile(file,"\"%s\"",color);
1135 if (i < (ssize_t) (image->colors-1))
1136 (void) FormatLocaleFile(file,",");
1137 if (((i+1) % 5) == 0)
1138 (void) FormatLocaleFile(file,"\n ");
1139 p++;
1140 }
1141 (void) FormatLocaleFile(file,"\n ],\n");
cristy9e818982014-01-18 14:54:37 +00001142 }
1143 if (image->error.mean_error_per_pixel != 0.0)
dirk6c316f22015-06-27 15:44:29 +00001144 (void) FormatLocaleFile(file," \"meanErrorPerPixel\": \"%g\",\n",
cristy9e818982014-01-18 14:54:37 +00001145 image->error.mean_error_per_pixel);
1146 if (image->error.normalized_mean_error != 0.0)
dirk6c316f22015-06-27 15:44:29 +00001147 (void) FormatLocaleFile(file," \"normalizedMeanError\": \"%g\",\n",
cristy9e818982014-01-18 14:54:37 +00001148 image->error.normalized_mean_error);
1149 if (image->error.normalized_maximum_error != 0.0)
dirk6c316f22015-06-27 15:44:29 +00001150 (void) FormatLocaleFile(file," \"normalizedMaximumError\": \"%g\",\n",
cristy9e818982014-01-18 14:54:37 +00001151 image->error.normalized_maximum_error);
dirk6c316f22015-06-27 15:44:29 +00001152 JsonFormatLocaleFile(file," \"renderingIntent\": %s,\n",
cristy9e818982014-01-18 14:54:37 +00001153 CommandOptionToMnemonic(MagickIntentOptions,(ssize_t)
1154 image->rendering_intent));
1155 if (image->gamma != 0.0)
dirk6c316f22015-06-27 15:44:29 +00001156 (void) FormatLocaleFile(file," \"gamma\": %g,\n",image->gamma);
cristy9e818982014-01-18 14:54:37 +00001157 if ((image->chromaticity.red_primary.x != 0.0) ||
1158 (image->chromaticity.green_primary.x != 0.0) ||
1159 (image->chromaticity.blue_primary.x != 0.0) ||
1160 (image->chromaticity.white_point.x != 0.0))
1161 {
1162 /*
1163 Display image chromaticity.
1164 */
dirk6c316f22015-06-27 15:44:29 +00001165 (void) FormatLocaleFile(file," \"chromaticity\": {\n");
1166 (void) FormatLocaleFile(file," \"redPrimary\": {\n"
1167 " \"x\": %g,\n \"y\": %g\n },\n",
cristy9e818982014-01-18 14:54:37 +00001168 image->chromaticity.red_primary.x,image->chromaticity.red_primary.y);
dirk6c316f22015-06-27 15:44:29 +00001169 (void) FormatLocaleFile(file," \"greenPrimary\": {\n"
1170 " \"x\": %g,\n \"y\": %g\n },\n",
cristy9e818982014-01-18 14:54:37 +00001171 image->chromaticity.green_primary.x,
1172 image->chromaticity.green_primary.y);
dirk6c316f22015-06-27 15:44:29 +00001173 (void) FormatLocaleFile(file," \"bluePrimary\": {\n"
1174 " \"x\": %g,\n \"y\": %g\n },\n",
cristy9e818982014-01-18 14:54:37 +00001175 image->chromaticity.blue_primary.x,image->chromaticity.blue_primary.y);
dirk6c316f22015-06-27 15:44:29 +00001176 (void) FormatLocaleFile(file," \"whitePrimary\": {\n"
1177 " \"x\": %g,\n \"y\": %g\n }\n",
cristy9e818982014-01-18 14:54:37 +00001178 image->chromaticity.white_point.x,image->chromaticity.white_point.y);
dirk6c316f22015-06-27 15:44:29 +00001179 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +00001180 }
1181 if ((image->extract_info.width*image->extract_info.height) != 0)
dirk6c316f22015-06-27 15:44:29 +00001182 (void) FormatLocaleFile(file," \"tileGeometry\": {\n"
1183 " \"width\": %.20g,\n \"height\": %.20g,\n"
1184 " \"x\": %.20g,\n \"y\": %.20g\n },\n",
cristy9e818982014-01-18 14:54:37 +00001185 (double) image->extract_info.width,(double) image->extract_info.height,
1186 (double) image->extract_info.x,(double) image->extract_info.y);
dirk6c316f22015-06-27 15:44:29 +00001187 GetColorTuple(&image->background_color,MagickTrue,color);
1188 (void) FormatLocaleFile(file," \"backgroundColor\": \"%s\",\n",color);
1189 GetColorTuple(&image->border_color,MagickTrue,color);
1190 (void) FormatLocaleFile(file," \"borderColor\": \"%s\",\n",color);
1191 GetColorTuple(&image->matte_color,MagickTrue,color);
1192 (void) FormatLocaleFile(file," \"matteColor\": \"%s\",\n",color);
1193 GetColorTuple(&image->transparent_color,MagickTrue,color);
1194 (void) FormatLocaleFile(file," \"transparentColor\": \"%s\",\n",color);
1195 JsonFormatLocaleFile(file," \"interlace\": %s,\n",CommandOptionToMnemonic(
cristy9e818982014-01-18 14:54:37 +00001196 MagickInterlaceOptions,(ssize_t) image->interlace));
dirk6c316f22015-06-27 15:44:29 +00001197 JsonFormatLocaleFile(file," \"intensity\": %s,\n",CommandOptionToMnemonic(
cristy9e818982014-01-18 14:54:37 +00001198 MagickPixelIntensityOptions,(ssize_t) image->intensity));
dirk6c316f22015-06-27 15:44:29 +00001199 JsonFormatLocaleFile(file," \"compose\": %s,\n",
1200 CommandOptionToMnemonic(MagickComposeOptions,(ssize_t) image->compose));
cristy9e818982014-01-18 14:54:37 +00001201 if ((image->page.width != 0) || (image->page.height != 0) ||
1202 (image->page.x != 0) || (image->page.y != 0))
dirk6c316f22015-06-27 15:44:29 +00001203 (void) FormatLocaleFile(file," \"pageGeometry\": {\n"
1204 " \"width\": %.20g,\n \"height\": %.20g,\n"
1205 " \"x\": %.20g,\n \"y\": %.20g\n },\n",
1206 (double) image->page.width,(double) image->page.height,
1207 (double) image->page.x,(double) image->page.y);
cristy9e818982014-01-18 14:54:37 +00001208 if ((image->page.x != 0) || (image->page.y != 0))
dirk6c316f22015-06-27 15:44:29 +00001209 (void) FormatLocaleFile(file," \"originGeometry\": %+.20g%+.20g\n",
1210 (double) image->page.x,(double) image->page.y);
1211 JsonFormatLocaleFile(file," \"dispose\": %s,\n",
1212 CommandOptionToMnemonic(MagickDisposeOptions,(ssize_t) image->dispose));
cristy9e818982014-01-18 14:54:37 +00001213 if (image->delay != 0)
dirk6c316f22015-06-27 15:44:29 +00001214 (void) FormatLocaleFile(file," \"delay\": \"%.20gx%.20g\"\n",
1215 (double) image->delay,(double) image->ticks_per_second);
cristy9e818982014-01-18 14:54:37 +00001216 if (image->iterations != 1)
dirk6c316f22015-06-27 15:44:29 +00001217 (void) FormatLocaleFile(file," \"iterations\": %.20g,\n",(double)
cristy9e818982014-01-18 14:54:37 +00001218 image->iterations);
1219 if ((image->next != (Image *) NULL) || (image->previous != (Image *) NULL))
dirk6c316f22015-06-27 15:44:29 +00001220 (void) FormatLocaleFile(file," \"scene\": %.20g\n \"scenes\": "
1221 "%.20g\n",(double) image->scene,(double) GetImageListLength(image));
cristy9e818982014-01-18 14:54:37 +00001222 else
1223 if (image->scene != 0)
dirk6c316f22015-06-27 15:44:29 +00001224 (void) FormatLocaleFile(file," \"scene\": %.20g,\n",(double)
1225 image->scene);
1226 JsonFormatLocaleFile(file," \"compression\": %s,\n",
1227 CommandOptionToMnemonic(MagickCompressOptions,(ssize_t)
1228 image->compression));
cristy9e818982014-01-18 14:54:37 +00001229 if (image->quality != UndefinedCompressionQuality)
dirk6c316f22015-06-27 15:44:29 +00001230 (void) FormatLocaleFile(file," \"quality\": %.20g,\n",(double)
1231 image->quality);
1232 JsonFormatLocaleFile(file," \"orientation\": %s,\n",
1233 CommandOptionToMnemonic(MagickOrientationOptions,(ssize_t)
1234 image->orientation));
cristy9e818982014-01-18 14:54:37 +00001235 if (image->montage != (char *) NULL)
dirk6c316f22015-06-27 15:44:29 +00001236 JsonFormatLocaleFile(file," \"montage\": \"%s\",\n",image->montage);
cristy9e818982014-01-18 14:54:37 +00001237 if (image->directory != (char *) NULL)
1238 {
1239 Image
1240 *tile;
1241
1242 ImageInfo
1243 *image_info;
1244
1245 register char
1246 *p,
1247 *q;
1248
1249 WarningHandler
1250 handler;
1251
1252 /*
1253 Display visual image directory.
1254 */
1255 image_info=AcquireImageInfo();
1256 (void) CloneString(&image_info->size,"64x64");
dirk6c316f22015-06-27 15:44:29 +00001257 (void) FormatLocaleFile(file," \"montageDirectory\": [");
1258 p=image->directory;
1259 while (*p != '\0')
cristy9e818982014-01-18 14:54:37 +00001260 {
1261 q=p;
1262 while ((*q != '\n') && (*q != '\0'))
1263 q++;
1264 (void) CopyMagickString(image_info->filename,p,(size_t) (q-p+1));
dirk6c316f22015-06-27 15:44:29 +00001265 p=q+1;
1266 JsonFormatLocaleFile(file,"{\n \"name\": %s",
1267 image_info->filename);
cristy9e818982014-01-18 14:54:37 +00001268 handler=SetWarningHandler((WarningHandler) NULL);
1269 tile=ReadImage(image_info,exception);
1270 (void) SetWarningHandler(handler);
1271 if (tile == (Image *) NULL)
1272 {
dirk6c316f22015-06-27 15:44:29 +00001273 (void) FormatLocaleFile(file," }");
cristy9e818982014-01-18 14:54:37 +00001274 continue;
1275 }
dirk6c316f22015-06-27 15:44:29 +00001276 (void) FormatLocaleFile(file,",\n \"info\": \"%.20gx%.20g %s\"",
1277 (double) tile->magick_columns,(double) tile->magick_rows,
1278 tile->magick);
cristy9e818982014-01-18 14:54:37 +00001279 (void) SignatureImage(tile,exception);
1280 ResetImagePropertyIterator(tile);
1281 property=GetNextImageProperty(tile);
1282 while (property != (const char *) NULL)
1283 {
dirk6c316f22015-06-27 15:44:29 +00001284 JsonFormatLocaleFile(file,",\n %s: ",property);
cristy9e818982014-01-18 14:54:37 +00001285 value=GetImageProperty(tile,property,exception);
dirk6c316f22015-06-27 15:44:29 +00001286 JsonFormatLocaleFile(file,"%s",value);
cristy9e818982014-01-18 14:54:37 +00001287 property=GetNextImageProperty(tile);
1288 }
1289 tile=DestroyImage(tile);
dirk6c316f22015-06-27 15:44:29 +00001290 if (*p != '\0')
1291 (void) FormatLocaleFile(file,"\n },");
1292 else
1293 (void) FormatLocaleFile(file,"\n }");
cristy9e818982014-01-18 14:54:37 +00001294 }
dirk6c316f22015-06-27 15:44:29 +00001295 (void) FormatLocaleFile(file,"],\n");
cristy9e818982014-01-18 14:54:37 +00001296 image_info=DestroyImageInfo(image_info);
1297 }
1298 (void) GetImageProperty(image,"exif:*",exception);
cristy55166322014-01-23 01:53:24 +00001299 (void) GetImageProperty(image,"icc:*",exception);
1300 (void) GetImageProperty(image,"iptc:*",exception);
1301 (void) GetImageProperty(image,"xmp:*",exception);
cristy9e818982014-01-18 14:54:37 +00001302 ResetImagePropertyIterator(image);
1303 property=GetNextImageProperty(image);
1304 if (property != (const char *) NULL)
1305 {
dirk6c316f22015-06-27 15:44:29 +00001306 size_t
1307 n;
1308
cristy9e818982014-01-18 14:54:37 +00001309 /*
1310 Display image properties.
1311 */
dirk6c316f22015-06-27 15:44:29 +00001312 n=0;
1313 (void) FormatLocaleFile(file," \"properties\": {\n");
cristy9e818982014-01-18 14:54:37 +00001314 while (property != (const char *) NULL)
1315 {
dirk6c316f22015-06-27 15:44:29 +00001316 if (n++ != 0)
1317 (void) FormatLocaleFile(file,",\n");
1318 JsonFormatLocaleFile(file," %s: ",property);
cristy9e818982014-01-18 14:54:37 +00001319 value=GetImageProperty(image,property,exception);
dirk6c316f22015-06-27 15:44:29 +00001320 JsonFormatLocaleFile(file,"%s",value);
cristy9e818982014-01-18 14:54:37 +00001321 property=GetNextImageProperty(image);
1322 }
dirk6c316f22015-06-27 15:44:29 +00001323 (void) FormatLocaleFile(file,"\n },\n");
cristy9e818982014-01-18 14:54:37 +00001324 }
cristy151b66d2015-04-15 10:50:31 +00001325 (void) FormatLocaleString(key,MagickPathExtent,"8BIM:1999,2998:#1");
cristy9e818982014-01-18 14:54:37 +00001326 value=GetImageProperty(image,key,exception);
1327 if (value != (const char *) NULL)
1328 {
1329 /*
1330 Display clipping path.
1331 */
dirk6c316f22015-06-27 15:44:29 +00001332 (void) FormatLocaleFile(file," \"clipping path\": {\n");
1333 JsonFormatLocaleFile(file,"%s\n",value);
1334 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +00001335 }
1336 ResetImageProfileIterator(image);
1337 name=GetNextImageProfile(image);
1338 if (name != (char *) NULL)
1339 {
1340 const StringInfo
1341 *profile;
1342
dirk6c316f22015-06-27 15:44:29 +00001343 size_t
1344 n;
1345
cristy9e818982014-01-18 14:54:37 +00001346 /*
1347 Identify image profiles.
1348 */
dirk6c316f22015-06-27 15:44:29 +00001349 n=0;
1350 (void) FormatLocaleFile(file," \"profiles\": {\n");
cristy9e818982014-01-18 14:54:37 +00001351 while (name != (char *) NULL)
1352 {
1353 profile=GetImageProfile(image,name);
1354 if (profile == (StringInfo *) NULL)
1355 continue;
dirk6c316f22015-06-27 15:44:29 +00001356 if (n++ != 0)
1357 (void) FormatLocaleFile(file,",\n");
1358 JsonFormatLocaleFile(file," %s: {\n",name);
cristy9e818982014-01-18 14:54:37 +00001359 if (LocaleCompare(name,"iptc") == 0)
1360 {
1361 char
1362 *attribute,
1363 **attribute_list;
1364
1365 const char
1366 *tag;
1367
1368 long
1369 dataset,
1370 record,
1371 sentinel;
1372
1373 register ssize_t
1374 j;
1375
1376 size_t
1377 length,
1378 profile_length;
1379
1380 profile_length=GetStringInfoLength(profile);
1381 for (i=0; i < (ssize_t) profile_length; i+=(ssize_t) length)
1382 {
1383 length=1;
1384 sentinel=GetStringInfoDatum(profile)[i++];
1385 if (sentinel != 0x1c)
1386 continue;
1387 dataset=GetStringInfoDatum(profile)[i++];
1388 record=GetStringInfoDatum(profile)[i++];
1389 switch (record)
1390 {
1391 case 5: tag="Image Name"; break;
1392 case 7: tag="Edit Status"; break;
1393 case 10: tag="Priority"; break;
1394 case 15: tag="Category"; break;
1395 case 20: tag="Supplemental Category"; break;
1396 case 22: tag="Fixture Identifier"; break;
1397 case 25: tag="Keyword"; break;
1398 case 30: tag="Release Date"; break;
1399 case 35: tag="Release Time"; break;
1400 case 40: tag="Special Instructions"; break;
1401 case 45: tag="Reference Service"; break;
1402 case 47: tag="Reference Date"; break;
1403 case 50: tag="Reference Number"; break;
1404 case 55: tag="Created Date"; break;
1405 case 60: tag="Created Time"; break;
1406 case 65: tag="Originating Program"; break;
1407 case 70: tag="Program Version"; break;
1408 case 75: tag="Object Cycle"; break;
1409 case 80: tag="Byline"; break;
1410 case 85: tag="Byline Title"; break;
1411 case 90: tag="City"; break;
cristya0b0ad32015-07-02 12:33:54 +00001412 case 92: tag="Sub-Location"; break;
cristy9e818982014-01-18 14:54:37 +00001413 case 95: tag="Province State"; break;
1414 case 100: tag="Country Code"; break;
1415 case 101: tag="Country"; break;
1416 case 103: tag="Original Transmission Reference"; break;
1417 case 105: tag="Headline"; break;
1418 case 110: tag="Credit"; break;
1419 case 115: tag="Src"; break;
1420 case 116: tag="Copyright String"; break;
1421 case 120: tag="Caption"; break;
1422 case 121: tag="Local Caption"; break;
1423 case 122: tag="Caption Writer"; break;
1424 case 200: tag="Custom Field 1"; break;
1425 case 201: tag="Custom Field 2"; break;
1426 case 202: tag="Custom Field 3"; break;
1427 case 203: tag="Custom Field 4"; break;
1428 case 204: tag="Custom Field 5"; break;
1429 case 205: tag="Custom Field 6"; break;
1430 case 206: tag="Custom Field 7"; break;
1431 case 207: tag="Custom Field 8"; break;
1432 case 208: tag="Custom Field 9"; break;
1433 case 209: tag="Custom Field 10"; break;
1434 case 210: tag="Custom Field 11"; break;
1435 case 211: tag="Custom Field 12"; break;
1436 case 212: tag="Custom Field 13"; break;
1437 case 213: tag="Custom Field 14"; break;
1438 case 214: tag="Custom Field 15"; break;
1439 case 215: tag="Custom Field 16"; break;
1440 case 216: tag="Custom Field 17"; break;
1441 case 217: tag="Custom Field 18"; break;
1442 case 218: tag="Custom Field 19"; break;
1443 case 219: tag="Custom Field 20"; break;
1444 default: tag="unknown"; break;
1445 }
1446 (void) FormatLocaleFile(file," %s[%.20g,%.20g]: ",tag,
1447 (double) dataset,(double) record);
1448 length=(size_t) (GetStringInfoDatum(profile)[i++] << 8);
1449 length|=GetStringInfoDatum(profile)[i++];
1450 attribute=(char *) NULL;
cristy151b66d2015-04-15 10:50:31 +00001451 if (~length >= (MagickPathExtent-1))
1452 attribute=(char *) AcquireQuantumMemory(length+MagickPathExtent,
cristy9e818982014-01-18 14:54:37 +00001453 sizeof(*attribute));
1454 if (attribute != (char *) NULL)
1455 {
1456 (void) CopyMagickString(attribute,(char *)
1457 GetStringInfoDatum(profile)+i,length+1);
1458 attribute_list=StringToList(attribute);
1459 if (attribute_list != (char **) NULL)
1460 {
dirk6c316f22015-06-27 15:44:29 +00001461 (void) FormatLocaleFile(file,"[");
cristy9e818982014-01-18 14:54:37 +00001462 for (j=0; attribute_list[j] != (char *) NULL; j++)
1463 {
dirk6c316f22015-06-27 15:44:29 +00001464 if (j != 0)
1465 (void) FormatLocaleFile(file,",");
1466 JsonFormatLocaleFile(file,"%s",attribute_list[j]);
cristy9e818982014-01-18 14:54:37 +00001467 attribute_list[j]=(char *) RelinquishMagickMemory(
1468 attribute_list[j]);
1469 }
dirk6c316f22015-06-27 15:44:29 +00001470 (void) FormatLocaleFile(file,"],");
cristy9e818982014-01-18 14:54:37 +00001471 attribute_list=(char **) RelinquishMagickMemory(
1472 attribute_list);
1473 }
dirk6c316f22015-06-27 15:44:29 +00001474 else
1475 (void) FormatLocaleFile(file,"null,");
cristy9e818982014-01-18 14:54:37 +00001476 attribute=DestroyString(attribute);
1477 }
dirk6c316f22015-06-27 15:44:29 +00001478 else
1479 (void) FormatLocaleFile(file,"null,");
cristy9e818982014-01-18 14:54:37 +00001480 }
1481 }
dirk6c316f22015-06-27 15:44:29 +00001482 (void) FormatLocaleFile(file," \"length\": \"%.20g\"",(double)
1483 GetStringInfoLength(profile));
1484 (void) FormatLocaleFile(file,"\n }");
cristy9e818982014-01-18 14:54:37 +00001485 name=GetNextImageProfile(image);
1486 }
dirk6c316f22015-06-27 15:44:29 +00001487 (void) FormatLocaleFile(file,"\n },\n");
cristy9e818982014-01-18 14:54:37 +00001488 }
1489 ResetImageArtifactIterator(image);
1490 artifact=GetNextImageArtifact(image);
1491 if (artifact != (const char *) NULL)
1492 {
dirk6c316f22015-06-27 15:44:29 +00001493 ssize_t
1494 n;
1495
cristy9e818982014-01-18 14:54:37 +00001496 /*
1497 Display image artifacts.
1498 */
dirk6c316f22015-06-27 15:44:29 +00001499 n=0;
1500 (void) FormatLocaleFile(file," \"artifacts\": {\n");
cristy9e818982014-01-18 14:54:37 +00001501 while (artifact != (const char *) NULL)
1502 {
dirk6c316f22015-06-27 15:44:29 +00001503 if (n++ != 0)
1504 (void) FormatLocaleFile(file,",\n");
1505 JsonFormatLocaleFile(file," %s: ",artifact);
cristy9e818982014-01-18 14:54:37 +00001506 value=GetImageArtifact(image,artifact);
dirk6c316f22015-06-27 15:44:29 +00001507 JsonFormatLocaleFile(file,"%s",value);
cristy9e818982014-01-18 14:54:37 +00001508 artifact=GetNextImageArtifact(image);
1509 }
dirk6c316f22015-06-27 15:44:29 +00001510 (void) FormatLocaleFile(file,"\n },\n");
cristy9e818982014-01-18 14:54:37 +00001511 }
1512 ResetImageRegistryIterator();
1513 registry=GetNextImageRegistry();
1514 if (registry != (const char *) NULL)
1515 {
dirk6c316f22015-06-27 15:44:29 +00001516 ssize_t
1517 n;
1518
cristy9e818982014-01-18 14:54:37 +00001519 /*
1520 Display image registry.
1521 */
dirk6c316f22015-06-27 15:44:29 +00001522 (void) FormatLocaleFile(file," \"registry\": {\n");
1523 n=0;
cristy9e818982014-01-18 14:54:37 +00001524 while (registry != (const char *) NULL)
1525 {
dirk6c316f22015-06-27 15:44:29 +00001526 if (n++ != 0)
1527 (void) FormatLocaleFile(file,",\n");
1528 JsonFormatLocaleFile(file," %s: ",registry);
cristy9e818982014-01-18 14:54:37 +00001529 value=(const char *) GetImageRegistry(StringRegistryType,registry,
1530 exception);
dirk6c316f22015-06-27 15:44:29 +00001531 JsonFormatLocaleFile(file,"%s",value);
cristy9e818982014-01-18 14:54:37 +00001532 registry=GetNextImageRegistry();
1533 }
dirk6c316f22015-06-27 15:44:29 +00001534 (void) FormatLocaleFile(file," },\n");
cristy9e818982014-01-18 14:54:37 +00001535 }
dirk6c316f22015-06-27 15:44:29 +00001536 (void) FormatLocaleFile(file," \"tainted\": %s,\n",
1537 image->taint != MagickFalse ? "true" : "false");
cristy151b66d2015-04-15 10:50:31 +00001538 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B",MagickPathExtent,
cristyd4618c02015-04-14 23:54:43 +00001539 format);
dirk6c316f22015-06-27 15:44:29 +00001540 JsonFormatLocaleFile(file," \"filesize\": %s,\n",format);
cristy9e818982014-01-18 14:54:37 +00001541 (void) FormatMagickSize((MagickSizeType) image->columns*image->rows,
cristy151b66d2015-04-15 10:50:31 +00001542 MagickFalse,"B",MagickPathExtent,format);
cristy9e818982014-01-18 14:54:37 +00001543 if (strlen(format) > 1)
1544 format[strlen(format)-1]='\0';
dirk6c316f22015-06-27 15:44:29 +00001545 JsonFormatLocaleFile(file," \"numberPixels\": %s,\n",format);
cristy9e818982014-01-18 14:54:37 +00001546 (void) FormatMagickSize((MagickSizeType) ((double) image->columns*image->rows/
cristy151b66d2015-04-15 10:50:31 +00001547 elapsed_time+0.5),MagickFalse,"B",MagickPathExtent,format);
dirk6c316f22015-06-27 15:44:29 +00001548 JsonFormatLocaleFile(file," \"pixelsPerSecond\": %s,\n",format);
1549 (void) FormatLocaleFile(file," \"userTime\": \"%0.3fu\",\n",user_time);
1550 (void) FormatLocaleFile(file," \"elapsedTime\": \"%lu:%02lu.%03lu\",\n",
1551 (unsigned long) (elapsed_time/60.0),(unsigned long) ceil(fmod(
1552 elapsed_time,60.0)),(unsigned long) (1000.0*(elapsed_time-floor(
1553 elapsed_time))));
1554 JsonFormatLocaleFile(file," \"version\": %s\n",
1555 GetMagickVersion((size_t *) NULL));
1556 (void) FormatLocaleFile(file," }\n}\n");
cristy9e818982014-01-18 14:54:37 +00001557 (void) fflush(file);
1558 return(ferror(file) != 0 ? MagickFalse : MagickTrue);
1559}
1560
cristy3f07aa32014-01-18 01:16:33 +00001561static MagickBooleanType WriteJSONImage(const ImageInfo *image_info,
1562 Image *image,ExceptionInfo *exception)
1563{
dirk6c316f22015-06-27 15:44:29 +00001564 FILE
1565 *file;
1566
cristy3f07aa32014-01-18 01:16:33 +00001567 MagickBooleanType
1568 status;
1569
1570 MagickOffsetType
1571 scene;
1572
1573 /*
1574 Open output image file.
1575 */
1576 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001577 assert(image_info->signature == MagickCoreSignature);
cristy3f07aa32014-01-18 01:16:33 +00001578 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001579 assert(image->signature == MagickCoreSignature);
cristy3f07aa32014-01-18 01:16:33 +00001580 if (image->debug != MagickFalse)
1581 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1582 status=OpenBlob(image_info,image,WriteBlobMode,exception);
1583 if (status == MagickFalse)
1584 return(status);
dirk6c316f22015-06-27 15:44:29 +00001585 file=GetBlobFileHandle(image);
1586 if (file == (FILE *) NULL)
1587 file=stdout;
cristy3f07aa32014-01-18 01:16:33 +00001588 scene=0;
1589 do
1590 {
dirk6c316f22015-06-27 15:44:29 +00001591 WriteBlobString(image,"[");
cristy9e818982014-01-18 14:54:37 +00001592 image->magick_columns=image->columns;
1593 image->magick_rows=image->rows;
dirk6c316f22015-06-27 15:44:29 +00001594 EncodeImageAttributes(image,file,exception);
cristy3f07aa32014-01-18 01:16:33 +00001595 if (GetNextImageInList(image) == (Image *) NULL)
dirk6c316f22015-06-27 15:44:29 +00001596 {
1597 WriteBlobString(image,"]");
1598 break;
1599 }
1600 WriteBlobString(image,",\n");
cristy3f07aa32014-01-18 01:16:33 +00001601 image=SyncNextImageInList(image);
1602 status=SetImageProgress(image,SaveImagesTag,scene++,
1603 GetImageListLength(image));
1604 if (status == MagickFalse)
1605 break;
1606 } while (image_info->adjoin != MagickFalse);
1607 (void) CloseBlob(image);
1608 return(MagickTrue);
1609}