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