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