/src/graphicsmagick/magick/describe.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2003 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % SPDX-License-Identifier: MIT |
6 | | % |
7 | | % This program is covered by multiple licenses, which are described in |
8 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
9 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
10 | | % |
11 | | % GraphicsMagick Describe Methods. |
12 | | % |
13 | | */ |
14 | | |
15 | | /* |
16 | | Include declarations. |
17 | | */ |
18 | | #include "magick/studio.h" |
19 | | #include "magick/analyze.h" |
20 | | #include "magick/attribute.h" |
21 | | #include "magick/blob.h" |
22 | | #include "magick/channel.h" |
23 | | #include "magick/color.h" |
24 | | #include "magick/color_lookup.h" |
25 | | #include "magick/constitute.h" |
26 | | #include "magick/describe.h" |
27 | | #include "magick/enum_strings.h" |
28 | | #include "magick/magick.h" |
29 | | #include "magick/pixel_cache.h" |
30 | | #include "magick/profile.h" |
31 | | #include "magick/signature.h" |
32 | | #include "magick/statistics.h" |
33 | | #include "magick/utility.h" |
34 | | |
35 | | /* |
36 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
37 | | % % |
38 | | % % |
39 | | % % |
40 | | % D e s c r i b e I m a g e % |
41 | | % % |
42 | | % % |
43 | | % % |
44 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
45 | | % |
46 | | % DescribeImage() describes an image by printing its attributes to the file. |
47 | | % Attributes include the image width, height, size, and others. |
48 | | % |
49 | | % The format of the DescribeImage method is: |
50 | | % |
51 | | % void DescribeImage(Image *image,FILE *file,const MagickBool verbose) |
52 | | % |
53 | | % A description of each parameter follows: |
54 | | % |
55 | | % o image: The image. |
56 | | % |
57 | | % o file: The file, typically stdout. |
58 | | % |
59 | | % o verbose: A value other than zero prints more detailed information |
60 | | % about the image. Values greater than one enable counting the number of |
61 | | % colors in the image. |
62 | | % |
63 | | % |
64 | | */ |
65 | | MagickExport MagickPassFail DescribeImage(Image *image,FILE *file, |
66 | | const MagickBool verbose) |
67 | 0 | { |
68 | 0 | char |
69 | 0 | color[MaxTextExtent], |
70 | 0 | format[MaxTextExtent]; |
71 | |
|
72 | 0 | const unsigned char |
73 | 0 | *profile; |
74 | |
|
75 | 0 | size_t |
76 | 0 | profile_length; |
77 | |
|
78 | 0 | const ImageAttribute |
79 | 0 | *attribute; |
80 | |
|
81 | 0 | const MagickInfo |
82 | 0 | *magick_info; |
83 | |
|
84 | 0 | double |
85 | 0 | elapsed_time, |
86 | 0 | user_time; |
87 | |
|
88 | 0 | unsigned long |
89 | 0 | columns, |
90 | 0 | rows; |
91 | |
|
92 | 0 | magick_int64_t |
93 | 0 | pixels_per_second; |
94 | |
|
95 | 0 | Image |
96 | 0 | *p; |
97 | |
|
98 | 0 | unsigned long |
99 | 0 | y; |
100 | |
|
101 | 0 | register size_t |
102 | 0 | i; |
103 | |
|
104 | 0 | register unsigned long |
105 | 0 | x; |
106 | |
|
107 | 0 | unsigned long |
108 | 0 | count; |
109 | |
|
110 | 0 | assert(image != (Image *) NULL); |
111 | 0 | assert(image->signature == MagickSignature); |
112 | 0 | assert(file != (FILE *) NULL); |
113 | 0 | elapsed_time=GetElapsedTime(&image->timer); |
114 | 0 | user_time=GetUserTime(&image->timer); |
115 | 0 | GetTimerInfo(&image->timer); |
116 | 0 | if (!verbose) |
117 | 0 | { |
118 | | /* |
119 | | Display summary info about the image. |
120 | | */ |
121 | 0 | if (*image->magick_filename != '\0') |
122 | 0 | if (LocaleCompare(image->magick_filename,image->filename) != 0) |
123 | 0 | (void) fprintf(file,"%.1024s=>",image->magick_filename); |
124 | 0 | if ((image->previous == (Image *) NULL) && |
125 | 0 | (image->next == (Image *) NULL) && (image->scene == 0)) |
126 | 0 | (void) fprintf(file,"%.1024s ",image->filename); |
127 | 0 | else |
128 | 0 | (void) fprintf(file,"%.1024s[%lu] ",image->filename,image->scene); |
129 | 0 | (void) fprintf(file,"%.1024s ",image->magick); |
130 | 0 | columns=image->columns; |
131 | 0 | rows=image->rows; |
132 | 0 | if ((image->magick_columns != 0) || (image->magick_rows != 0)) |
133 | 0 | if ((image->magick_columns != image->columns) || |
134 | 0 | (image->magick_rows != image->rows)) |
135 | 0 | { |
136 | 0 | columns=image->magick_columns; |
137 | 0 | rows=image->magick_rows; |
138 | 0 | (void) fprintf(file,"%lux%lu=>",image->magick_columns, |
139 | 0 | image->magick_rows); |
140 | 0 | } |
141 | 0 | (void) fprintf(file,"%lux%lu%+ld%+ld ",image->columns,image->rows, |
142 | 0 | image->page.x,image->page.y); |
143 | 0 | if (image->storage_class == DirectClass) |
144 | 0 | { |
145 | 0 | (void) fprintf(file,"DirectClass "); |
146 | 0 | if (image->total_colors != 0) |
147 | 0 | { |
148 | 0 | FormatSize(image->total_colors,format); |
149 | 0 | (void) fprintf(file,"%.1024s ",format); |
150 | 0 | } |
151 | 0 | } |
152 | 0 | else |
153 | 0 | if (image->total_colors <= image->colors) |
154 | 0 | (void) fprintf(file,"PseudoClass %uc ",image->colors); |
155 | 0 | else |
156 | 0 | { |
157 | 0 | (void) fprintf(file,"PseudoClass %lu=>%uc ",image->total_colors, |
158 | 0 | image->colors); |
159 | 0 | (void) fprintf(file,"%ld/%.6f/%.6fe ", |
160 | 0 | (long) image->error.mean_error_per_pixel, |
161 | 0 | image->error.normalized_mean_error, |
162 | 0 | image->error.normalized_maximum_error); |
163 | 0 | } |
164 | 0 | if(image->matte==MagickTrue) |
165 | 0 | (void) fputs("+opacity ",file); |
166 | 0 | (void) fprintf(file,"%u-bit ",image->depth); |
167 | 0 | if (GetBlobSize(image) != 0) |
168 | 0 | { |
169 | 0 | FormatSize(GetBlobSize(image),format); |
170 | 0 | (void) fprintf(file,"%.1024s ",format); |
171 | 0 | } |
172 | 0 | (void) fprintf(file,"%0.3fu %ldm:%.6fs", |
173 | 0 | user_time, |
174 | 0 | (long) (elapsed_time/60.0), |
175 | 0 | fmod(elapsed_time,60.0)); |
176 | | /* |
177 | | Only display pixel read rate if the time accumulated is at |
178 | | least six times the timer's resolution (typically 0.01 on |
179 | | Unix). |
180 | | */ |
181 | 0 | if (!(image->ping) && (elapsed_time > 0.001) && |
182 | 0 | (elapsed_time >= GetTimerResolution()*6)) |
183 | 0 | { |
184 | 0 | pixels_per_second=(magick_int64_t) ((double) rows*columns/ |
185 | 0 | elapsed_time); |
186 | 0 | FormatSize(pixels_per_second,format); |
187 | 0 | (void) fprintf(file," (%s pixels/s)",format); |
188 | 0 | } |
189 | 0 | (void) fprintf(file,"\n"); |
190 | |
|
191 | 0 | return (ferror(file) ? MagickFail : MagickPass); |
192 | 0 | } |
193 | | /* |
194 | | Display verbose info about the image. |
195 | | */ |
196 | 0 | (void) SignatureImage(image); |
197 | 0 | if (verbose > 1) |
198 | 0 | image->total_colors=GetNumberColors(image,(FILE *) NULL,&image->exception); |
199 | 0 | (void) fprintf(file,"Image: %.1024s\n",image->filename); |
200 | 0 | magick_info=GetMagickInfo(image->magick,&image->exception); |
201 | 0 | if ((magick_info == (const MagickInfo *) NULL) || |
202 | 0 | (*magick_info->description == '\0')) |
203 | 0 | (void) fprintf(file," Format: %.1024s\n",image->magick); |
204 | 0 | else |
205 | 0 | (void) fprintf(file," Format: %.1024s (%.1024s)\n",image->magick, |
206 | 0 | magick_info->description); |
207 | 0 | (void) fprintf(file," Geometry: %lux%lu\n",image->columns,image->rows); |
208 | 0 | if (image->storage_class == DirectClass) |
209 | 0 | (void) fprintf(file," Class: DirectClass\n"); |
210 | 0 | else |
211 | 0 | (void) fprintf(file," Class: PseudoClass\n"); |
212 | 0 | if ((image->magick_columns != 0) || (image->magick_rows != 0)) |
213 | 0 | if ((image->magick_columns != image->columns) || |
214 | 0 | (image->magick_rows != image->rows)) |
215 | 0 | (void) fprintf(file," Base geometry: %lux%lu\n",image->magick_columns, |
216 | 0 | image->magick_rows); |
217 | 0 | (void) fprintf(file," Type: "); |
218 | 0 | switch (GetImageType(image,&image->exception)) |
219 | 0 | { |
220 | 0 | case BilevelType: (void) fprintf(file,"bilevel"); break; |
221 | 0 | case GrayscaleType: (void) fprintf(file,"grayscale"); break; |
222 | 0 | case GrayscaleMatteType: |
223 | 0 | (void) fprintf(file,"grayscale with transparency"); break; |
224 | 0 | case PaletteType: (void) fprintf(file,"palette"); break; |
225 | 0 | case PaletteMatteType: |
226 | 0 | (void) fprintf(file,"palette with transparency"); break; |
227 | 0 | case TrueColorType: (void) fprintf(file,"true color"); break; |
228 | 0 | case TrueColorMatteType: |
229 | 0 | (void) fprintf(file,"true color with transparency"); break; |
230 | 0 | case ColorSeparationType: (void) fprintf(file,"color separated"); break; |
231 | 0 | case ColorSeparationMatteType: |
232 | 0 | (void) fprintf(file,"color separated with transparency"); break; |
233 | 0 | default: (void) fprintf(file,"undefined"); break; |
234 | 0 | } |
235 | 0 | (void) fprintf(file,"\n"); |
236 | 0 | (void) fprintf(file," Depth: %lu bits-per-pixel component\n", |
237 | 0 | GetImageDepth(image,&image->exception)); |
238 | 0 | (void) fprintf(file," Channel Depths:\n"); |
239 | 0 | if (image->colorspace == CMYKColorspace) |
240 | 0 | { |
241 | 0 | (void) fprintf(file," Cyan: %u bits\n", |
242 | 0 | GetImageChannelDepth(image,CyanChannel, |
243 | 0 | &image->exception)); |
244 | 0 | (void) fprintf(file," Magenta: %u bits\n", |
245 | 0 | GetImageChannelDepth(image,MagentaChannel, |
246 | 0 | &image->exception)); |
247 | 0 | (void) fprintf(file," Yellow: %u bits\n", |
248 | 0 | GetImageChannelDepth(image,YellowChannel, |
249 | 0 | &image->exception)); |
250 | 0 | (void) fprintf(file," Black: %u bits\n", |
251 | 0 | GetImageChannelDepth(image,BlackChannel, |
252 | 0 | &image->exception)); |
253 | 0 | } |
254 | 0 | else if ((IsGrayColorspace(image->colorspace)) || |
255 | 0 | (image->is_grayscale == True)) |
256 | 0 | { |
257 | 0 | (void) fprintf(file," Gray: %u bits\n", |
258 | 0 | GetImageChannelDepth(image,RedChannel, |
259 | 0 | &image->exception)); |
260 | 0 | } |
261 | 0 | else |
262 | 0 | { |
263 | 0 | (void) fprintf(file," Red: %u bits\n", |
264 | 0 | GetImageChannelDepth(image,RedChannel, |
265 | 0 | &image->exception)); |
266 | 0 | (void) fprintf(file," Green: %u bits\n", |
267 | 0 | GetImageChannelDepth(image,GreenChannel, |
268 | 0 | &image->exception)); |
269 | 0 | (void) fprintf(file," Blue: %u bits\n", |
270 | 0 | GetImageChannelDepth(image,BlueChannel, |
271 | 0 | &image->exception)); |
272 | 0 | } |
273 | 0 | if (image->matte) |
274 | 0 | (void) fprintf(file," Opacity: %u bits\n", |
275 | 0 | GetImageChannelDepth(image,OpacityChannel, |
276 | 0 | &image->exception)); |
277 | 0 | (void) fprintf(file," Channel Statistics:\n"); |
278 | 0 | { |
279 | 0 | ImageStatistics |
280 | 0 | statistics; |
281 | |
|
282 | 0 | (void) GetImageStatistics(image,&statistics,&image->exception); |
283 | |
|
284 | 0 | if (image->colorspace == CMYKColorspace) |
285 | 0 | { |
286 | 0 | (void) fprintf(file," Cyan:\n"); |
287 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
288 | 0 | MaxRGB*statistics.red.minimum, |
289 | 0 | statistics.red.minimum); |
290 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
291 | 0 | MaxRGB*statistics.red.maximum, |
292 | 0 | statistics.red.maximum); |
293 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
294 | 0 | MaxRGB*statistics.red.mean, |
295 | 0 | statistics.red.mean); |
296 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
297 | 0 | MaxRGB*statistics.red.standard_deviation, |
298 | 0 | statistics.red.standard_deviation); |
299 | 0 | (void) fprintf(file," Magenta:\n"); |
300 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
301 | 0 | MaxRGB*statistics.green.minimum, |
302 | 0 | statistics.green.minimum); |
303 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
304 | 0 | MaxRGB*statistics.green.maximum, |
305 | 0 | statistics.green.maximum); |
306 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
307 | 0 | MaxRGB*statistics.green.mean, |
308 | 0 | statistics.green.mean); |
309 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
310 | 0 | MaxRGB*statistics.green.standard_deviation, |
311 | 0 | statistics.green.standard_deviation); |
312 | 0 | (void) fprintf(file," Yellow:\n"); |
313 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
314 | 0 | MaxRGB*statistics.blue.minimum, |
315 | 0 | statistics.blue.minimum); |
316 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
317 | 0 | MaxRGB*statistics.blue.maximum, |
318 | 0 | statistics.blue.maximum); |
319 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
320 | 0 | MaxRGB*statistics.blue.mean, |
321 | 0 | statistics.blue.mean); |
322 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
323 | 0 | MaxRGB*statistics.blue.standard_deviation, |
324 | 0 | statistics.blue.standard_deviation); |
325 | 0 | (void) fprintf(file," Black:\n"); |
326 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
327 | 0 | MaxRGB*statistics.opacity.minimum, |
328 | 0 | statistics.opacity.minimum); |
329 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
330 | 0 | MaxRGB*statistics.opacity.maximum, |
331 | 0 | statistics.opacity.maximum); |
332 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
333 | 0 | MaxRGB*statistics.opacity.mean, |
334 | 0 | statistics.opacity.mean); |
335 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
336 | 0 | MaxRGB*statistics.opacity.standard_deviation, |
337 | 0 | statistics.opacity.standard_deviation); |
338 | | /* |
339 | | if (image->matte) |
340 | | (void) fprintf(file," Opacity:\n"); |
341 | | */ |
342 | 0 | } |
343 | 0 | else if ((IsGrayColorspace(image->colorspace)) || |
344 | 0 | (image->is_grayscale == MagickTrue)) |
345 | 0 | { |
346 | 0 | (void) fprintf(file," Gray:\n"); |
347 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
348 | 0 | MaxRGB*statistics.red.minimum, |
349 | 0 | statistics.red.minimum); |
350 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
351 | 0 | MaxRGB*statistics.red.maximum, |
352 | 0 | statistics.red.maximum); |
353 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
354 | 0 | MaxRGB*statistics.red.mean, |
355 | 0 | statistics.red.mean); |
356 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
357 | 0 | MaxRGB*statistics.red.standard_deviation, |
358 | 0 | statistics.red.standard_deviation); |
359 | 0 | if (image->matte) |
360 | 0 | { |
361 | 0 | (void) fprintf(file," Opacity:\n"); |
362 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
363 | 0 | MaxRGB*statistics.opacity.minimum, |
364 | 0 | statistics.opacity.minimum); |
365 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
366 | 0 | MaxRGB*statistics.opacity.maximum, |
367 | 0 | statistics.opacity.maximum); |
368 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
369 | 0 | MaxRGB*statistics.opacity.mean, |
370 | 0 | statistics.opacity.mean); |
371 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
372 | 0 | MaxRGB*statistics.opacity.standard_deviation, |
373 | 0 | statistics.opacity.standard_deviation); |
374 | 0 | } |
375 | 0 | } |
376 | 0 | else |
377 | 0 | { |
378 | 0 | (void) fprintf(file," Red:\n"); |
379 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
380 | 0 | MaxRGB*statistics.red.minimum, |
381 | 0 | statistics.red.minimum); |
382 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
383 | 0 | MaxRGB*statistics.red.maximum, |
384 | 0 | statistics.red.maximum); |
385 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
386 | 0 | MaxRGB*statistics.red.mean, |
387 | 0 | statistics.red.mean); |
388 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
389 | 0 | MaxRGB*statistics.red.standard_deviation, |
390 | 0 | statistics.red.standard_deviation); |
391 | 0 | (void) fprintf(file," Green:\n"); |
392 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
393 | 0 | MaxRGB*statistics.green.minimum, |
394 | 0 | statistics.green.minimum); |
395 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
396 | 0 | MaxRGB*statistics.green.maximum, |
397 | 0 | statistics.green.maximum); |
398 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
399 | 0 | MaxRGB*statistics.green.mean, |
400 | 0 | statistics.green.mean); |
401 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
402 | 0 | MaxRGB*statistics.green.standard_deviation, |
403 | 0 | statistics.green.standard_deviation); |
404 | 0 | (void) fprintf(file," Blue:\n"); |
405 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
406 | 0 | MaxRGB*statistics.blue.minimum, |
407 | 0 | statistics.blue.minimum); |
408 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
409 | 0 | MaxRGB*statistics.blue.maximum, |
410 | 0 | statistics.blue.maximum); |
411 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
412 | 0 | MaxRGB*statistics.blue.mean, |
413 | 0 | statistics.blue.mean); |
414 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
415 | 0 | MaxRGB*statistics.blue.standard_deviation, |
416 | 0 | statistics.blue.standard_deviation); |
417 | 0 | if (image->matte) |
418 | 0 | { |
419 | 0 | (void) fprintf(file," Opacity:\n"); |
420 | 0 | (void) fprintf(file," Minimum: %13.02lf (%1.4f)\n", |
421 | 0 | MaxRGB*statistics.opacity.minimum, |
422 | 0 | statistics.opacity.minimum); |
423 | 0 | (void) fprintf(file," Maximum: %13.02lf (%1.4f)\n", |
424 | 0 | MaxRGB*statistics.opacity.maximum, |
425 | 0 | statistics.opacity.maximum); |
426 | 0 | (void) fprintf(file," Mean: %13.02lf (%1.4f)\n", |
427 | 0 | MaxRGB*statistics.opacity.mean, |
428 | 0 | statistics.opacity.mean); |
429 | 0 | (void) fprintf(file," Standard Deviation: %13.02lf (%1.4f)\n", |
430 | 0 | MaxRGB*statistics.opacity.standard_deviation, |
431 | 0 | statistics.opacity.standard_deviation); |
432 | 0 | } |
433 | 0 | } |
434 | 0 | } |
435 | 0 | x=0; |
436 | 0 | p=(Image *) NULL; |
437 | 0 | if ((image->matte && (strcmp(image->magick,"GIF") != 0)) || image->taint) |
438 | 0 | { |
439 | 0 | char |
440 | 0 | tuple[MaxTextExtent]; |
441 | |
|
442 | 0 | MagickBool |
443 | 0 | found_transparency; |
444 | |
|
445 | 0 | register const PixelPacket |
446 | 0 | *p; |
447 | |
|
448 | 0 | p=(PixelPacket *) NULL; |
449 | 0 | found_transparency = MagickFalse; |
450 | 0 | for (y=0; y < image->rows; y++) |
451 | 0 | { |
452 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
453 | 0 | if (p == (const PixelPacket *) NULL) |
454 | 0 | break; |
455 | 0 | for (x=0; x < image->columns; x++) |
456 | 0 | { |
457 | 0 | if (p->opacity == TransparentOpacity) |
458 | 0 | { |
459 | 0 | found_transparency=MagickTrue; |
460 | 0 | break; |
461 | 0 | } |
462 | 0 | p++; |
463 | 0 | } |
464 | 0 | if (x < image->columns) |
465 | 0 | break; |
466 | 0 | } |
467 | 0 | if (found_transparency) |
468 | 0 | { |
469 | 0 | GetColorTuple(p,image->depth,image->matte,False,tuple); |
470 | 0 | (void) fprintf(file," Opacity: %.1024s\t",tuple); |
471 | 0 | GetColorTuple(p,image->depth,image->matte,True,tuple); |
472 | 0 | (void) fprintf(file," %.1024s\n",tuple); |
473 | 0 | } |
474 | 0 | } |
475 | 0 | if (image->storage_class == DirectClass) |
476 | 0 | { |
477 | 0 | if (image->total_colors != 0) |
478 | 0 | (void) fprintf(file," Colors: %lu\n",image->total_colors); |
479 | 0 | } |
480 | 0 | else |
481 | 0 | { |
482 | 0 | if (image->total_colors <= image->colors) |
483 | 0 | (void) fprintf(file," Colors: %u\n",image->colors); |
484 | 0 | else |
485 | 0 | (void) fprintf(file," Colors: %lu=>%u\n",image->total_colors, |
486 | 0 | image->colors); |
487 | 0 | } |
488 | 0 | if (image->storage_class == DirectClass) |
489 | 0 | { |
490 | 0 | if (image->total_colors < 1024) |
491 | 0 | if (verbose > 1) |
492 | 0 | (void) GetNumberColors(image,file,&image->exception); |
493 | 0 | } |
494 | 0 | else |
495 | 0 | { |
496 | 0 | char |
497 | 0 | name[MaxTextExtent]; |
498 | |
|
499 | 0 | register PixelPacket |
500 | 0 | *p; |
501 | | |
502 | | /* |
503 | | Display image colormap. |
504 | | */ |
505 | 0 | p=image->colormap; |
506 | 0 | for (i=0; i < image->colors; i++) |
507 | 0 | { |
508 | 0 | char |
509 | 0 | tuple[MaxTextExtent]; |
510 | |
|
511 | 0 | GetColorTuple(p,image->depth,image->matte,False,tuple); |
512 | 0 | (void) fprintf(file," %" MAGICK_SIZE_T_F "u: %.1024s", |
513 | 0 | (MAGICK_SIZE_T) i,tuple); |
514 | 0 | (void) fprintf(file,"\t"); |
515 | 0 | (void) QueryColorname(image,p,SVGCompliance,name,&image->exception); |
516 | 0 | (void) fprintf(file," %.1024s",name); |
517 | 0 | (void) fprintf(file,"\n"); |
518 | 0 | p++; |
519 | 0 | } |
520 | 0 | } |
521 | 0 | if (image->error.mean_error_per_pixel != 0.0) |
522 | 0 | (void) fprintf(file," Mean Exception Per Pixel: %ld\n", |
523 | 0 | (long) image->error.mean_error_per_pixel); |
524 | 0 | if (image->error.normalized_mean_error != 0.0) |
525 | 0 | (void) fprintf(file," Normalized Mean Exception: %g\n", |
526 | 0 | image->error.normalized_mean_error); |
527 | 0 | if (image->error.normalized_maximum_error != 0.0) |
528 | 0 | (void) fprintf(file," Normalized Maximum Exception: %gn", |
529 | 0 | image->error.normalized_maximum_error); |
530 | 0 | if (image->rendering_intent == SaturationIntent) |
531 | 0 | (void) fprintf(file," Rendering-Intent: saturation\n"); |
532 | 0 | else |
533 | 0 | if (image->rendering_intent == PerceptualIntent) |
534 | 0 | (void) fprintf(file," Rendering-Intent: perceptual\n"); |
535 | 0 | else |
536 | 0 | if (image->rendering_intent == AbsoluteIntent) |
537 | 0 | (void) fprintf(file," Rendering-Intent: absolute\n"); |
538 | 0 | else |
539 | 0 | if (image->rendering_intent == RelativeIntent) |
540 | 0 | (void) fprintf(file," Rendering-Intent: relative\n"); |
541 | 0 | if (image->gamma != 0.0) |
542 | 0 | (void) fprintf(file," Gamma: %g\n",image->gamma); |
543 | 0 | if ((image->chromaticity.red_primary.x != 0.0) || |
544 | 0 | (image->chromaticity.green_primary.x != 0.0) || |
545 | 0 | (image->chromaticity.blue_primary.x != 0.0) || |
546 | 0 | (image->chromaticity.white_point.x != 0.0)) |
547 | 0 | { |
548 | | /* |
549 | | Display image chromaticity. |
550 | | */ |
551 | 0 | (void) fprintf(file," Chromaticity:\n"); |
552 | 0 | (void) fprintf(file," red primary: (%g,%g)\n", |
553 | 0 | image->chromaticity.red_primary.x, |
554 | 0 | image->chromaticity.red_primary.y); |
555 | 0 | (void) fprintf(file," green primary: (%g,%g)\n", |
556 | 0 | image->chromaticity.green_primary.x, |
557 | 0 | image->chromaticity.green_primary.y); |
558 | 0 | (void) fprintf(file," blue primary: (%g,%g)\n", |
559 | 0 | image->chromaticity.blue_primary.x, |
560 | 0 | image->chromaticity.blue_primary.y); |
561 | 0 | (void) fprintf(file," white point: (%g,%g)\n", |
562 | 0 | image->chromaticity.white_point.x, |
563 | 0 | image->chromaticity.white_point.y); |
564 | 0 | } |
565 | 0 | if ((image->tile_info.width*image->tile_info.height) != 0) |
566 | 0 | (void) fprintf(file," Tile geometry: %lux%lu%+ld%+ld\n", |
567 | 0 | image->tile_info.width,image->tile_info.height, |
568 | 0 | image->tile_info.x, |
569 | 0 | image->tile_info.y); |
570 | 0 | if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0)) |
571 | 0 | { |
572 | | /* |
573 | | Display image resolution. |
574 | | */ |
575 | 0 | (void) fprintf(file," Resolution: %gx%g",image->x_resolution, |
576 | 0 | image->y_resolution); |
577 | 0 | if (image->units == UndefinedResolution) |
578 | 0 | (void) fprintf(file," pixels\n"); |
579 | 0 | else |
580 | 0 | if (image->units == PixelsPerInchResolution) |
581 | 0 | (void) fprintf(file," pixels/inch\n"); |
582 | 0 | else |
583 | 0 | if (image->units == PixelsPerCentimeterResolution) |
584 | 0 | (void) fprintf(file," pixels/centimeter\n"); |
585 | 0 | else |
586 | 0 | (void) fprintf(file,"\n"); |
587 | 0 | } |
588 | 0 | FormatSize(GetBlobSize(image),format); |
589 | 0 | (void) fprintf(file," Filesize: %.1024s\n",format); |
590 | 0 | fprintf(file," Interlace: %s\n", |
591 | 0 | InterlaceTypeToString(image->interlace == UndefinedInterlace ? |
592 | 0 | NoInterlace : image->interlace)); |
593 | 0 | (void) fprintf(file," Orientation: %s\n", |
594 | 0 | OrientationTypeToString(image->orientation)); |
595 | 0 | (void) QueryColorname(image,&image->background_color,SVGCompliance,color, |
596 | 0 | &image->exception); |
597 | 0 | (void) fprintf(file," Background Color: %.1024s\n",color); |
598 | 0 | (void) QueryColorname(image,&image->border_color,SVGCompliance,color, |
599 | 0 | &image->exception); |
600 | 0 | (void) fprintf(file," Border Color: %.1024s\n",color); |
601 | 0 | (void) QueryColorname(image,&image->matte_color,SVGCompliance,color, |
602 | 0 | &image->exception); |
603 | 0 | (void) fprintf(file," Matte Color: %.1024s\n",color); |
604 | 0 | if ((image->page.width != 0) && (image->page.height != 0)) |
605 | 0 | (void) fprintf(file," Page geometry: %lux%lu%+ld%+ld\n",image->page.width, |
606 | 0 | image->page.height,image->page.x,image->page.y); |
607 | 0 | (void) fprintf(file," Compose: %s\n", |
608 | 0 | CompositeOperatorToString(image->compose)); |
609 | 0 | (void) fprintf(file," Dispose: "); |
610 | 0 | switch (image->dispose) |
611 | 0 | { |
612 | 0 | case UndefinedDispose: (void) fprintf(file,"Undefined\n"); break; |
613 | 0 | case NoneDispose: (void) fprintf(file,"None\n"); break; |
614 | 0 | case BackgroundDispose: (void) fprintf(file,"Background\n"); break; |
615 | 0 | case PreviousDispose: (void) fprintf(file,"Previous\n"); break; |
616 | 0 | default: (void) fprintf(file,"\n"); break; |
617 | 0 | } |
618 | 0 | if (image->delay != 0) |
619 | 0 | (void) fprintf(file," Delay: %lu\n",image->delay); |
620 | 0 | if (image->iterations != 1) |
621 | 0 | (void) fprintf(file," Iterations: %lu\n",image->iterations); |
622 | 0 | p=image; |
623 | 0 | while (p->previous != (Image *) NULL) |
624 | 0 | p=p->previous; |
625 | 0 | for (count=1; p->next != (Image *) NULL; count++) |
626 | 0 | p=p->next; |
627 | 0 | if (count > 1) |
628 | 0 | (void) fprintf(file," Scene: %lu of %lu\n",image->scene,count); |
629 | 0 | else |
630 | 0 | if (image->scene != 0) |
631 | 0 | (void) fprintf(file," Scene: %lu\n",image->scene); |
632 | 0 | (void) fprintf(file," Compression: %s\n", |
633 | 0 | CompressionTypeToString(image->compression)); |
634 | | /* |
635 | | Display formatted image attributes. This must happen before we access |
636 | | any pseudo attributes like EXIF since doing so causes real attributes |
637 | | to be created and we would get duplicates in the output. |
638 | | */ |
639 | 0 | attribute=GetImageAttribute(image,(char *) NULL); |
640 | 0 | { |
641 | 0 | for ( ; attribute != (const ImageAttribute *) NULL; |
642 | 0 | attribute=attribute->next) |
643 | 0 | { |
644 | 0 | if (LocaleNCompare("EXIF",attribute->key,4) != 0) |
645 | 0 | { |
646 | 0 | (void) fprintf(file," %c", toupper((int)attribute->key[0])); |
647 | 0 | if (strlen(attribute->key) > 1) |
648 | 0 | (void) fprintf(file,"%.1024s",attribute->key+1); |
649 | |
|
650 | 0 | (void) fprintf(file,": "); |
651 | 0 | (void) fprintf(file,"%s\n",attribute->value); |
652 | 0 | } |
653 | 0 | } |
654 | 0 | } |
655 | 0 | if((profile=GetImageProfile(image,"ICM",&profile_length)) != 0) |
656 | 0 | (void) fprintf(file," Profile-color: %lu bytes\n",(unsigned long) |
657 | 0 | profile_length); |
658 | 0 | if((profile=GetImageProfile(image,"IPTC",&profile_length)) != 0) |
659 | 0 | { |
660 | 0 | char |
661 | 0 | *tag, |
662 | 0 | *text; |
663 | |
|
664 | 0 | size_t |
665 | 0 | length; |
666 | | |
667 | | /* |
668 | | Describe IPTC data. |
669 | | */ |
670 | 0 | (void) fprintf(file," Profile-iptc: %lu bytes\n",(unsigned long) |
671 | 0 | profile_length); |
672 | 0 | for (i=0; i+5U < profile_length; ) |
673 | 0 | { |
674 | 0 | if (profile[i] != 0x1c) |
675 | 0 | { |
676 | 0 | i++; |
677 | 0 | continue; |
678 | 0 | } |
679 | 0 | i++; /* skip file separator */ |
680 | 0 | i++; /* skip record number */ |
681 | 0 | switch (profile[i]) |
682 | 0 | { |
683 | 0 | case 5: tag=(char *) "Image Name"; break; |
684 | 0 | case 7: tag=(char *) "Edit Status"; break; |
685 | 0 | case 10: tag=(char *) "Priority"; break; |
686 | 0 | case 15: tag=(char *) "Category"; break; |
687 | 0 | case 20: tag=(char *) "Supplemental Category"; break; |
688 | 0 | case 22: tag=(char *) "Fixture Identifier"; break; |
689 | 0 | case 25: tag=(char *) "Keyword"; break; |
690 | 0 | case 30: tag=(char *) "Release Date"; break; |
691 | 0 | case 35: tag=(char *) "Release Time"; break; |
692 | 0 | case 40: tag=(char *) "Special Instructions"; break; |
693 | 0 | case 45: tag=(char *) "Reference Service"; break; |
694 | 0 | case 47: tag=(char *) "Reference Date"; break; |
695 | 0 | case 50: tag=(char *) "Reference Number"; break; |
696 | 0 | case 55: tag=(char *) "Created Date"; break; |
697 | 0 | case 60: tag=(char *) "Created Time"; break; |
698 | 0 | case 65: tag=(char *) "Originating Program"; break; |
699 | 0 | case 70: tag=(char *) "Program Version"; break; |
700 | 0 | case 75: tag=(char *) "Object Cyc"; break; |
701 | 0 | case 80: tag=(char *) "Byline"; break; |
702 | 0 | case 85: tag=(char *) "Byline Title"; break; |
703 | 0 | case 90: tag=(char *) "City"; break; |
704 | 0 | case 95: tag=(char *) "Province State"; break; |
705 | 0 | case 100: tag=(char *) "Country Code"; break; |
706 | 0 | case 101: tag=(char *) "Country"; break; |
707 | 0 | case 103: tag=(char *) "Original Transmission Reference"; break; |
708 | 0 | case 105: tag=(char *) "Headline"; break; |
709 | 0 | case 110: tag=(char *) "Credit"; break; |
710 | 0 | case 115: tag=(char *) "Source"; break; |
711 | 0 | case 116: tag=(char *) "Copyright String"; break; |
712 | 0 | case 120: tag=(char *) "Caption"; break; |
713 | 0 | case 121: tag=(char *) "Local Caption"; break; |
714 | 0 | case 122: tag=(char *) "Caption Writer"; break; |
715 | 0 | case 200: tag=(char *) "Custom Field 1"; break; |
716 | 0 | case 201: tag=(char *) "Custom Field 2"; break; |
717 | 0 | case 202: tag=(char *) "Custom Field 3"; break; |
718 | 0 | case 203: tag=(char *) "Custom Field 4"; break; |
719 | 0 | case 204: tag=(char *) "Custom Field 5"; break; |
720 | 0 | case 205: tag=(char *) "Custom Field 6"; break; |
721 | 0 | case 206: tag=(char *) "Custom Field 7"; break; |
722 | 0 | case 207: tag=(char *) "Custom Field 8"; break; |
723 | 0 | case 208: tag=(char *) "Custom Field 9"; break; |
724 | 0 | case 209: tag=(char *) "Custom Field 10"; break; |
725 | 0 | case 210: tag=(char *) "Custom Field 11"; break; |
726 | 0 | case 211: tag=(char *) "Custom Field 12"; break; |
727 | 0 | case 212: tag=(char *) "Custom Field 13"; break; |
728 | 0 | case 213: tag=(char *) "Custom Field 14"; break; |
729 | 0 | case 214: tag=(char *) "Custom Field 15"; break; |
730 | 0 | case 215: tag=(char *) "Custom Field 16"; break; |
731 | 0 | case 216: tag=(char *) "Custom Field 17"; break; |
732 | 0 | case 217: tag=(char *) "Custom Field 18"; break; |
733 | 0 | case 218: tag=(char *) "Custom Field 19"; break; |
734 | 0 | case 219: tag=(char *) "Custom Field 20"; break; |
735 | 0 | default: tag=(char *) "unknown"; break; |
736 | 0 | } |
737 | 0 | i++; |
738 | 0 | (void) fprintf(file," %.1024s:\n",tag); |
739 | 0 | length=(size_t) profile[i++] << 8; |
740 | 0 | length|=(size_t) profile[i++]; |
741 | 0 | length=Min(length,profile_length-i); |
742 | 0 | text=MagickAllocateMemory(char *,length+1); |
743 | 0 | if (text != (char *) NULL) |
744 | 0 | { |
745 | 0 | char |
746 | 0 | **textlist; |
747 | |
|
748 | 0 | register unsigned long |
749 | 0 | j; |
750 | |
|
751 | 0 | (void) strncpy(text,(char *) profile+i,length); |
752 | 0 | text[length]='\0'; |
753 | 0 | textlist=StringToList(text); |
754 | 0 | if (textlist != (char **) NULL) |
755 | 0 | { |
756 | 0 | for (j=0; textlist[j] != (char *) NULL; j++) |
757 | 0 | { |
758 | 0 | (void) fprintf(file," %s\n",textlist[j]); |
759 | 0 | MagickFreeMemory(textlist[j]); |
760 | 0 | } |
761 | 0 | MagickFreeMemory(textlist); |
762 | 0 | } |
763 | 0 | MagickFreeMemory(text); |
764 | 0 | } |
765 | 0 | i+=length; |
766 | 0 | } |
767 | 0 | } |
768 | 0 | { |
769 | 0 | const char |
770 | 0 | *profile_name; |
771 | |
|
772 | 0 | size_t |
773 | 0 | profile_length=0; |
774 | |
|
775 | 0 | const unsigned char * |
776 | 0 | profile_info; |
777 | |
|
778 | 0 | ImageProfileIterator |
779 | 0 | profile_iterator; |
780 | |
|
781 | 0 | profile_iterator=AllocateImageProfileIterator(image); |
782 | 0 | while(NextImageProfile(profile_iterator,&profile_name,&profile_info, |
783 | 0 | &profile_length) != MagickFail) |
784 | 0 | { |
785 | 0 | if ((LocaleCompare(profile_name,"ICC") == 0) || |
786 | 0 | (LocaleCompare(profile_name,"ICM") == 0) || |
787 | 0 | (LocaleCompare(profile_name,"IPTC") == 0) || |
788 | 0 | (LocaleCompare(profile_name,"8BIM") == 0)) |
789 | 0 | continue; |
790 | | |
791 | 0 | if (profile_length == 0) |
792 | 0 | continue; |
793 | 0 | (void) fprintf(file," Profile-%.1024s: %lu bytes\n", |
794 | 0 | profile_name == (char *) NULL ? "generic" : profile_name, |
795 | 0 | (unsigned long) profile_length); |
796 | 0 | if (LocaleCompare(profile_name,"EXIF") == 0) |
797 | 0 | { |
798 | 0 | attribute=GetImageAttribute(image,"EXIF:*"); |
799 | 0 | if (attribute != (const ImageAttribute *) NULL) |
800 | 0 | { |
801 | 0 | char |
802 | 0 | **values; |
803 | |
|
804 | 0 | register char |
805 | 0 | *p; |
806 | |
|
807 | 0 | values=StringToList(attribute->value); |
808 | 0 | if (values != (char **) NULL) |
809 | 0 | { |
810 | 0 | for (x=0; values[x] != (char *) NULL; x++) |
811 | 0 | { |
812 | 0 | (void) fprintf(file," "); |
813 | 0 | for (p=values[x]; *p != '\0'; p++) |
814 | 0 | { |
815 | 0 | if (p > values[x]) |
816 | 0 | if ((isupper((int) ((unsigned char) *p)) |
817 | 0 | != MagickFalse) && |
818 | 0 | (islower((int) ((unsigned char) *(p+1))) |
819 | 0 | != MagickFalse)) |
820 | 0 | (void) fprintf(file," "); |
821 | 0 | if (*p == '=') |
822 | 0 | { |
823 | 0 | (void) fprintf(file,": "); |
824 | 0 | for (p++; *p != '\0'; p++) |
825 | 0 | (void) fputc(*p,file); |
826 | 0 | break; |
827 | 0 | } |
828 | 0 | (void) fputc(*p,file); |
829 | 0 | } |
830 | 0 | (void) fputc('\n',file); |
831 | 0 | MagickFreeMemory(values[x]); |
832 | 0 | } |
833 | 0 | MagickFreeMemory(values); |
834 | 0 | } |
835 | 0 | } |
836 | 0 | } /* End of EXIF */ |
837 | 0 | } |
838 | 0 | DeallocateImageProfileIterator(profile_iterator); |
839 | 0 | } |
840 | 0 | if (image->montage != (char *) NULL) |
841 | 0 | (void) fprintf(file," Montage: %.1024s\n",image->montage); |
842 | 0 | if (image->directory != (char *) NULL) |
843 | 0 | { |
844 | 0 | Image |
845 | 0 | *tile; |
846 | |
|
847 | 0 | ImageInfo |
848 | 0 | *image_info; |
849 | |
|
850 | 0 | register char |
851 | 0 | *p, |
852 | 0 | *q; |
853 | |
|
854 | 0 | WarningHandler |
855 | 0 | handler; |
856 | | |
857 | | /* |
858 | | Display visual image directory. |
859 | | */ |
860 | 0 | image_info=CloneImageInfo((ImageInfo *) NULL); |
861 | 0 | (void) CloneString(&image_info->size,"64x64"); |
862 | 0 | (void) fprintf(file," Directory:\n"); |
863 | 0 | for (p=image->directory; *p != '\0'; p++) |
864 | 0 | { |
865 | 0 | q=p; |
866 | 0 | while ((*q != '\n') && (*q != '\0') && |
867 | 0 | ((size_t) (q-p+1) < sizeof(image_info->filename))) |
868 | 0 | q++; |
869 | 0 | (void) strncpy(image_info->filename,p,q-p); |
870 | 0 | image_info->filename[q-p]='\0'; |
871 | 0 | if (*q == '\0') |
872 | 0 | break; |
873 | 0 | p=q; |
874 | 0 | (void) fprintf(file," %.1024s",image_info->filename); |
875 | 0 | handler=SetWarningHandler((WarningHandler) NULL); |
876 | 0 | tile=ReadImage(image_info,&image->exception); |
877 | 0 | (void) SetWarningHandler(handler); |
878 | 0 | if (tile == (Image *) NULL) |
879 | 0 | { |
880 | 0 | (void) fprintf(file,"\n"); |
881 | 0 | continue; |
882 | 0 | } |
883 | 0 | (void) fprintf(file," %lux%lu %.1024s\n",tile->magick_columns, |
884 | 0 | tile->magick_rows,tile->magick); |
885 | 0 | (void) SignatureImage(tile); |
886 | 0 | attribute=GetImageAttribute(tile,(char *) NULL); |
887 | 0 | for ( ; attribute != (const ImageAttribute *) NULL; |
888 | 0 | attribute=attribute->next) |
889 | 0 | { |
890 | 0 | if (*attribute->key == '[') |
891 | 0 | continue; |
892 | 0 | (void) fprintf(file," %.1024s:\n",attribute->key); |
893 | 0 | (void) fprintf(file,"%s\n",attribute->value); |
894 | 0 | } |
895 | 0 | DestroyImage(tile); |
896 | 0 | } |
897 | 0 | DestroyImageInfo(image_info); |
898 | 0 | } |
899 | 0 | if (image->taint) |
900 | 0 | (void) fprintf(file," Tainted: True\n"); |
901 | 0 | else |
902 | 0 | (void) fprintf(file," Tainted: False\n"); |
903 | | /* |
904 | | Only display time information if the time accumulated is at least |
905 | | the timer's resolution. |
906 | | */ |
907 | 0 | if (user_time >= GetTimerResolution()) |
908 | 0 | (void) fprintf(file," User Time: %0.3fu\n",user_time); |
909 | 0 | if (!(image->ping) && (elapsed_time >= GetTimerResolution())) |
910 | 0 | { |
911 | 0 | (void) fprintf(file," Elapsed Time: %ldm:%.6fs\n", |
912 | 0 | (long) (elapsed_time/60.0), |
913 | 0 | fmod(elapsed_time,60.0)); |
914 | 0 | pixels_per_second=(magick_int64_t) ((double) image->rows* |
915 | 0 | image->columns/ |
916 | 0 | (elapsed_time > GetTimerResolution() ? |
917 | 0 | elapsed_time : GetTimerResolution())); |
918 | 0 | FormatSize(pixels_per_second,format); |
919 | 0 | (void) fprintf(file," Pixels Per Second: %s\n", format); |
920 | 0 | } |
921 | 0 | (void) fflush(file); |
922 | 0 | return (ferror(file) ? MagickFail : MagickPass); |
923 | 0 | } |