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