/src/graphicsmagick/coders/pnm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | % Copyright (C) 2003-2023 GraphicsMagick Group |
3 | | % Copyright (C) 2002 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 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % PPPP N N M M % |
15 | | % P P NN N MM MM % |
16 | | % PPPP N N N M M M % |
17 | | % P N NN M M % |
18 | | % P N N M M % |
19 | | % % |
20 | | % % |
21 | | % Read/Write PBMPlus Portable Anymap Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % John Cristy % |
26 | | % July 1992 % |
27 | | % % |
28 | | % % |
29 | | % % |
30 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
31 | | % |
32 | | % |
33 | | */ |
34 | | |
35 | | /* |
36 | | Include declarations. |
37 | | */ |
38 | | #include "magick/studio.h" |
39 | | #include "magick/analyze.h" |
40 | | #include "magick/attribute.h" |
41 | | #include "magick/blob.h" |
42 | | #include "magick/color.h" |
43 | | #include "magick/colormap.h" |
44 | | #include "magick/constitute.h" |
45 | | #include "magick/log.h" |
46 | | #include "magick/magick.h" |
47 | | #include "magick/monitor.h" |
48 | | #include "magick/omp_data_view.h" |
49 | | #include "magick/pixel_cache.h" |
50 | | #include "magick/utility.h" |
51 | | |
52 | | /* |
53 | | Forward declarations. |
54 | | */ |
55 | | static unsigned int |
56 | | WritePNMImage(const ImageInfo *,Image *); |
57 | | |
58 | | |
59 | | /* |
60 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
61 | | % % |
62 | | % % |
63 | | % % |
64 | | % I s P N M % |
65 | | % % |
66 | | % % |
67 | | % % |
68 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
69 | | % |
70 | | % Method IsPNM returns True if the image format type, identified by the |
71 | | % magick string, is PNM. |
72 | | % |
73 | | % The format of the IsPNM method is: |
74 | | % |
75 | | % unsigned int IsPNM(const unsigned char *magick,const size_t length) |
76 | | % |
77 | | % A description of each parameter follows: |
78 | | % |
79 | | % o status: Method IsPNM returns True if the image format type is PNM. |
80 | | % |
81 | | % o magick: This string is generally the first few bytes of an image file |
82 | | % or blob. |
83 | | % |
84 | | % o length: Specifies the length of the magick string. |
85 | | % |
86 | | % |
87 | | */ |
88 | | static unsigned int IsPNM(const unsigned char *magick,const size_t length) |
89 | 0 | { |
90 | 0 | if (length < 2) |
91 | 0 | return(False); |
92 | 0 | if ((*magick == 'P') && isdigit((int) magick[1])) |
93 | 0 | return(True); |
94 | 0 | return(False); |
95 | 0 | } |
96 | | |
97 | | /* |
98 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
99 | | % % |
100 | | % % |
101 | | % % |
102 | | % R e a d P N M I m a g e % |
103 | | % % |
104 | | % % |
105 | | % % |
106 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
107 | | % |
108 | | % Method ReadPNMImage reads a Portable Anymap image file and returns it. |
109 | | % It allocates the memory necessary for the new Image structure and returns |
110 | | % a pointer to the new image. |
111 | | % |
112 | | % The format of the ReadPNMImage method is: |
113 | | % |
114 | | % Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception) |
115 | | % |
116 | | % A description of each parameter follows: |
117 | | % |
118 | | % o image: Method ReadPNMImage returns a pointer to the image after |
119 | | % reading. A null image is returned if there is a memory shortage or |
120 | | % if the image cannot be read. |
121 | | % |
122 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
123 | | % |
124 | | % o exception: return any errors or warnings in this structure. |
125 | | % |
126 | | % |
127 | | */ |
128 | | |
129 | | static unsigned int PNMInteger(Image *image,const unsigned int base) |
130 | 235k | { |
131 | 235k | int |
132 | 235k | c; |
133 | | |
134 | 235k | unsigned long |
135 | 235k | value; |
136 | | |
137 | | /* |
138 | | Skip any leading whitespace. |
139 | | */ |
140 | 235k | do |
141 | 5.51M | { |
142 | 5.51M | c=ReadBlobByte(image); |
143 | 5.51M | if (c == EOF) |
144 | 13.0k | return(0); |
145 | 5.51M | } while (!isdigit(c)); |
146 | 222k | c &= 0xff; |
147 | 222k | if (base == 2) |
148 | 15.2k | return(c-'0'); |
149 | | /* |
150 | | Evaluate number. |
151 | | */ |
152 | 206k | value=0; |
153 | 338k | while(1) |
154 | 338k | { |
155 | 338k | value*=10; |
156 | 338k | value+=c-'0'; |
157 | 338k | c=ReadBlobByte(image); |
158 | 338k | if ((c == EOF) || !(isdigit(c))) |
159 | 206k | break; |
160 | 131k | c &= 0xff; |
161 | 131k | } |
162 | | |
163 | 206k | return(value); |
164 | 222k | } |
165 | | |
166 | | static unsigned int PNMIntegerOrComment(Image *image,const unsigned int base) |
167 | 67.4k | { |
168 | 67.4k | int |
169 | 67.4k | c; |
170 | | |
171 | 67.4k | unsigned long |
172 | 67.4k | value; |
173 | | |
174 | 67.4k | static const char P7Comment[] = "END_OF_COMMENTS\n"; |
175 | | |
176 | | /* |
177 | | Skip any leading whitespace. |
178 | | */ |
179 | 67.4k | do |
180 | 3.57M | { |
181 | 3.57M | c=ReadBlobByte(image); |
182 | 3.57M | if (c == EOF) |
183 | 2.82k | return(0); |
184 | 3.57M | c &= 0xff; |
185 | 3.57M | if (c == '#') |
186 | 80.8k | { |
187 | 80.8k | char |
188 | 80.8k | *comment; |
189 | | |
190 | 80.8k | const ImageAttribute |
191 | 80.8k | *comment_attr; |
192 | | |
193 | 80.8k | ExtendedSignedIntegralType |
194 | 80.8k | offset; |
195 | | |
196 | 80.8k | register char |
197 | 80.8k | *p, |
198 | 80.8k | *q; |
199 | | |
200 | 80.8k | size_t |
201 | 80.8k | length; |
202 | | |
203 | | /* |
204 | | Read comment. |
205 | | */ |
206 | 80.8k | if ((comment_attr=GetImageAttribute(image,"comment")) != (const ImageAttribute *) NULL) |
207 | 78.4k | { |
208 | | /* |
209 | | If existing comment text length exceeds arbitrary limit, |
210 | | then do no further comment processing for this file. |
211 | | */ |
212 | 78.4k | if (comment_attr->length > MaxTextExtent*2) |
213 | 4.36k | { |
214 | 5.87M | for ( ; (c != EOF) && (c != '\n'); ) |
215 | 5.87M | c=ReadBlobByte(image); |
216 | 4.36k | return 0; |
217 | 4.36k | } |
218 | 78.4k | } |
219 | 76.4k | length=MaxTextExtent; |
220 | 76.4k | comment=MagickAllocateResourceLimitedMemory(char *,length+sizeof(P7Comment)); |
221 | 76.4k | p=comment; |
222 | 76.4k | offset=p-comment; |
223 | 76.4k | if (comment != (char *) NULL) |
224 | 243M | for ( ; (c != EOF) && (c != '\n'); p++) |
225 | 243M | { |
226 | 243M | if ((size_t) (p-comment) >= length) |
227 | 117k | { |
228 | 117k | size_t |
229 | 117k | text_length; |
230 | | |
231 | 117k | char |
232 | 117k | *new_comment; |
233 | | |
234 | 117k | text_length=(size_t) (p-comment); |
235 | 117k | length+=MaxTextExtent; |
236 | 117k | new_comment=MagickReallocateResourceLimitedMemory(char *,comment,length+sizeof(P7Comment)); |
237 | 117k | if (new_comment == (char *) NULL) |
238 | 0 | { |
239 | 0 | MagickFreeResourceLimitedMemory(comment); |
240 | 0 | break; |
241 | 0 | } |
242 | 117k | comment=new_comment; |
243 | 117k | p=comment+text_length; |
244 | 117k | } |
245 | 243M | c=ReadBlobByte(image); |
246 | 243M | *p=c; |
247 | 243M | *(p+1)='\0'; |
248 | 243M | } |
249 | 76.4k | if (comment == (char *) NULL) |
250 | 0 | return(0); |
251 | 76.4k | q=comment+offset; |
252 | 76.4k | if (LocaleCompare(q,P7Comment) == 0) |
253 | 0 | *q='\0'; |
254 | | /* |
255 | | FIXME: |
256 | | Implicitly extend existing comment attribute since comments |
257 | | can span multiple lines. |
258 | | */ |
259 | 76.4k | (void) SetImageAttribute(image,"comment",comment); |
260 | 76.4k | MagickFreeResourceLimitedMemory(comment); |
261 | 76.4k | continue; |
262 | 76.4k | } |
263 | 3.57M | } while (!isdigit(c)); |
264 | 60.2k | if (base == 2) |
265 | 0 | return(c-'0'); |
266 | | /* |
267 | | Evaluate number. |
268 | | */ |
269 | 60.2k | value=0; |
270 | 60.2k | do |
271 | 83.2k | { |
272 | 83.2k | value*=10; |
273 | 83.2k | value+=c-'0'; |
274 | 83.2k | c=ReadBlobByte(image); |
275 | 83.2k | if (c == EOF) |
276 | 531 | return(value); |
277 | 83.2k | } |
278 | 60.2k | while (isdigit(c)); |
279 | 59.6k | return(value); |
280 | 60.2k | } |
281 | | |
282 | | #define ValidateScalingIndex(image, index, max) \ |
283 | 60.9k | do \ |
284 | 60.9k | { \ |
285 | 60.9k | if (index > max) \ |
286 | 60.9k | ThrowReaderException(CorruptImageError,CorruptImage, image); \ |
287 | 59.8k | } while (0) |
288 | | |
289 | | #define ValidateScalingPixel(image, pixel, max) \ |
290 | 13.5k | do \ |
291 | 13.5k | { \ |
292 | 13.5k | ValidateScalingIndex(image, pixel.red, max); \ |
293 | 13.5k | ValidateScalingIndex(image, pixel.green, max); \ |
294 | 13.3k | ValidateScalingIndex(image, pixel.blue, max); \ |
295 | 13.1k | } while (0) |
296 | | |
297 | | typedef enum |
298 | | { |
299 | | Undefined_PNM_Format, |
300 | | PBM_ASCII_Format, /* P1 */ |
301 | | PGM_ASCII_Format, /* P2 */ |
302 | | PPM_ASCII_Format, /* P3 */ |
303 | | PBM_RAW_Format, /* P4 */ |
304 | | PGM_RAW_Format, /* P5 */ |
305 | | PPM_RAW_Format, /* P6 */ |
306 | | PAM_Format, /* P7 */ |
307 | | XV_332_Format /* P7 332 */ |
308 | | } PNMSubformat; |
309 | | |
310 | | static const char *PNMSubformatToString(const PNMSubformat f) |
311 | 16.2k | { |
312 | 16.2k | const char *s = "unknown"; |
313 | | |
314 | 16.2k | switch (f) |
315 | 16.2k | { |
316 | 0 | case Undefined_PNM_Format: |
317 | 0 | s = "Undefined"; |
318 | 0 | break; |
319 | 969 | case PBM_ASCII_Format: /* P1 */ |
320 | 969 | s = "PBM ASCII"; |
321 | 969 | break; |
322 | 2.42k | case PGM_ASCII_Format: /* P2 */ |
323 | 2.42k | s = "PGM ASCII"; |
324 | 2.42k | break; |
325 | 2.25k | case PPM_ASCII_Format: /* P3 */ |
326 | 2.25k | s = "PPM ASCII"; |
327 | 2.25k | break; |
328 | 2.29k | case PBM_RAW_Format: /* P4 */ |
329 | 2.29k | s = "PBM RAW"; |
330 | 2.29k | break; |
331 | 1.55k | case PGM_RAW_Format: /* P5 */ |
332 | 1.55k | s = "PGM RAW"; |
333 | 1.55k | break; |
334 | 2.73k | case PPM_RAW_Format: /* P6 */ |
335 | 2.73k | s = "PPM RAW"; |
336 | 2.73k | break; |
337 | 3.95k | case PAM_Format: /* P7 */ |
338 | 3.95k | s = "PAM"; |
339 | 3.95k | break; |
340 | 103 | case XV_332_Format: /* P7 332 */ |
341 | 103 | s = "XV 332 icon"; |
342 | 103 | break; |
343 | 16.2k | } |
344 | 16.2k | return s; |
345 | 16.2k | } |
346 | | |
347 | | #if defined(HAVE_OPENMP) |
348 | | # define PNMReadUseOpenMP 1 |
349 | | |
350 | | static int PNMReadThreads(const Image* image, const size_t bytes_per_row) |
351 | | { |
352 | | const int omp_max_threads = omp_get_max_threads(); |
353 | | int threads; |
354 | | ARG_NOT_USED(image); |
355 | | threads=(int)(Min(bytes_per_row/4096U,(size_t) Max(0,omp_max_threads))); |
356 | | if (0 == threads) |
357 | | threads=1; |
358 | | return threads; |
359 | | } |
360 | | #endif /* defined(HAVE_OPENMP) */ |
361 | | |
362 | | static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception) |
363 | 25.3k | { |
364 | 25.3k | char |
365 | 25.3k | c; |
366 | | |
367 | 25.3k | PNMSubformat |
368 | 25.3k | format; |
369 | | |
370 | 25.3k | Image |
371 | 25.3k | *image; |
372 | | |
373 | 25.3k | long |
374 | 25.3k | y; |
375 | | |
376 | 25.3k | LongPixelPacket |
377 | 25.3k | pixel; |
378 | | |
379 | 25.3k | register IndexPacket |
380 | 25.3k | *indexes; |
381 | | |
382 | 25.3k | register unsigned long |
383 | 25.3k | i; |
384 | | |
385 | 25.3k | size_t |
386 | 25.3k | count, |
387 | 25.3k | number_pixels; |
388 | | |
389 | 25.3k | unsigned int |
390 | 25.3k | index, |
391 | 25.3k | bits_per_sample; |
392 | | |
393 | 25.3k | MagickPassFail |
394 | 25.3k | status; |
395 | | |
396 | 25.3k | unsigned int |
397 | 25.3k | max_value, |
398 | 25.3k | samples_per_pixel; |
399 | | |
400 | | /* |
401 | | Open image file. |
402 | | */ |
403 | 25.3k | assert(image_info != (const ImageInfo *) NULL); |
404 | 25.3k | assert(image_info->signature == MagickSignature); |
405 | 25.3k | assert(exception != (ExceptionInfo *) NULL); |
406 | 25.3k | assert(exception->signature == MagickSignature); |
407 | 25.3k | image=AllocateImage(image_info); |
408 | 25.3k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
409 | 25.3k | if (status == False) |
410 | 25.3k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
411 | | /* |
412 | | Read PNM image. |
413 | | */ |
414 | 25.3k | count=ReadBlob(image,1,(char *) &c); |
415 | 25.3k | do |
416 | 25.3k | { |
417 | | /* |
418 | | Initialize image structure. |
419 | | */ |
420 | 25.3k | max_value=0; |
421 | 25.3k | bits_per_sample=0; |
422 | 25.3k | samples_per_pixel=0; |
423 | | |
424 | 25.3k | if (count == 0) |
425 | 25.3k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
426 | | |
427 | 25.3k | if (c != 'P') |
428 | 81 | { |
429 | 81 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Read %c rather than expected 'P'!",c); |
430 | 81 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
431 | 0 | } |
432 | | |
433 | 25.2k | c=ReadBlobByte(image); |
434 | 25.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"PNM Format Id: P%c", |
435 | 25.2k | c); |
436 | | |
437 | 25.2k | switch (c) |
438 | 25.2k | { |
439 | 1.67k | case '1': format=PBM_ASCII_Format; break; |
440 | 2.56k | case '2': format=PGM_ASCII_Format; break; |
441 | 2.34k | case '3': format=PPM_ASCII_Format; break; |
442 | 2.78k | case '4': format=PBM_RAW_Format; break; |
443 | 1.74k | case '5': format=PGM_RAW_Format; break; |
444 | 4.40k | case '6': format=PPM_RAW_Format; break; |
445 | 8.65k | case '7': |
446 | 8.65k | { |
447 | 8.65k | if ((ReadBlobByte(image) == ' ') && |
448 | 8.65k | (PNMIntegerOrComment(image,10) == 332)) |
449 | 578 | format=XV_332_Format; |
450 | 8.07k | else |
451 | 8.07k | format=PAM_Format; |
452 | 8.65k | break; |
453 | 0 | } |
454 | 1.13k | default: |
455 | 1.13k | { |
456 | 1.13k | format=Undefined_PNM_Format; |
457 | 1.13k | } |
458 | 25.2k | } |
459 | | |
460 | 25.2k | if (PAM_Format == format) |
461 | 8.07k | { |
462 | | /* |
463 | | PAM header format |
464 | | |
465 | | P7 |
466 | | WIDTH 227 |
467 | | HEIGHT 149 |
468 | | DEPTH 3 |
469 | | MAXVAL 255 |
470 | | TUPLTYPE RGB |
471 | | ENDHDR |
472 | | */ |
473 | | |
474 | 8.07k | char |
475 | 8.07k | keyword[MaxTextExtent]; |
476 | | |
477 | 8.07k | register char |
478 | 8.07k | *p; |
479 | | |
480 | 8.07k | int |
481 | 8.07k | c; |
482 | | |
483 | 576k | while (1) |
484 | 576k | { |
485 | 576k | p=keyword; |
486 | 576k | c=ReadBlobByte(image); |
487 | 576k | do |
488 | 1.91M | { |
489 | 1.91M | if (isalnum(c) || ('#' == c)) |
490 | 1.90M | if ((p-keyword) < (MaxTextExtent-1)) |
491 | 1.90M | { |
492 | 1.90M | *p++=c; |
493 | 1.90M | if ('#' == c) |
494 | 345k | break; |
495 | 1.90M | } |
496 | 1.57M | c=ReadBlobByte(image); |
497 | 1.57M | } while (isalnum(c) || ('#' == c)); |
498 | 0 | *p='\0'; |
499 | | |
500 | 576k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
501 | 576k | "Keyword \"%s\"",keyword); |
502 | 576k | if ((EOF == c) || (LocaleCompare(keyword,"ENDHDR") == 0)) |
503 | 3.17k | { |
504 | 3.17k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
505 | 3.17k | "Exiting header!"); |
506 | 3.17k | break; |
507 | 3.17k | } |
508 | 573k | else if (LocaleCompare(keyword,"HEIGHT") == 0) |
509 | 49.2k | { |
510 | 49.2k | image->rows=PNMIntegerOrComment(image,10); |
511 | 49.2k | } |
512 | 524k | else if (LocaleCompare(keyword,"WIDTH") == 0) |
513 | 40.2k | { |
514 | 40.2k | image->columns=PNMInteger(image,10); |
515 | 40.2k | } |
516 | 484k | else if (LocaleCompare(keyword,"DEPTH") == 0) |
517 | 47.5k | { |
518 | 47.5k | samples_per_pixel=PNMInteger(image,10); |
519 | 47.5k | } |
520 | 436k | else if (LocaleCompare(keyword,"MAXVAL") == 0) |
521 | 35.1k | { |
522 | 35.1k | max_value=PNMInteger(image,10); |
523 | 35.1k | } |
524 | 401k | else if (LocaleCompare(keyword,"TUPLTYPE") == 0) |
525 | 51.7k | { |
526 | | /* Skip white space */ |
527 | 51.7k | do |
528 | 61.7k | { |
529 | 61.7k | c=ReadBlobByte(image); |
530 | 61.7k | } while (isspace(c) && (EOF != c)); |
531 | 51.7k | if (EOF == c) |
532 | 83 | break; |
533 | | /* Tupletype argument */ |
534 | 51.6k | p=keyword; |
535 | 51.6k | do |
536 | 108M | { |
537 | 108M | if ((p-keyword) < (MaxTextExtent-1)) |
538 | 17.1M | *p++=c; |
539 | 108M | c=ReadBlobByte(image); |
540 | 108M | } while (('\n' != c) && (EOF != c)); |
541 | 51.6k | *p='\0'; |
542 | 51.6k | if (EOF == c) |
543 | 316 | break; |
544 | 51.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
545 | 51.3k | "TUPLTYPE \"%s\"",keyword); |
546 | 51.3k | if (LocaleNCompare(keyword,"BLACKANDWHITE",13) == 0) |
547 | 1.25k | { |
548 | 1.25k | image->colorspace=GRAYColorspace; |
549 | 1.25k | image->is_monochrome=MagickTrue; |
550 | 1.25k | } |
551 | 50.0k | else if (LocaleNCompare(keyword,"CMYK",4) == 0) |
552 | 16.0k | { |
553 | 16.0k | image->colorspace=CMYKColorspace; |
554 | 16.0k | } |
555 | 34.0k | else if (LocaleNCompare(keyword,"GRAYSCALE",9) == 0) |
556 | 1.61k | { |
557 | 1.61k | image->colorspace=GRAYColorspace; |
558 | 1.61k | } |
559 | 32.4k | else if (LocaleNCompare(keyword,"RGB",3) == 0) |
560 | 237 | { |
561 | 237 | } |
562 | | |
563 | | /* |
564 | | Check for alpha flag. |
565 | | */ |
566 | 51.3k | count=strlen(keyword); |
567 | 51.3k | if ((count > 6) && (LocaleNCompare(keyword+count-6,"_ALPHA",6) == 0)) |
568 | 15.1k | { |
569 | 15.1k | image->matte=MagickTrue; |
570 | 15.1k | } |
571 | 51.3k | } |
572 | 349k | else if (LocaleNCompare(keyword,"#",1) == 0) |
573 | 345k | { |
574 | | /* Skip leading white space */ |
575 | 345k | do |
576 | 596k | { |
577 | 596k | c=ReadBlobByte(image); |
578 | 596k | } while (isspace(c) && (EOF != c)); |
579 | 345k | if (EOF == c) |
580 | 181 | break; |
581 | | |
582 | | /* Comment */ |
583 | 345k | p=keyword; |
584 | 143M | while ((p-keyword) < (MaxTextExtent-2)) |
585 | 142M | { |
586 | 142M | *p++=c; |
587 | 142M | c=ReadBlobByte(image); |
588 | 142M | if (c == '\n') |
589 | 280k | { |
590 | 280k | *p++=c; |
591 | 280k | break; |
592 | 280k | } |
593 | 142M | if (c == EOF) |
594 | 512 | break; |
595 | 142M | } |
596 | 345k | *p='\0'; |
597 | | /* |
598 | | FIXME: |
599 | | Implicitly extend existing comment attribute since comments |
600 | | can span multiple lines. |
601 | | */ |
602 | 345k | (void) SetImageAttribute(image,"comment",keyword); |
603 | 345k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
604 | 345k | "Comment: \"%s\"",keyword); |
605 | 345k | } |
606 | 4.31k | else |
607 | 4.31k | { |
608 | | /* Unknown! */ |
609 | 4.31k | do |
610 | 95.6M | { |
611 | 95.6M | c=ReadBlobByte(image); |
612 | 95.6M | } while (('\n' != c) && (EOF != c)); |
613 | 4.31k | break; |
614 | 4.31k | } |
615 | 576k | } |
616 | 8.07k | } |
617 | 17.2k | else |
618 | 17.2k | { |
619 | | /* |
620 | | PNM header type format |
621 | | |
622 | | P1 |
623 | | # feep.pbm |
624 | | 24 7 |
625 | | |
626 | | P3 |
627 | | # feep.ppm |
628 | | 4 4 |
629 | | 15 |
630 | | */ |
631 | 17.2k | image->columns=PNMIntegerOrComment(image,10); |
632 | 17.2k | image->rows=PNMInteger(image,10); |
633 | | |
634 | 17.2k | if ((format == PBM_ASCII_Format) || (format == PBM_RAW_Format)) |
635 | 4.46k | max_value=1; /* bitmap */ |
636 | 12.7k | else |
637 | 12.7k | max_value=PNMInteger(image,10); |
638 | | |
639 | 17.2k | switch (format) |
640 | 17.2k | { |
641 | 1.67k | case PBM_ASCII_Format: |
642 | 4.46k | case PBM_RAW_Format: |
643 | 7.02k | case PGM_ASCII_Format: |
644 | 8.76k | case PGM_RAW_Format: |
645 | 9.34k | case XV_332_Format: |
646 | 9.34k | { |
647 | 9.34k | samples_per_pixel=1; |
648 | 9.34k | break; |
649 | 8.76k | } |
650 | 2.34k | case PPM_ASCII_Format: |
651 | 6.74k | case PPM_RAW_Format: |
652 | 6.74k | { |
653 | 6.74k | samples_per_pixel=3; |
654 | 6.74k | break; |
655 | 2.34k | } |
656 | 1.13k | default: |
657 | 1.13k | { |
658 | 1.13k | } |
659 | 17.2k | } |
660 | 17.2k | } |
661 | | |
662 | 25.2k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Dimensions: %lux%lu", |
663 | 25.2k | image->columns,image->rows); |
664 | 25.2k | if ((image->columns == 0) || (image->rows == 0)) |
665 | 17.9k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
666 | | |
667 | 17.9k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Max Value: %u", |
668 | 17.9k | max_value); |
669 | 17.9k | if ((max_value == 0) || (max_value > 4294967295U)) |
670 | 17.7k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
671 | | |
672 | 17.7k | if ((format == XV_332_Format) && (max_value != 255)) |
673 | 17.3k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
674 | | |
675 | 17.3k | bits_per_sample=0; |
676 | 17.3k | if (max_value <= 1) |
677 | 7.77k | bits_per_sample=1; |
678 | 9.54k | else if (max_value <= 255U) |
679 | 5.66k | bits_per_sample=8; |
680 | 3.88k | else if (max_value <= 65535U) |
681 | 2.21k | bits_per_sample=16; |
682 | 1.67k | else if (max_value <= 4294967295U) |
683 | 1.67k | bits_per_sample=32; |
684 | | |
685 | 17.3k | image->depth=Min(bits_per_sample,QuantumDepth); |
686 | | |
687 | 17.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image Depth: %u", |
688 | 17.3k | image->depth); |
689 | 17.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Samples Per Pixel: %u", |
690 | 17.3k | samples_per_pixel); |
691 | 17.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Bits Per Sample: %u", |
692 | 17.3k | bits_per_sample); |
693 | | |
694 | 17.3k | if (EOFBlob(image)) |
695 | 4.81k | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
696 | 17.3k | image->filename); |
697 | | |
698 | 17.3k | if ((1 == samples_per_pixel) && (max_value < MaxColormapSize) && |
699 | 17.3k | ((size_t) image->columns*image->rows >= max_value)) |
700 | 7.23k | { |
701 | 7.23k | image->storage_class=PseudoClass; |
702 | 7.23k | image->colors= |
703 | 7.23k | max_value >= MaxColormapSize ? MaxColormapSize : max_value+1; |
704 | 7.23k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Colors: %u", |
705 | 7.23k | image->colors); |
706 | 7.23k | } |
707 | 17.3k | number_pixels=MagickArraySize(image->columns,image->rows); |
708 | 17.3k | if (number_pixels == 0) |
709 | 17.3k | ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image); |
710 | 17.3k | if (image->storage_class == PseudoClass) |
711 | 7.23k | { |
712 | | /* |
713 | | Create colormap. |
714 | | */ |
715 | 7.23k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
716 | 7.23k | "Allocating colormap with %u colors", |
717 | 7.23k | image->colors); |
718 | 7.23k | if (!AllocateImageColormap(image,image->colors)) |
719 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed, |
720 | 7.23k | image); |
721 | 7.23k | if ((format == XV_332_Format) && (image->colors == 256)) |
722 | 97 | { |
723 | | /* |
724 | | Initialize 332 colormap. |
725 | | */ |
726 | 97 | i=0; |
727 | 873 | for (pixel.red=0; pixel.red < 8; pixel.red++) |
728 | 6.98k | for (pixel.green=0; pixel.green < 8; pixel.green++) |
729 | 31.0k | for (pixel.blue=0; pixel.blue < 4; pixel.blue++) |
730 | 24.8k | { |
731 | 24.8k | image->colormap[i].red=(Quantum) |
732 | 24.8k | (((double) MaxRGB*pixel.red)/0x07+0.5); |
733 | 24.8k | image->colormap[i].green=(Quantum) |
734 | 24.8k | (((double) MaxRGB*pixel.green)/0x07+0.5); |
735 | 24.8k | image->colormap[i].blue=(Quantum) |
736 | 24.8k | (((double) MaxRGB*pixel.blue)/0x03+0.5); |
737 | 24.8k | i++; |
738 | 24.8k | } |
739 | 97 | } |
740 | 7.23k | } |
741 | 17.3k | if (image_info->ping && (image_info->subrange != 0)) |
742 | 0 | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
743 | 0 | break; |
744 | | |
745 | 17.3k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
746 | 16.3k | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
747 | | |
748 | | /* |
749 | | Convert PNM pixels to runlength-encoded MIFF packets. |
750 | | */ |
751 | 16.3k | switch (format) |
752 | 16.3k | { |
753 | 969 | case PBM_ASCII_Format: |
754 | 969 | { |
755 | | /* |
756 | | Convert PBM image to pixel packets. |
757 | | */ |
758 | 969 | register unsigned long |
759 | 969 | x; |
760 | | |
761 | 969 | register PixelPacket |
762 | 969 | *q; |
763 | | |
764 | 969 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
765 | 969 | "Reading %s pixel data",PNMSubformatToString(format)); |
766 | 10.1k | for (y=0; y < (long) image->rows; y++) |
767 | 10.0k | { |
768 | 10.0k | q=SetImagePixels(image,0,y,image->columns,1); |
769 | 10.0k | if (q == (PixelPacket *) NULL) |
770 | 0 | break; |
771 | 10.0k | indexes=AccessMutableIndexes(image); |
772 | 25.2k | for (x=0; x < image->columns; x++) |
773 | 16.0k | { |
774 | 16.0k | index=!PNMInteger(image,2); |
775 | 16.0k | if (EOFBlob(image)) |
776 | 801 | break; |
777 | 15.2k | VerifyColormapIndex(image,index); |
778 | 15.2k | indexes[x]=index; |
779 | 15.2k | *q++=image->colormap[index]; |
780 | 15.2k | } |
781 | 10.0k | if (!SyncImagePixels(image)) |
782 | 0 | break; |
783 | 10.0k | if (image->previous == (Image *) NULL) |
784 | 10.0k | if (QuantumTick(y,image->rows)) |
785 | 6.27k | if (!MagickMonitorFormatted(y,image->rows,exception, |
786 | 6.27k | LoadImageText,image->filename, |
787 | 6.27k | image->columns,image->rows)) |
788 | 0 | break; |
789 | 10.0k | if (EOFBlob(image)) |
790 | 801 | break; |
791 | 10.0k | } |
792 | 969 | image->is_grayscale=MagickTrue; |
793 | 969 | image->is_monochrome=MagickTrue; |
794 | 969 | if (EOFBlob(image)) |
795 | 801 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
796 | 969 | image->filename); |
797 | 969 | break; |
798 | 0 | } |
799 | 2.42k | case PGM_ASCII_Format: |
800 | 2.42k | { |
801 | | /* |
802 | | Convert PGM image to pixel packets. |
803 | | */ |
804 | 2.42k | register unsigned long |
805 | 2.42k | x; |
806 | | |
807 | 2.42k | register PixelPacket |
808 | 2.42k | *q; |
809 | | |
810 | 2.42k | unsigned long |
811 | 2.42k | intensity; |
812 | | |
813 | 2.42k | MagickBool |
814 | 2.42k | is_grayscale, |
815 | 2.42k | is_monochrome; |
816 | | |
817 | 2.42k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
818 | 2.42k | "Reading %s pixel data",PNMSubformatToString(format)); |
819 | 2.42k | is_grayscale=MagickTrue; |
820 | 2.42k | is_monochrome=MagickTrue; |
821 | 11.4k | for (y=0; y < (long) image->rows; y++) |
822 | 11.3k | { |
823 | 11.3k | q=SetImagePixels(image,0,y,image->columns,1); |
824 | 11.3k | if (q == (PixelPacket *) NULL) |
825 | 0 | break; |
826 | 11.3k | if (image->storage_class == PseudoClass) |
827 | 7.52k | { |
828 | | /* |
829 | | PseudoClass |
830 | | */ |
831 | 7.52k | indexes=AccessMutableIndexes(image); |
832 | 18.4k | for (x=0; x < image->columns; x++) |
833 | 12.1k | { |
834 | 12.1k | intensity=PNMInteger(image,10); |
835 | 12.1k | ValidateScalingIndex(image, intensity, max_value); |
836 | 11.8k | if (EOFBlob(image)) |
837 | 983 | break; |
838 | 10.8k | index=intensity; |
839 | 10.8k | VerifyColormapIndex(image,index); |
840 | 10.8k | indexes[x]=index; |
841 | 10.8k | *q=image->colormap[index]; |
842 | 10.8k | is_monochrome &= IsMonochrome(*q); |
843 | 10.8k | q++; |
844 | 10.8k | } |
845 | 7.52k | } |
846 | 3.82k | else |
847 | 3.82k | { |
848 | | /* |
849 | | DirectClass |
850 | | */ |
851 | 11.6k | for (x=0; x < image->columns; x++) |
852 | 8.83k | { |
853 | 8.83k | intensity=PNMInteger(image,10); |
854 | 8.83k | ValidateScalingIndex(image, intensity, max_value); |
855 | 8.66k | if (EOFBlob(image)) |
856 | 850 | break; |
857 | 7.81k | intensity=ScaleAnyToQuantum(intensity, max_value); |
858 | 7.81k | q->red=q->green=q->blue=intensity; |
859 | 7.81k | is_monochrome &= IsMonochrome(*q); |
860 | 7.81k | q++; |
861 | 7.81k | } |
862 | 3.82k | } |
863 | 10.8k | if (EOFBlob(image)) |
864 | 1.83k | break; |
865 | 9.04k | if (!SyncImagePixels(image)) |
866 | 0 | break; |
867 | 9.04k | if (image->previous == (Image *) NULL) |
868 | 9.04k | if (QuantumTick(y,image->rows)) |
869 | 6.27k | if (!MagickMonitorFormatted(y,image->rows,exception, |
870 | 6.27k | LoadImageText,image->filename, |
871 | 6.27k | image->columns,image->rows)) |
872 | 0 | break; |
873 | 9.04k | } |
874 | 1.94k | image->is_monochrome=is_monochrome; |
875 | 1.94k | image->is_grayscale=is_grayscale; |
876 | 1.94k | if (EOFBlob(image)) |
877 | 1.83k | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
878 | 1.94k | image->filename); |
879 | 1.94k | break; |
880 | 2.42k | } |
881 | 2.25k | case PPM_ASCII_Format: |
882 | 2.25k | { |
883 | | /* |
884 | | Convert PNM image to pixel packets. |
885 | | */ |
886 | 2.25k | register unsigned long |
887 | 2.25k | x; |
888 | | |
889 | 2.25k | register PixelPacket |
890 | 2.25k | *q; |
891 | | |
892 | 2.25k | MagickBool |
893 | 2.25k | is_grayscale, |
894 | 2.25k | is_monochrome; |
895 | | |
896 | 2.25k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
897 | 2.25k | "Reading %s pixel data",PNMSubformatToString(format)); |
898 | 2.25k | is_grayscale=MagickTrue; |
899 | 2.25k | is_monochrome=MagickTrue; |
900 | 9.70k | for (y=0; y < (long) image->rows; y++) |
901 | 9.61k | { |
902 | 9.61k | q=SetImagePixels(image,0,y,image->columns,1); |
903 | 9.61k | if (q == (PixelPacket *) NULL) |
904 | 0 | break; |
905 | 22.5k | for (x=0; x < image->columns; x++) |
906 | 15.0k | { |
907 | 15.0k | pixel.red=PNMInteger(image,10); |
908 | 15.0k | pixel.green=PNMInteger(image,10); |
909 | 15.0k | pixel.blue=PNMInteger(image,10); |
910 | 15.0k | if (EOFBlob(image)) |
911 | 1.58k | break; |
912 | 13.5k | ValidateScalingPixel(image, pixel, max_value); |
913 | 12.9k | pixel.red=ScaleAnyToQuantum(pixel.red, max_value); |
914 | 12.9k | pixel.green=ScaleAnyToQuantum(pixel.green, max_value); |
915 | 12.9k | pixel.blue=ScaleAnyToQuantum(pixel.blue, max_value); |
916 | 12.9k | q->red=(Quantum) pixel.red; |
917 | 12.9k | q->green=(Quantum) pixel.green; |
918 | 12.9k | q->blue=(Quantum) pixel.blue; |
919 | 12.9k | is_monochrome &= IsMonochrome(*q); |
920 | 12.9k | is_grayscale &= IsGray(*q); |
921 | 12.9k | q++; |
922 | 12.9k | } |
923 | 9.02k | if (EOFBlob(image)) |
924 | 1.58k | break; |
925 | 7.44k | if (!SyncImagePixels(image)) |
926 | 0 | break; |
927 | 7.44k | if (image->previous == (Image *) NULL) |
928 | 7.44k | if (QuantumTick(y,image->rows)) |
929 | 4.64k | if (!MagickMonitorFormatted(y,image->rows,exception, |
930 | 4.64k | LoadImageText,image->filename, |
931 | 4.64k | image->columns,image->rows)) |
932 | 0 | break; |
933 | 7.44k | } |
934 | 1.67k | image->is_monochrome=is_monochrome; |
935 | 1.67k | image->is_grayscale=is_grayscale; |
936 | 1.67k | if (EOFBlob(image)) |
937 | 1.58k | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
938 | 1.67k | image->filename); |
939 | 1.67k | break; |
940 | 2.25k | } |
941 | 2.29k | case PBM_RAW_Format: |
942 | 3.84k | case PGM_RAW_Format: |
943 | 6.58k | case PPM_RAW_Format: |
944 | 10.5k | case PAM_Format: |
945 | 10.6k | case XV_332_Format: |
946 | 10.6k | { |
947 | | /* |
948 | | Convert PBM/PGM/PPM/PAM/XV raw raster image to pixel packets. |
949 | | */ |
950 | 10.6k | ImportPixelAreaOptions |
951 | 10.6k | import_options; |
952 | | |
953 | 10.6k | QuantumType |
954 | 10.6k | quantum_type; |
955 | | |
956 | 10.6k | size_t |
957 | 10.6k | bytes_per_row; |
958 | | |
959 | 10.6k | MagickBool |
960 | 10.6k | check_pixels, |
961 | 10.6k | is_grayscale, |
962 | 10.6k | is_monochrome, |
963 | 10.6k | use_scaling; |
964 | | |
965 | 10.6k | unsigned long |
966 | 10.6k | max_value_given_bits, |
967 | 10.6k | row_count=0; |
968 | | |
969 | 10.6k | ThreadViewDataSet |
970 | 10.6k | *scanline_set; |
971 | | |
972 | 10.6k | double |
973 | 10.6k | sample_scale; |
974 | | |
975 | 10.6k | unsigned int |
976 | 10.6k | sample_max; |
977 | | |
978 | | #if defined(HAVE_OPENMP) |
979 | | int |
980 | | pnm_read_threads; |
981 | | #endif |
982 | | |
983 | 10.6k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
984 | 10.6k | "Reading %s pixel data",PNMSubformatToString(format)); |
985 | | |
986 | 10.6k | ImportPixelAreaOptionsInit(&import_options); |
987 | | |
988 | 10.6k | check_pixels=MagickTrue; |
989 | 10.6k | is_grayscale=MagickTrue; |
990 | 10.6k | is_monochrome=MagickTrue; |
991 | | |
992 | | /* |
993 | | Deduce correct import parameters. |
994 | | */ |
995 | 10.6k | quantum_type=UndefinedQuantum; |
996 | 10.6k | import_options.grayscale_miniswhite=MagickFalse; |
997 | 10.6k | max_value_given_bits=MaxValueGivenBits(bits_per_sample); |
998 | 10.6k | if (max_value_given_bits == 0UL) |
999 | 0 | { |
1000 | 0 | ThrowException(exception,CorruptImageError,ImproperImageHeader, |
1001 | 0 | image->filename); |
1002 | 0 | break; |
1003 | 0 | } |
1004 | 10.6k | sample_max=RoundDoubleToQuantum((MaxRGBDouble*max_value)/max_value_given_bits); |
1005 | 10.6k | if (sample_max == 0U) |
1006 | 0 | { |
1007 | 0 | ThrowException(exception,CorruptImageError,ImproperImageHeader, |
1008 | 0 | image->filename); |
1009 | 0 | break; |
1010 | 0 | } |
1011 | 10.6k | sample_scale=MaxRGBDouble/sample_max; |
1012 | 10.6k | use_scaling=(MaxRGB != sample_max); |
1013 | 10.6k | bytes_per_row=0; |
1014 | | |
1015 | 10.6k | if (1 == samples_per_pixel) |
1016 | 4.80k | { |
1017 | 4.80k | if (1 == bits_per_sample) |
1018 | 2.73k | { |
1019 | | /* PBM */ |
1020 | 2.73k | import_options.grayscale_miniswhite=MagickTrue; |
1021 | 2.73k | quantum_type=GrayQuantum; |
1022 | 2.73k | } |
1023 | 2.06k | else |
1024 | 2.06k | { |
1025 | | /* PGM & XV_332 */ |
1026 | 2.06k | if ((XV_332_Format == format) && (image->storage_class == PseudoClass)) |
1027 | 97 | { |
1028 | 97 | quantum_type=IndexQuantum; |
1029 | 97 | } |
1030 | 1.96k | else |
1031 | 1.96k | { |
1032 | 1.96k | quantum_type=GrayQuantum; |
1033 | 1.96k | } |
1034 | 2.06k | } |
1035 | 4.80k | } |
1036 | 5.84k | else if (2 == samples_per_pixel && image->matte) |
1037 | 650 | { |
1038 | 650 | quantum_type=GrayAlphaQuantum; |
1039 | 650 | } |
1040 | 5.19k | else if (3 == samples_per_pixel) |
1041 | 2.83k | { |
1042 | | /* PPM */ |
1043 | 2.83k | quantum_type=RGBQuantum; |
1044 | 2.83k | } |
1045 | 2.35k | else if (4 == samples_per_pixel) |
1046 | 1.24k | { |
1047 | 1.24k | if (CMYKColorspace == image->colorspace) |
1048 | 655 | quantum_type=CMYKQuantum; |
1049 | 594 | else |
1050 | 594 | quantum_type=RGBAQuantum; |
1051 | 1.24k | } |
1052 | 1.11k | else if (5 == samples_per_pixel) |
1053 | 607 | { |
1054 | 607 | if (CMYKColorspace == image->colorspace) |
1055 | 593 | quantum_type=CMYKAQuantum; |
1056 | 607 | } |
1057 | | |
1058 | 10.6k | if (image->logging) |
1059 | 10.6k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1060 | 10.6k | "Import Quantum Type: %s", |
1061 | 10.6k | QuantumTypeToString(quantum_type)); |
1062 | | |
1063 | 10.6k | samples_per_pixel=MagickGetQuantumSamplesPerPixel(quantum_type); |
1064 | 10.6k | if (image->logging) |
1065 | 10.6k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1066 | 10.6k | "Samples/Pixel: %u", samples_per_pixel); |
1067 | | |
1068 | 10.6k | if (1 == bits_per_sample) |
1069 | 5.38k | { |
1070 | | /* bytes_per_row=(((size_t) image->columns*samples_per_pixel+7) >> 3); */ |
1071 | 5.38k | bytes_per_row=MagickArraySize(image->columns,samples_per_pixel); |
1072 | 5.38k | if (bytes_per_row) |
1073 | 5.16k | bytes_per_row += 7; |
1074 | 5.38k | if (bytes_per_row) |
1075 | 5.16k | bytes_per_row >>= 3; |
1076 | 5.38k | } |
1077 | 5.25k | else |
1078 | 5.25k | { |
1079 | 5.25k | bytes_per_row=MagickArraySize((((size_t) bits_per_sample+7)/8)* |
1080 | 5.25k | samples_per_pixel,image->columns); |
1081 | 5.25k | } |
1082 | | |
1083 | 10.6k | if (image->logging) |
1084 | 10.6k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1085 | 10.6k | "Bytes/Row: %" MAGICK_SIZE_T_F "u", |
1086 | 10.6k | (MAGICK_SIZE_T) bytes_per_row); |
1087 | | |
1088 | 10.6k | if (1 == samples_per_pixel) |
1089 | 4.80k | { |
1090 | 4.80k | check_pixels=MagickFalse; |
1091 | 4.80k | } |
1092 | 10.6k | if (GrayQuantum) |
1093 | 10.6k | { |
1094 | 10.6k | if (1 == bits_per_sample) |
1095 | 5.38k | { |
1096 | 5.38k | is_grayscale=MagickTrue; |
1097 | 5.38k | is_monochrome=MagickTrue; |
1098 | 5.38k | } |
1099 | 5.25k | else |
1100 | 5.25k | { |
1101 | 5.25k | is_grayscale=MagickTrue; |
1102 | 5.25k | is_monochrome=MagickFalse; |
1103 | 5.25k | } |
1104 | 10.6k | } |
1105 | | |
1106 | | /* Validate file size before allocating memory */ |
1107 | 10.6k | if (BlobIsSeekable(image)) |
1108 | 10.6k | { |
1109 | 10.6k | const magick_off_t file_size = GetBlobSize(image); |
1110 | 10.6k | const magick_off_t current_offset = TellBlob(image); |
1111 | 10.6k | if ((file_size > 0) && |
1112 | 10.6k | (current_offset > 0) && |
1113 | 10.6k | (file_size > current_offset)) |
1114 | 8.05k | { |
1115 | 8.05k | const magick_off_t remaining = file_size-current_offset; |
1116 | 8.05k | const magick_off_t needed = (magick_off_t) image->rows * |
1117 | 8.05k | (magick_off_t) bytes_per_row; |
1118 | 8.05k | if ((remaining < (magick_off_t) bytes_per_row) || |
1119 | 8.05k | (remaining < needed)) |
1120 | 228 | { |
1121 | 228 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
1122 | 228 | image->filename); |
1123 | 228 | break; |
1124 | 228 | } |
1125 | 8.05k | } |
1126 | 10.6k | } |
1127 | | |
1128 | | #if defined(HAVE_OPENMP) |
1129 | | pnm_read_threads = PNMReadThreads(image,bytes_per_row); |
1130 | | if (image->logging) |
1131 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1132 | | "Using %d thread%s...", pnm_read_threads, |
1133 | | pnm_read_threads > 1 ? "s" : ""); |
1134 | | #endif |
1135 | 10.4k | scanline_set=AllocateThreadViewDataArray(image,exception,bytes_per_row,1); |
1136 | 10.4k | if (scanline_set == (ThreadViewDataSet *) NULL) |
1137 | 9.89k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1138 | | #if PNMReadUseOpenMP |
1139 | | # if defined(TUNE_OPENMP) |
1140 | | # pragma omp parallel for schedule(runtime) shared(is_grayscale,is_monochrome,row_count,status) |
1141 | | # else |
1142 | | # pragma omp parallel for num_threads(pnm_read_threads) schedule(static,1) shared(is_grayscale,is_monochrome,row_count,status) |
1143 | | # endif |
1144 | | #endif |
1145 | 833k | for (y=0; y < (long) image->rows; y++) |
1146 | 823k | { |
1147 | 823k | register unsigned long |
1148 | 823k | x; |
1149 | | |
1150 | 823k | register PixelPacket |
1151 | 823k | *q = (PixelPacket *) NULL; |
1152 | | |
1153 | 823k | void |
1154 | 823k | *pixels; |
1155 | | |
1156 | 823k | MagickBool |
1157 | 823k | thread_status; |
1158 | | |
1159 | 823k | MagickBool |
1160 | 823k | thread_is_grayscale, |
1161 | 823k | thread_is_monochrome; |
1162 | | |
1163 | 823k | unsigned long |
1164 | 823k | thread_row_count; |
1165 | | |
1166 | 823k | ImportPixelAreaInfo |
1167 | 823k | import_info; |
1168 | | |
1169 | | #if PNMReadUseOpenMP |
1170 | | # pragma omp critical (GM_ReadPNMImage) |
1171 | | #endif |
1172 | 823k | thread_status=status; |
1173 | 823k | if (thread_status == MagickFail) |
1174 | 196k | continue; |
1175 | | |
1176 | 627k | pixels=AccessThreadViewData(scanline_set); |
1177 | | |
1178 | | #if PNMReadUseOpenMP |
1179 | | # pragma omp critical (GM_ReadPNMImage) |
1180 | | #endif |
1181 | 627k | { |
1182 | 627k | thread_is_grayscale=is_grayscale; |
1183 | 627k | thread_is_monochrome=is_monochrome; |
1184 | | |
1185 | 627k | if (ReadBlobZC(image,bytes_per_row,&pixels) != bytes_per_row) |
1186 | 2.16k | thread_status=MagickFail; |
1187 | | |
1188 | 627k | thread_row_count=row_count; |
1189 | 627k | row_count++; |
1190 | | |
1191 | 627k | if (image->previous == (Image *) NULL) |
1192 | 627k | if (QuantumTick(thread_row_count,image->rows)) |
1193 | 171k | if (!MagickMonitorFormatted(thread_row_count,image->rows, |
1194 | 171k | exception,LoadImageText, |
1195 | 171k | image->filename, |
1196 | 171k | image->columns,image->rows)) |
1197 | 0 | thread_status=MagickFail; |
1198 | 627k | } |
1199 | | |
1200 | 627k | if (thread_status != MagickFail) |
1201 | 625k | if ((q=SetImagePixels(image,0,thread_row_count,image->columns,1)) == |
1202 | 625k | (PixelPacket *) NULL) |
1203 | 0 | thread_status=MagickFail; |
1204 | | |
1205 | 627k | if (thread_status != MagickFail) |
1206 | 625k | if (!ImportImagePixelArea(image,quantum_type,bits_per_sample,pixels, |
1207 | 625k | &import_options,&import_info)) |
1208 | 0 | thread_status=MagickFail; |
1209 | | /* |
1210 | | Scale sub-ranged pixels up to full range if necessary |
1211 | | */ |
1212 | 627k | if ((thread_status != MagickFail) && (use_scaling)) |
1213 | 6.85M | for (x=0; x < image->columns; x++) |
1214 | 6.75M | { |
1215 | 6.75M | SetRedSample(&q[x], |
1216 | 6.75M | RoundDoubleToQuantum(sample_scale* |
1217 | 6.75M | GetRedSample(&q[x]))); |
1218 | 6.75M | SetGreenSample(&q[x], |
1219 | 6.75M | RoundDoubleToQuantum(sample_scale* |
1220 | 6.75M | GetGreenSample(&q[x]))); |
1221 | 6.75M | SetBlueSample(&q[x], |
1222 | 6.75M | RoundDoubleToQuantum(sample_scale* |
1223 | 6.75M | GetBlueSample(&q[x]))); |
1224 | 6.75M | if (image->matte) |
1225 | 711k | SetOpacitySample(&q[x], |
1226 | 6.75M | MaxRGB- |
1227 | 6.75M | RoundDoubleToQuantum(sample_scale* |
1228 | 6.75M | (MaxRGB- |
1229 | 6.75M | GetOpacitySample(&q[x])))); |
1230 | 6.75M | } |
1231 | | /* |
1232 | | For a DirectClass image, check all pixels for |
1233 | | gray/monochrome status since this format is often |
1234 | | used for input from Ghostscript, which may output |
1235 | | bilevel or gray in an RGB format. It is easier to |
1236 | | check now while the pixels are still "hot" in |
1237 | | memory. |
1238 | | */ |
1239 | 627k | if (thread_status != MagickFail) |
1240 | 625k | if (check_pixels) |
1241 | 54.7k | if (thread_is_grayscale || thread_is_monochrome) |
1242 | 208k | for (x=0; x < image->columns; x++) |
1243 | 194k | { |
1244 | 194k | thread_is_grayscale = thread_is_grayscale && IsGray(q[x]); |
1245 | 194k | thread_is_monochrome = thread_is_monochrome && IsMonochrome(q[x]); |
1246 | 194k | if (!thread_is_grayscale && !thread_is_monochrome) |
1247 | 2.43k | break; |
1248 | 194k | } |
1249 | | |
1250 | 627k | if (thread_status != MagickFail) |
1251 | 625k | if (!SyncImagePixels(image)) |
1252 | 0 | thread_status=MagickFail; |
1253 | | |
1254 | | #if PNMReadUseOpenMP |
1255 | | # pragma omp critical (GM_ReadPNMImage) |
1256 | | #endif |
1257 | 627k | { |
1258 | 627k | if (thread_status == MagickFail) |
1259 | 2.16k | status=MagickFail; |
1260 | | |
1261 | 627k | if (!thread_is_grayscale) |
1262 | 40.8k | is_grayscale=thread_is_grayscale; |
1263 | | |
1264 | 627k | if (!thread_is_monochrome) |
1265 | 128k | is_monochrome=thread_is_monochrome; |
1266 | 627k | } |
1267 | 627k | } |
1268 | 9.89k | DestroyThreadViewDataSet(scanline_set); |
1269 | 9.89k | image->is_monochrome=is_monochrome; |
1270 | 9.89k | image->is_grayscale=is_grayscale; |
1271 | 9.89k | if ((status == MagickFail) && (image->exception.severity)) |
1272 | 95 | CopyException(exception,&image->exception); |
1273 | 9.89k | if (EOFBlob(image)) |
1274 | 7.49k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
1275 | 7.49k | break; |
1276 | 9.89k | } |
1277 | 82 | default: |
1278 | 82 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1279 | 16.3k | } |
1280 | 12.3k | StopTimer(&image->timer); |
1281 | 12.3k | if (status ==MagickFail) |
1282 | 0 | break; |
1283 | | /* |
1284 | | Proceed to next image. |
1285 | | */ |
1286 | 12.3k | if (image_info->subrange != 0) |
1287 | 12.3k | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
1288 | 12.3k | break; |
1289 | 0 | if ((format == PBM_ASCII_Format) || (format == PGM_ASCII_Format) || (format == PPM_ASCII_Format)) |
1290 | 0 | do |
1291 | 0 | { |
1292 | | /* |
1293 | | Skip to end of line. |
1294 | | */ |
1295 | 0 | count=ReadBlob(image,1,&c); |
1296 | 0 | if (count == 0) |
1297 | 0 | break; |
1298 | 0 | } while (c != '\n'); |
1299 | 0 | count=ReadBlob(image,1,&c); |
1300 | 0 | if ((count != 0) && (c == 'P')) |
1301 | 0 | { |
1302 | | /* |
1303 | | Allocate next image structure. |
1304 | | */ |
1305 | 0 | AllocateNextImage(image_info,image); |
1306 | 0 | if (image->next == (Image *) NULL) |
1307 | 0 | { |
1308 | 0 | DestroyImageList(image); |
1309 | 0 | return((Image *) NULL); |
1310 | 0 | } |
1311 | 0 | image=SyncNextImageInList(image); |
1312 | 0 | if (!MagickMonitorFormatted(TellBlob(image),GetBlobSize(image), |
1313 | 0 | exception,LoadImagesText, |
1314 | 0 | image->filename)) |
1315 | 0 | break; |
1316 | 0 | } |
1317 | 0 | } while ((count != 0) && (c == 'P')); |
1318 | 12.3k | while (image->previous != (Image *) NULL) |
1319 | 0 | image=image->previous; |
1320 | 12.3k | CloseBlob(image); |
1321 | 12.3k | return(image); |
1322 | 25.3k | } |
1323 | | |
1324 | | /* |
1325 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1326 | | % % |
1327 | | % % |
1328 | | % % |
1329 | | % R e g i s t e r P N M I m a g e % |
1330 | | % % |
1331 | | % % |
1332 | | % % |
1333 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1334 | | % |
1335 | | % Method RegisterPNMImage adds attributes for the PNM image format to |
1336 | | % the list of supported formats. The attributes include the image format |
1337 | | % tag, a method to read and/or write the format, whether the format |
1338 | | % supports the saving of more than one frame to the same file or blob, |
1339 | | % whether the format supports native in-memory I/O, and a brief |
1340 | | % description of the format. |
1341 | | % |
1342 | | % The format of the RegisterPNMImage method is: |
1343 | | % |
1344 | | % RegisterPNMImage(void) |
1345 | | % |
1346 | | */ |
1347 | | ModuleExport void RegisterPNMImage(void) |
1348 | 10 | { |
1349 | 10 | MagickInfo |
1350 | 10 | *entry; |
1351 | | |
1352 | 10 | entry=SetMagickInfo("P7"); |
1353 | 10 | entry->decoder=(DecoderHandler) ReadPNMImage; |
1354 | 10 | entry->encoder=(EncoderHandler) WritePNMImage; |
1355 | 10 | entry->description="Xv thumbnail format"; |
1356 | 10 | entry->extension_treatment=IgnoreExtensionTreatment; |
1357 | 10 | entry->module="PNM"; |
1358 | 10 | (void) RegisterMagickInfo(entry); |
1359 | | |
1360 | 10 | entry=SetMagickInfo("PAM"); |
1361 | 10 | entry->decoder=(DecoderHandler) ReadPNMImage; |
1362 | 10 | entry->encoder=(EncoderHandler) WritePNMImage; |
1363 | 10 | entry->description="Portable Arbitrary Map format"; |
1364 | 10 | entry->module="PNM"; |
1365 | 10 | entry->coder_class=PrimaryCoderClass; |
1366 | 10 | (void) RegisterMagickInfo(entry); |
1367 | | |
1368 | 10 | entry=SetMagickInfo("PBM"); |
1369 | 10 | entry->decoder=(DecoderHandler) ReadPNMImage; |
1370 | 10 | entry->encoder=(EncoderHandler) WritePNMImage; |
1371 | 10 | entry->description="Portable bitmap format (black/white)"; |
1372 | 10 | entry->module="PNM"; |
1373 | 10 | entry->coder_class=PrimaryCoderClass; |
1374 | 10 | (void) RegisterMagickInfo(entry); |
1375 | | |
1376 | 10 | entry=SetMagickInfo("PGM"); |
1377 | 10 | entry->decoder=(DecoderHandler) ReadPNMImage; |
1378 | 10 | entry->encoder=(EncoderHandler) WritePNMImage; |
1379 | 10 | entry->description="Portable graymap format (gray scale)"; |
1380 | 10 | entry->module="PNM"; |
1381 | 10 | entry->coder_class=PrimaryCoderClass; |
1382 | 10 | (void) RegisterMagickInfo(entry); |
1383 | | |
1384 | 10 | entry=SetMagickInfo("PNM"); |
1385 | 10 | entry->decoder=(DecoderHandler) ReadPNMImage; |
1386 | 10 | entry->encoder=(EncoderHandler) WritePNMImage; |
1387 | 10 | entry->magick=(MagickHandler) IsPNM; |
1388 | 10 | entry->description="Portable anymap"; |
1389 | 10 | entry->module="PNM"; |
1390 | 10 | entry->coder_class=PrimaryCoderClass; |
1391 | 10 | (void) RegisterMagickInfo(entry); |
1392 | | |
1393 | 10 | entry=SetMagickInfo("PPM"); |
1394 | 10 | entry->decoder=(DecoderHandler) ReadPNMImage; |
1395 | 10 | entry->encoder=(EncoderHandler) WritePNMImage; |
1396 | 10 | entry->description="Portable pixmap format (color)"; |
1397 | 10 | entry->module="PNM"; |
1398 | 10 | entry->coder_class=PrimaryCoderClass; |
1399 | 10 | (void) RegisterMagickInfo(entry); |
1400 | | |
1401 | 10 | } |
1402 | | |
1403 | | /* |
1404 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1405 | | % % |
1406 | | % % |
1407 | | % % |
1408 | | % U n r e g i s t e r P N M I m a g e % |
1409 | | % % |
1410 | | % % |
1411 | | % % |
1412 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1413 | | % |
1414 | | % Method UnregisterPNMImage removes format registrations made by the |
1415 | | % PNM module from the list of supported formats. |
1416 | | % |
1417 | | % The format of the UnregisterPNMImage method is: |
1418 | | % |
1419 | | % UnregisterPNMImage(void) |
1420 | | % |
1421 | | */ |
1422 | | ModuleExport void UnregisterPNMImage(void) |
1423 | 0 | { |
1424 | 0 | (void) UnregisterMagickInfo("P7"); |
1425 | 0 | (void) UnregisterMagickInfo("PAM"); |
1426 | 0 | (void) UnregisterMagickInfo("PBM"); |
1427 | 0 | (void) UnregisterMagickInfo("PGM"); |
1428 | 0 | (void) UnregisterMagickInfo("PNM"); |
1429 | 0 | (void) UnregisterMagickInfo("PPM"); |
1430 | 0 | } |
1431 | | |
1432 | | /* |
1433 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1434 | | % % |
1435 | | % % |
1436 | | % % |
1437 | | % W r i t e P N M I m a g e % |
1438 | | % % |
1439 | | % % |
1440 | | % % |
1441 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1442 | | % |
1443 | | % Procedure WritePNMImage writes an image to a file in the PNM rasterfile |
1444 | | % format. |
1445 | | % |
1446 | | % The format of the WritePNMImage method is: |
1447 | | % |
1448 | | % unsigned int WritePNMImage(const ImageInfo *image_info,Image *image) |
1449 | | % |
1450 | | % A description of each parameter follows. |
1451 | | % |
1452 | | % o status: Method WritePNMImage return True if the image is written. |
1453 | | % False is returned is there is a memory shortage or if the image file |
1454 | | % fails to write. |
1455 | | % |
1456 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
1457 | | % |
1458 | | % o image: A pointer to an Image structure. |
1459 | | % |
1460 | | % |
1461 | | */ |
1462 | | static const char lut_255[][4] = |
1463 | | { |
1464 | | "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", |
1465 | | "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", |
1466 | | "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", |
1467 | | "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", |
1468 | | "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", |
1469 | | "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", |
1470 | | "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", |
1471 | | "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", |
1472 | | "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", |
1473 | | "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", |
1474 | | "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", |
1475 | | "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", |
1476 | | "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", |
1477 | | "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", |
1478 | | "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", |
1479 | | "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", |
1480 | | "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", |
1481 | | "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", |
1482 | | "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", |
1483 | | "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", |
1484 | | "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", |
1485 | | "248", "249", "250", "251", "252", "253", "254", "255" |
1486 | | }; |
1487 | | |
1488 | 0 | #define AppendUnsignedCharValueToString(j,buffer,value) \ |
1489 | 0 | { \ |
1490 | 0 | const char *lut_entry=lut_255[value]; \ |
1491 | 0 | while(*lut_entry != '\0') \ |
1492 | 0 | { \ |
1493 | 0 | buffer[j++]=*lut_entry; \ |
1494 | 0 | lut_entry++; \ |
1495 | 0 | } \ |
1496 | 0 | } |
1497 | | |
1498 | | static unsigned int WritePNMImage(const ImageInfo *image_info,Image *image) |
1499 | 6.87k | { |
1500 | 6.87k | char |
1501 | 6.87k | buffer[MaxTextExtent]; |
1502 | | |
1503 | 6.87k | const ImageAttribute |
1504 | 6.87k | *attribute; |
1505 | | |
1506 | 6.87k | IndexPacket |
1507 | 6.87k | index; |
1508 | | |
1509 | 6.87k | PNMSubformat |
1510 | 6.87k | format; |
1511 | | |
1512 | 6.87k | unsigned int |
1513 | 6.87k | depth; |
1514 | | |
1515 | 6.87k | unsigned long |
1516 | 6.87k | y; |
1517 | | |
1518 | 6.87k | register const PixelPacket |
1519 | 6.87k | *p; |
1520 | | |
1521 | 6.87k | register const IndexPacket |
1522 | 6.87k | *indexes; |
1523 | | |
1524 | 6.87k | register unsigned long |
1525 | 6.87k | i, |
1526 | 6.87k | x; |
1527 | | |
1528 | 6.87k | unsigned int |
1529 | 6.87k | scene, |
1530 | 6.87k | status; |
1531 | | |
1532 | 6.87k | size_t |
1533 | 6.87k | image_list_length; |
1534 | | |
1535 | | /* |
1536 | | Open output image file. |
1537 | | */ |
1538 | 6.87k | assert(image_info != (const ImageInfo *) NULL); |
1539 | 6.87k | assert(image_info->signature == MagickSignature); |
1540 | 6.87k | assert(image != (Image *) NULL); |
1541 | 6.87k | assert(image->signature == MagickSignature); |
1542 | 6.87k | image_list_length=GetImageListLength(image); |
1543 | 6.87k | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
1544 | 6.87k | if (status == MagickFail) |
1545 | 6.87k | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
1546 | 6.87k | scene=0; |
1547 | 6.87k | do |
1548 | 6.87k | { |
1549 | 6.87k | depth=(image->depth <= 8 ? 8 : image->depth <= 16 ? 16 : 32); |
1550 | | |
1551 | | /* |
1552 | | Write PNM file header. |
1553 | | */ |
1554 | 6.87k | format=Undefined_PNM_Format; |
1555 | 6.87k | if (LocaleCompare(image_info->magick,"P7") == 0) |
1556 | 1.05k | { |
1557 | 1.05k | format=XV_332_Format; |
1558 | 1.05k | } |
1559 | 5.82k | else if (LocaleCompare(image_info->magick,"PPM") == 0) |
1560 | 1.06k | { |
1561 | 1.06k | format=PPM_RAW_Format; |
1562 | 1.06k | } |
1563 | 4.75k | else if (LocaleCompare(image_info->magick,"PGM") == 0) |
1564 | 1.09k | { |
1565 | 1.09k | format=PGM_RAW_Format; |
1566 | 1.09k | } |
1567 | 3.66k | else if (LocaleCompare(image_info->magick,"PBM") == 0) |
1568 | 1.14k | { |
1569 | 1.14k | format=PBM_RAW_Format; |
1570 | 1.14k | } |
1571 | 2.52k | else if (LocaleCompare(image_info->magick,"PAM") == 0) |
1572 | 1.30k | { |
1573 | 1.30k | format=PAM_Format; |
1574 | 1.30k | } |
1575 | 1.22k | else /* PNM auto format */ |
1576 | 1.22k | { |
1577 | 1.22k | ImageCharacteristics |
1578 | 1.22k | characteristics; |
1579 | | |
1580 | | /* |
1581 | | Make sure that image is in an RGB type space. |
1582 | | */ |
1583 | 1.22k | (void) TransformColorspace(image,RGBColorspace); |
1584 | | |
1585 | | /* |
1586 | | Analyze image to be written. |
1587 | | */ |
1588 | 1.22k | if (!GetImageCharacteristics(image,&characteristics, |
1589 | 1.22k | (OptimizeType == image_info->type), |
1590 | 1.22k | &image->exception)) |
1591 | 0 | { |
1592 | 0 | CloseBlob(image); |
1593 | 0 | return MagickFail; |
1594 | 0 | } |
1595 | | |
1596 | 1.22k | if ((characteristics.monochrome) && |
1597 | 1.22k | (image_info->type != GrayscaleType) && |
1598 | 1.22k | (image_info->type != GrayscaleMatteType) && |
1599 | 1.22k | (image_info->type != TrueColorType) && |
1600 | 1.22k | (image_info->type != TrueColorMatteType)) |
1601 | 333 | { |
1602 | | /* PBM */ |
1603 | 333 | format=PBM_RAW_Format; |
1604 | 333 | } |
1605 | 890 | else if ((characteristics.grayscale) && |
1606 | 890 | (image_info->type != TrueColorType) && |
1607 | 890 | (image_info->type != TrueColorMatteType)) |
1608 | 236 | { |
1609 | | /* PGM */ |
1610 | 236 | format=PGM_RAW_Format; |
1611 | 236 | } |
1612 | 654 | else |
1613 | 654 | { |
1614 | | /* PPM */ |
1615 | 654 | format=PPM_RAW_Format; |
1616 | 654 | } |
1617 | 1.22k | } |
1618 | | |
1619 | | /* |
1620 | | Check if ASCII subformat is requested. |
1621 | | */ |
1622 | 6.87k | if ((PBM_RAW_Format == format) || (PGM_RAW_Format == format) | (PPM_RAW_Format == format)) |
1623 | 4.51k | { |
1624 | 4.51k | MagickBool |
1625 | 4.51k | ascii = MagickFalse; |
1626 | | |
1627 | | /* |
1628 | | If quality is set to zero or "pnm:ascii" is defined, then |
1629 | | select an ASCII subformat. |
1630 | | */ |
1631 | 4.51k | if (image_info->quality == 0) |
1632 | 0 | ascii=MagickTrue; |
1633 | 4.51k | else if ((AccessDefinition(image_info,"pnm","ascii"))) |
1634 | 0 | ascii=MagickTrue; |
1635 | | |
1636 | 4.51k | if (ascii) |
1637 | 0 | { |
1638 | 0 | if (PBM_RAW_Format == format) |
1639 | 0 | format=PBM_ASCII_Format; |
1640 | 0 | else if (PGM_RAW_Format == format) |
1641 | 0 | format=PGM_ASCII_Format; |
1642 | 0 | else if (PPM_RAW_Format == format) |
1643 | 0 | format=PPM_ASCII_Format; |
1644 | 0 | } |
1645 | 4.51k | } |
1646 | | |
1647 | 6.87k | { |
1648 | 6.87k | const char *header = ""; |
1649 | 6.87k | switch (format) |
1650 | 6.87k | { |
1651 | 0 | case Undefined_PNM_Format: break; |
1652 | 0 | case PBM_ASCII_Format: header="P1"; break; |
1653 | 0 | case PGM_ASCII_Format: header="P2"; break; |
1654 | 0 | case PPM_ASCII_Format: header="P3"; break; |
1655 | 1.47k | case PBM_RAW_Format: header="P4"; break; |
1656 | 1.32k | case PGM_RAW_Format: header="P5"; break; |
1657 | 1.71k | case PPM_RAW_Format: header="P6"; break; |
1658 | 1.30k | case PAM_Format: header="P7"; break; |
1659 | 1.05k | case XV_332_Format: header="P7 332"; break; |
1660 | 6.87k | } |
1661 | 6.87k | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Format Id: %s", |
1662 | 6.87k | header); |
1663 | 6.87k | (void) WriteBlobString(image,header); |
1664 | 6.87k | (void) WriteBlobByte(image,'\n'); |
1665 | 6.87k | } |
1666 | | |
1667 | 0 | attribute=GetImageAttribute(image,"comment"); |
1668 | 6.87k | if (attribute != (const ImageAttribute *) NULL) |
1669 | 1.65k | { |
1670 | 1.65k | register char |
1671 | 1.65k | *av; |
1672 | | |
1673 | | /* |
1674 | | Write comments to file. |
1675 | | */ |
1676 | 1.65k | (void) WriteBlobByte(image,'#'); |
1677 | 114M | for (av=attribute->value; *av != '\0'; av++) |
1678 | 114M | { |
1679 | 114M | (void) WriteBlobByte(image,*av); |
1680 | 114M | if ((*av == '\n') && (*(av+1) != '\0')) |
1681 | 48.7k | (void) WriteBlobByte(image,'#'); |
1682 | 114M | } |
1683 | 1.65k | (void) WriteBlobByte(image,'\n'); |
1684 | 1.65k | } |
1685 | 6.87k | if ((PAM_Format != format) && (XV_332_Format != format)) |
1686 | 4.51k | { |
1687 | 4.51k | FormatString(buffer,"%lu %lu\n",image->columns,image->rows); |
1688 | 4.51k | (void) WriteBlobString(image,buffer); |
1689 | 4.51k | } |
1690 | | /* |
1691 | | Write PNM raster pixels. |
1692 | | */ |
1693 | 6.87k | switch (format) |
1694 | 6.87k | { |
1695 | 0 | case PBM_ASCII_Format: |
1696 | 0 | { |
1697 | 0 | unsigned int |
1698 | 0 | polarity; |
1699 | |
|
1700 | 0 | size_t |
1701 | 0 | j; |
1702 | | |
1703 | | /* |
1704 | | Convert image to a PBM ASCII image. |
1705 | | */ |
1706 | 0 | (void) SetImageType(image,BilevelType); |
1707 | 0 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2); |
1708 | 0 | if (image->colors == 2) |
1709 | 0 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < |
1710 | 0 | PixelIntensityToQuantum(&image->colormap[1]); |
1711 | 0 | i=0; |
1712 | 0 | j=0; |
1713 | 0 | for (y=0; y < image->rows; y++) |
1714 | 0 | { |
1715 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1716 | 0 | if (p == (const PixelPacket *) NULL) |
1717 | 0 | { |
1718 | 0 | status=MagickFail; |
1719 | 0 | break; |
1720 | 0 | } |
1721 | 0 | indexes=AccessImmutableIndexes(image); |
1722 | 0 | for (x=0; x < image->columns; x++) |
1723 | 0 | { |
1724 | 0 | buffer[j++] = (indexes[x] == polarity ? '0' : '1'); |
1725 | 0 | buffer[j++] = ' '; |
1726 | 0 | i++; |
1727 | 0 | if (i == 36) |
1728 | 0 | { |
1729 | 0 | buffer[j++] = '\n'; |
1730 | 0 | i=0; |
1731 | 0 | } |
1732 | 0 | if (j+4 > sizeof(buffer)) |
1733 | 0 | { |
1734 | 0 | status=(WriteBlob(image,j,buffer) == j); |
1735 | 0 | j=0; |
1736 | 0 | if (MagickFail == status) |
1737 | 0 | break; |
1738 | 0 | } |
1739 | 0 | } |
1740 | 0 | if (image->previous == (Image *) NULL) |
1741 | 0 | if (QuantumTick(y,image->rows)) |
1742 | 0 | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1743 | 0 | SaveImageText,image->filename, |
1744 | 0 | image->columns,image->rows)) |
1745 | 0 | { |
1746 | 0 | status=MagickFail; |
1747 | 0 | break; |
1748 | 0 | } |
1749 | 0 | if (MagickFail == status) |
1750 | 0 | break; |
1751 | 0 | } |
1752 | 0 | if (MagickFail != status) |
1753 | 0 | { |
1754 | 0 | if (i != 0) |
1755 | 0 | buffer[j++] = '\n'; |
1756 | 0 | if (j > 0) |
1757 | 0 | status=(WriteBlob(image,j,buffer) == j); |
1758 | 0 | } |
1759 | 0 | break; |
1760 | 0 | } |
1761 | 0 | case PGM_ASCII_Format: |
1762 | 0 | { |
1763 | | /* |
1764 | | Convert image to a PGM ASCII image. |
1765 | | */ |
1766 | 0 | size_t |
1767 | 0 | j; |
1768 | |
|
1769 | 0 | unsigned int |
1770 | 0 | value; |
1771 | | |
1772 | | /* |
1773 | | Make sure that image is in an RGB type space. |
1774 | | */ |
1775 | 0 | (void) TransformColorspace(image,RGBColorspace); |
1776 | |
|
1777 | 0 | i=0; |
1778 | 0 | j=0; |
1779 | |
|
1780 | 0 | value=(depth <=8 ? 255U : depth <= 16 ? 65535U : 4294967295U); |
1781 | |
|
1782 | 0 | j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u\n",value); |
1783 | 0 | for (y=0; y < image->rows; y++) |
1784 | 0 | { |
1785 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1786 | 0 | if (p == (const PixelPacket *) NULL) |
1787 | 0 | { |
1788 | 0 | status=MagickFail; |
1789 | 0 | break; |
1790 | 0 | } |
1791 | 0 | for (x=0; x < image->columns; x++) |
1792 | 0 | { |
1793 | 0 | if (image->is_grayscale) |
1794 | 0 | index=p->red; |
1795 | 0 | else |
1796 | 0 | index=PixelIntensityToQuantum(p); |
1797 | 0 | if (depth <= 8) |
1798 | 0 | { |
1799 | | /* Use LUT for speed */ |
1800 | 0 | value=ScaleQuantumToChar(index); |
1801 | 0 | AppendUnsignedCharValueToString(j,buffer,value); |
1802 | 0 | buffer[j++] = ' '; |
1803 | 0 | } |
1804 | 0 | else if (depth <= 16) |
1805 | 0 | { |
1806 | 0 | value=ScaleQuantumToShort(index); |
1807 | 0 | j += snprintf(&buffer[j],(sizeof(buffer)-j)," %u",value); |
1808 | 0 | } |
1809 | 0 | else |
1810 | 0 | { |
1811 | 0 | value=ScaleQuantumToLong(index); |
1812 | 0 | j += snprintf(&buffer[j],(sizeof(buffer)-j)," %u",value); |
1813 | 0 | } |
1814 | |
|
1815 | 0 | i++; |
1816 | 0 | if (i == 12) |
1817 | 0 | { |
1818 | 0 | buffer[j++] = '\n'; |
1819 | 0 | i=0; |
1820 | 0 | } |
1821 | 0 | if (j+8 > sizeof(buffer)) |
1822 | 0 | { |
1823 | 0 | status=(WriteBlob(image,j,buffer) == j); |
1824 | 0 | j=0; |
1825 | 0 | if (MagickFail == status) |
1826 | 0 | break; |
1827 | 0 | } |
1828 | 0 | p++; |
1829 | 0 | } |
1830 | 0 | if (image->previous == (Image *) NULL) |
1831 | 0 | if (QuantumTick(y,image->rows)) |
1832 | 0 | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1833 | 0 | SaveImageText,image->filename, |
1834 | 0 | image->columns,image->rows)) |
1835 | 0 | { |
1836 | 0 | status=MagickFail; |
1837 | 0 | break; |
1838 | 0 | } |
1839 | 0 | if (MagickFail == status) |
1840 | 0 | break; |
1841 | 0 | } |
1842 | 0 | if (MagickFail != status) |
1843 | 0 | { |
1844 | 0 | if (i != 0) |
1845 | 0 | buffer[j++] = '\n'; |
1846 | 0 | if (j > 0) |
1847 | 0 | status=(WriteBlob(image,j,buffer) == j); |
1848 | 0 | } |
1849 | 0 | break; |
1850 | 0 | } |
1851 | 0 | case PPM_ASCII_Format: |
1852 | 0 | { |
1853 | | /* |
1854 | | Convert image to a PPM ASCII image. |
1855 | | */ |
1856 | 0 | size_t |
1857 | 0 | j; |
1858 | |
|
1859 | 0 | unsigned int |
1860 | 0 | value; |
1861 | | |
1862 | | /* |
1863 | | Make sure that image is in an RGB type space. |
1864 | | */ |
1865 | 0 | (void) TransformColorspace(image,RGBColorspace); |
1866 | |
|
1867 | 0 | i=0; |
1868 | 0 | j=0; |
1869 | |
|
1870 | 0 | value=(depth <=8 ? 255U : (depth <= 16 ? 65535U : 4294967295U)); |
1871 | |
|
1872 | 0 | j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u\n",value); |
1873 | 0 | for (y=0; y < image->rows; y++) |
1874 | 0 | { |
1875 | 0 | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1876 | 0 | if (p == (const PixelPacket *) NULL) |
1877 | 0 | { |
1878 | 0 | status=MagickFail; |
1879 | 0 | break; |
1880 | 0 | } |
1881 | 0 | for (x=0; x < image->columns; x++) |
1882 | 0 | { |
1883 | 0 | if (depth <= 8) |
1884 | 0 | { |
1885 | | /* Use LUT for speed */ |
1886 | 0 | value=ScaleQuantumToChar(p->red); |
1887 | 0 | AppendUnsignedCharValueToString(j,buffer,value); |
1888 | 0 | buffer[j++] = ' '; |
1889 | 0 | value=ScaleQuantumToChar(p->green); |
1890 | 0 | AppendUnsignedCharValueToString(j,buffer,value); |
1891 | 0 | buffer[j++] = ' '; |
1892 | 0 | value=ScaleQuantumToChar(p->blue); |
1893 | 0 | AppendUnsignedCharValueToString(j,buffer,value); |
1894 | 0 | buffer[j++] = ' '; |
1895 | 0 | } |
1896 | 0 | else if (depth <= 16) |
1897 | 0 | { |
1898 | 0 | j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u %u %u ", |
1899 | 0 | ScaleQuantumToShort(p->red), |
1900 | 0 | ScaleQuantumToShort(p->green), |
1901 | 0 | ScaleQuantumToShort(p->blue)); |
1902 | 0 | } |
1903 | 0 | else |
1904 | 0 | { |
1905 | 0 | j += snprintf(&buffer[j],(sizeof(buffer)-j),"%u %u %u ", |
1906 | 0 | (unsigned int) ScaleQuantumToLong(p->red), |
1907 | 0 | (unsigned int) ScaleQuantumToLong(p->green), |
1908 | 0 | (unsigned int) ScaleQuantumToLong(p->blue)); |
1909 | 0 | } |
1910 | 0 | i++; |
1911 | 0 | if (i == 4) |
1912 | 0 | { |
1913 | 0 | buffer[j++] = '\n'; |
1914 | 0 | i=0; |
1915 | 0 | } |
1916 | 0 | if (j+(8*3) > sizeof(buffer)) |
1917 | 0 | { |
1918 | 0 | status=(WriteBlob(image,j,buffer) == j); |
1919 | 0 | j=0; |
1920 | 0 | if (MagickFail == status) |
1921 | 0 | break; |
1922 | 0 | } |
1923 | 0 | p++; |
1924 | 0 | } |
1925 | 0 | if (image->previous == (Image *) NULL) |
1926 | 0 | if (QuantumTick(y,image->rows)) |
1927 | 0 | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1928 | 0 | SaveImageText,image->filename, |
1929 | 0 | image->columns,image->rows)) |
1930 | 0 | { |
1931 | 0 | status=MagickFail; |
1932 | 0 | break; |
1933 | 0 | } |
1934 | 0 | if (MagickFail == status) |
1935 | 0 | break; |
1936 | 0 | } |
1937 | 0 | if (MagickFail != status) |
1938 | 0 | { |
1939 | 0 | if (i != 0) |
1940 | 0 | buffer[j++] = '\n'; |
1941 | 0 | if (j > 0) |
1942 | 0 | status=(WriteBlob(image,j,buffer) == j); |
1943 | 0 | } |
1944 | 0 | break; |
1945 | 0 | } |
1946 | 1.47k | case PBM_RAW_Format: |
1947 | 2.80k | case PGM_RAW_Format: |
1948 | 4.51k | case PPM_RAW_Format: |
1949 | 5.82k | case PAM_Format: |
1950 | 5.82k | { |
1951 | 5.82k | ExportPixelAreaOptions |
1952 | 5.82k | export_options; |
1953 | | |
1954 | 5.82k | size_t |
1955 | 5.82k | bytes_per_row; |
1956 | | |
1957 | 5.82k | QuantumType |
1958 | 5.82k | quantum_type; |
1959 | | |
1960 | 5.82k | unsigned int |
1961 | 5.82k | bits_per_sample, |
1962 | 5.82k | samples_per_pixel; |
1963 | | |
1964 | 5.82k | MagickBool |
1965 | 5.82k | grayscale_miniswhite=MagickFalse; |
1966 | | |
1967 | 5.82k | unsigned char |
1968 | 5.82k | *pixels; |
1969 | | |
1970 | | /* |
1971 | | Deduce correct export parameters. |
1972 | | */ |
1973 | 5.82k | bits_per_sample=(depth <=8 ? 8 : (depth <= 16 ? 16 : 32)); |
1974 | 5.82k | quantum_type=RGBQuantum; |
1975 | 5.82k | if (PBM_RAW_Format == format) |
1976 | 1.47k | { |
1977 | 1.47k | bits_per_sample=1; |
1978 | 1.47k | grayscale_miniswhite=MagickTrue; |
1979 | 1.47k | quantum_type=GrayQuantum; |
1980 | 1.47k | } |
1981 | 4.34k | else if (PGM_RAW_Format == format) |
1982 | 1.32k | { |
1983 | 1.32k | quantum_type=GrayQuantum; |
1984 | 1.32k | } |
1985 | 3.02k | else if (PPM_RAW_Format == format) |
1986 | 1.71k | { |
1987 | 1.71k | quantum_type=RGBQuantum; |
1988 | 1.71k | } |
1989 | 1.30k | else if (PAM_Format == format) |
1990 | 1.30k | { |
1991 | 1.30k | ImageCharacteristics |
1992 | 1.30k | characteristics; |
1993 | | |
1994 | | /* |
1995 | | Make sure image is of desired type. |
1996 | | */ |
1997 | 1.30k | if (UndefinedType != image_info->type) |
1998 | 0 | SetImageType(image,image_info->type); |
1999 | | |
2000 | | /* |
2001 | | Analyze the image to get its characteristics. |
2002 | | */ |
2003 | 1.30k | if (!GetImageCharacteristics(image,&characteristics, |
2004 | 1.30k | (OptimizeType == image_info->type), |
2005 | 1.30k | &image->exception)) |
2006 | 0 | { |
2007 | 0 | CloseBlob(image); |
2008 | 0 | return MagickFail; |
2009 | 0 | } |
2010 | | |
2011 | | /* |
2012 | | Choose best encoding based on image characteristics. |
2013 | | */ |
2014 | 1.30k | if (characteristics.cmyk) |
2015 | 401 | { |
2016 | 401 | if (image->matte) |
2017 | 152 | quantum_type=CMYKAQuantum; |
2018 | 249 | else |
2019 | 249 | quantum_type=CMYKQuantum; |
2020 | 401 | } |
2021 | 901 | else if (characteristics.monochrome) |
2022 | 344 | { |
2023 | 344 | bits_per_sample=1; |
2024 | 344 | grayscale_miniswhite=MagickTrue; |
2025 | | |
2026 | 344 | if (image->matte) |
2027 | 46 | quantum_type=GrayAlphaQuantum; |
2028 | 298 | else |
2029 | 298 | quantum_type=GrayQuantum; |
2030 | 344 | } |
2031 | 557 | else if (characteristics.grayscale) |
2032 | 284 | { |
2033 | 284 | if (image->matte) |
2034 | 120 | quantum_type=GrayAlphaQuantum; |
2035 | 164 | else |
2036 | 164 | quantum_type=GrayQuantum; |
2037 | 284 | } |
2038 | 273 | else |
2039 | 273 | { |
2040 | 273 | if (image->matte) |
2041 | 43 | quantum_type=RGBAQuantum; |
2042 | 230 | else |
2043 | 230 | quantum_type=RGBQuantum; |
2044 | 273 | } |
2045 | 1.30k | } |
2046 | 5.82k | if (image->logging) |
2047 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2048 | 0 | "Export Quantum Type: %s", |
2049 | 0 | QuantumTypeToString(quantum_type)); |
2050 | | |
2051 | 5.82k | samples_per_pixel=MagickGetQuantumSamplesPerPixel(quantum_type); |
2052 | 5.82k | if (image->logging) |
2053 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2054 | 0 | "Samples/Pixel: %u", samples_per_pixel); |
2055 | | |
2056 | 5.82k | if (1 == bits_per_sample) |
2057 | 1.81k | { |
2058 | | /* bytes_per_row=(((size_t) image->columns*samples_per_pixel+7) >> 3); */ |
2059 | 1.81k | bytes_per_row=MagickArraySize(image->columns,samples_per_pixel); |
2060 | 1.81k | if (bytes_per_row) |
2061 | 1.81k | bytes_per_row += 7; |
2062 | 1.81k | if (bytes_per_row) |
2063 | 1.81k | bytes_per_row >>= 3; |
2064 | 1.81k | } |
2065 | 4.00k | else |
2066 | 4.00k | { |
2067 | 4.00k | bytes_per_row=MagickArraySize((((size_t) bits_per_sample+7)/8)* |
2068 | 4.00k | samples_per_pixel,image->columns); |
2069 | 4.00k | } |
2070 | | |
2071 | 5.82k | if (image->logging) |
2072 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2073 | 0 | "Bytes/Row: %" MAGICK_SIZE_T_F "u", |
2074 | 0 | (MAGICK_SIZE_T) bytes_per_row); |
2075 | | |
2076 | 5.82k | ExportPixelAreaOptionsInit(&export_options); |
2077 | 5.82k | export_options.grayscale_miniswhite=grayscale_miniswhite; |
2078 | | |
2079 | | /* |
2080 | | Allocate memory for pixels. |
2081 | | */ |
2082 | 5.82k | pixels=MagickAllocateResourceLimitedMemory(unsigned char *,bytes_per_row); |
2083 | 5.82k | if (pixels == (unsigned char *) NULL) |
2084 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
2085 | 5.82k | image); |
2086 | | |
2087 | | /* |
2088 | | Output header details |
2089 | | */ |
2090 | 5.82k | if (PAM_Format == format) |
2091 | 1.30k | { |
2092 | | /* |
2093 | | PAM header |
2094 | | */ |
2095 | 1.30k | const char *tuple_type=NULL; |
2096 | | |
2097 | 1.30k | if (GrayQuantum == quantum_type) |
2098 | 462 | { |
2099 | 462 | if (1 == bits_per_sample) |
2100 | 298 | tuple_type="BLACKANDWHITE"; |
2101 | 164 | else |
2102 | 164 | tuple_type="GRAYSCALE"; |
2103 | 462 | } |
2104 | 840 | else if (GrayAlphaQuantum == quantum_type) |
2105 | 166 | { |
2106 | 166 | if (1 == bits_per_sample) |
2107 | 46 | tuple_type="BLACKANDWHITE_ALPHA"; |
2108 | 120 | else |
2109 | 120 | tuple_type="GRAYSCALE_ALPHA"; |
2110 | 166 | } |
2111 | 674 | else if (RGBQuantum == quantum_type) |
2112 | 230 | tuple_type="RGB"; |
2113 | 444 | else if (RGBAQuantum == quantum_type) |
2114 | 43 | tuple_type="RGB_ALPHA"; |
2115 | 401 | else if (CMYKQuantum == quantum_type) |
2116 | 249 | tuple_type="CMYK"; |
2117 | 152 | else if (CMYKAQuantum == quantum_type) |
2118 | 152 | tuple_type="CMYK_ALPHA"; |
2119 | | |
2120 | 1.30k | FormatString(buffer,"WIDTH %lu\nHEIGHT %lu\nDEPTH %u" |
2121 | 1.30k | "\nMAXVAL %lu\nTUPLTYPE %s\n", |
2122 | 1.30k | image->columns,image->rows,samples_per_pixel, |
2123 | 1.30k | MaxValueGivenBits(bits_per_sample),tuple_type); |
2124 | 1.30k | if (image->logging) |
2125 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2126 | 0 | "PAM Header: WIDTH %lu, HEIGHT %lu, " |
2127 | 0 | "DEPTH %u, MAXVAL %lu, TUPLTYPE %s", |
2128 | 0 | image->columns, |
2129 | 0 | image->rows,samples_per_pixel, |
2130 | 0 | MaxValueGivenBits(bits_per_sample), |
2131 | 0 | tuple_type); |
2132 | 1.30k | WriteBlobString(image,buffer); |
2133 | | |
2134 | 1.30k | (void) WriteBlobString(image,"ENDHDR\n"); |
2135 | 1.30k | } |
2136 | 4.51k | else if ((PGM_RAW_Format == format) || (PPM_RAW_Format == format)) |
2137 | 3.04k | { |
2138 | | /* |
2139 | | PGM, PPM header |
2140 | | */ |
2141 | 3.04k | FormatString(buffer,"%lu\n",MaxValueGivenBits(bits_per_sample)); |
2142 | 3.04k | WriteBlobString(image,buffer); |
2143 | 3.04k | } |
2144 | | |
2145 | | /* |
2146 | | Output pixels |
2147 | | */ |
2148 | 436k | for (y=0; y < image->rows; y++) |
2149 | 431k | { |
2150 | 431k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
2151 | 431k | if (p == (const PixelPacket *) NULL) |
2152 | 0 | break; |
2153 | 431k | if (ExportImagePixelArea(image,quantum_type,bits_per_sample,pixels,&export_options,0) == MagickFail) |
2154 | 0 | break; |
2155 | 431k | if (WriteBlob(image,bytes_per_row,(char *) pixels) != bytes_per_row) |
2156 | 171 | break; |
2157 | 430k | if (image->previous == (Image *) NULL) |
2158 | 430k | if (QuantumTick(y,image->rows)) |
2159 | 118k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
2160 | 118k | SaveImageText,image->filename, |
2161 | 118k | image->columns,image->rows)) |
2162 | 0 | break; |
2163 | 430k | } |
2164 | 5.82k | MagickFreeResourceLimitedMemory(pixels); |
2165 | | |
2166 | 5.82k | break; |
2167 | 5.82k | } |
2168 | 1.05k | case XV_332_Format: |
2169 | 1.05k | { |
2170 | 1.05k | static const short int |
2171 | 1.05k | dither_red[2][16]= |
2172 | 1.05k | { |
2173 | 1.05k | {-16, 4, -1, 11,-14, 6, -3, 9,-15, 5, -2, 10,-13, 7, -4, 8}, |
2174 | 1.05k | { 15, -5, 0,-12, 13, -7, 2,-10, 14, -6, 1,-11, 12, -8, 3, -9} |
2175 | 1.05k | }, |
2176 | 1.05k | dither_green[2][16]= |
2177 | 1.05k | { |
2178 | 1.05k | { 11,-15, 7, -3, 8,-14, 4, -2, 10,-16, 6, -4, 9,-13, 5, -1}, |
2179 | 1.05k | {-12, 14, -8, 2, -9, 13, -5, 1,-11, 15, -7, 3,-10, 12, -6, 0} |
2180 | 1.05k | }, |
2181 | 1.05k | dither_blue[2][16]= |
2182 | 1.05k | { |
2183 | 1.05k | { -3, 9,-13, 7, -1, 11,-15, 5, -4, 8,-14, 6, -2, 10,-16, 4}, |
2184 | 1.05k | { 2,-10, 12, -8, 0,-12, 14, -6, 3, -9, 13, -7, 1,-11, 15, -5} |
2185 | 1.05k | }; |
2186 | | |
2187 | 1.05k | long |
2188 | 1.05k | value; |
2189 | | |
2190 | 1.05k | Quantum |
2191 | 1.05k | pixel; |
2192 | | |
2193 | 1.05k | unsigned short |
2194 | 1.05k | *blue_map[2][16], |
2195 | 1.05k | *green_map[2][16], |
2196 | 1.05k | *red_map[2][16]; |
2197 | | |
2198 | 1.05k | unsigned int |
2199 | 1.05k | j; |
2200 | | |
2201 | | /* |
2202 | | Allocate and initialize dither maps. |
2203 | | */ |
2204 | 1.05k | memset(blue_map,0,sizeof(blue_map)); |
2205 | 1.05k | memset(green_map,0,sizeof(green_map)); |
2206 | 1.05k | memset(red_map,0,sizeof(red_map)); |
2207 | 3.17k | for (i=0; i < 2; i++) |
2208 | 36.0k | for (j=0; j < 16; j++) |
2209 | 33.8k | { |
2210 | 33.8k | red_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *, |
2211 | 33.8k | 256*sizeof(unsigned short)); |
2212 | 33.8k | green_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *, |
2213 | 33.8k | 256*sizeof(unsigned short)); |
2214 | 33.8k | blue_map[i][j]=MagickAllocateResourceLimitedMemory(unsigned short *, |
2215 | 33.8k | 256*sizeof(unsigned short)); |
2216 | 33.8k | if ((red_map[i][j] == (unsigned short *) NULL) || |
2217 | 33.8k | (green_map[i][j] == (unsigned short *) NULL) || |
2218 | 33.8k | (blue_map[i][j] == (unsigned short *) NULL)) |
2219 | 0 | { |
2220 | 0 | for (i=0; i < 2; i++) |
2221 | 0 | for (j=0; j < 16; j++) |
2222 | 0 | { |
2223 | 0 | MagickFreeResourceLimitedMemory(green_map[i][j]); |
2224 | 0 | MagickFreeResourceLimitedMemory(blue_map[i][j]); |
2225 | 0 | MagickFreeResourceLimitedMemory(red_map[i][j]); |
2226 | 0 | } |
2227 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
2228 | 0 | image); |
2229 | 0 | } |
2230 | 33.8k | } |
2231 | | /* |
2232 | | Initialize dither tables. |
2233 | | */ |
2234 | 3.17k | for (i=0; i < 2; i++) |
2235 | 36.0k | for (j=0; j < 16; j++) |
2236 | 8.70M | for (x=0; x < 256; x++) |
2237 | 8.67M | { |
2238 | 8.67M | value=x-16; |
2239 | 8.67M | if (x < 48) |
2240 | 1.62M | value=x/2+8; |
2241 | 8.67M | value+=dither_red[i][j]; |
2242 | 8.67M | red_map[i][j][x]=(unsigned short) |
2243 | 8.67M | ((value < 0) ? 0 : (value > 255) ? 255 : value); |
2244 | 8.67M | value=x-16; |
2245 | 8.67M | if (x < 48) |
2246 | 1.62M | value=x/2+8; |
2247 | 8.67M | value+=dither_green[i][j]; |
2248 | 8.67M | green_map[i][j][x]=(unsigned short) |
2249 | 8.67M | ((value < 0) ? 0 : (value > 255) ? 255 : value); |
2250 | 8.67M | value=x-32; |
2251 | 8.67M | if (x < 112) |
2252 | 3.79M | value=x/2+24; |
2253 | 8.67M | value+=2*dither_blue[i][j]; |
2254 | 8.67M | blue_map[i][j][x]=(unsigned short) |
2255 | 8.67M | ((value < 0) ? 0 : (value > 255) ? 255 : value); |
2256 | 8.67M | } |
2257 | | /* |
2258 | | Write pixels. |
2259 | | */ |
2260 | 1.05k | (void) WriteBlobString(image,"#END_OF_COMMENTS\n"); |
2261 | 1.05k | FormatString(buffer,"%lu %lu 255\n",image->columns,image->rows); |
2262 | 1.05k | (void) WriteBlobString(image,buffer); |
2263 | 1.05k | i=0; |
2264 | 1.05k | j=0; |
2265 | 123k | for (y=0; y < image->rows; y++) |
2266 | 122k | { |
2267 | 122k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
2268 | 122k | if (p == (const PixelPacket *) NULL) |
2269 | 0 | break; |
2270 | 71.5M | for (x=0; x < image->columns; x++) |
2271 | 71.3M | { |
2272 | 71.3M | if (!image_info->dither) |
2273 | 0 | pixel=(Quantum) ((ScaleQuantumToChar(p->red) & 0xe0) | |
2274 | 0 | ((ScaleQuantumToChar(p->green) & 0xe0) >> 3) | |
2275 | 0 | ((ScaleQuantumToChar(p->blue) & 0xc0) >> 6)); |
2276 | 71.3M | else |
2277 | 71.3M | pixel=(Quantum) |
2278 | 71.3M | ((red_map[i][j][ScaleQuantumToChar(p->red)] & 0xe0) | |
2279 | 71.3M | ((green_map[i][j][ScaleQuantumToChar(p->green)] & 0xe0) >> 3) | |
2280 | 71.3M | ((blue_map[i][j][ScaleQuantumToChar(p->blue)] & 0xc0) >> 6)); |
2281 | 71.3M | (void) WriteBlobByte(image,pixel); |
2282 | 71.3M | p++; |
2283 | 71.3M | j++; |
2284 | 71.3M | if (j == 16) |
2285 | 4.46M | j=0; |
2286 | 71.3M | } |
2287 | 122k | i++; |
2288 | 122k | if (i == 2) |
2289 | 60.9k | i=0; |
2290 | 122k | if (QuantumTick(y,image->rows)) |
2291 | 26.8k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
2292 | 26.8k | SaveImageText,image->filename, |
2293 | 26.8k | image->columns,image->rows)) |
2294 | 0 | break; |
2295 | 122k | } |
2296 | | /* |
2297 | | Free allocated memory. |
2298 | | */ |
2299 | 3.17k | for (i=0; i < 2; i++) |
2300 | 36.0k | for (j=0; j < 16; j++) |
2301 | 33.8k | { |
2302 | 33.8k | MagickFreeResourceLimitedMemory(green_map[i][j]); |
2303 | 33.8k | MagickFreeResourceLimitedMemory(blue_map[i][j]); |
2304 | 33.8k | MagickFreeResourceLimitedMemory(red_map[i][j]); |
2305 | 33.8k | } |
2306 | 1.05k | break; |
2307 | 1.05k | } |
2308 | 0 | case Undefined_PNM_Format: |
2309 | 0 | break; |
2310 | 6.87k | } |
2311 | 6.87k | if (image->next == (Image *) NULL) |
2312 | 6.87k | break; |
2313 | 0 | image=SyncNextImageInList(image); |
2314 | 0 | if (status != MagickFail) |
2315 | 0 | status=MagickMonitorFormatted(scene++,image_list_length, |
2316 | 0 | &image->exception,SaveImagesText, |
2317 | 0 | image->filename); |
2318 | 0 | if (status == MagickFail) |
2319 | 0 | break; |
2320 | 0 | } while (image_info->adjoin); |
2321 | 6.87k | if (image_info->adjoin) |
2322 | 6.87k | while (image->previous != (Image *) NULL) |
2323 | 0 | image=image->previous; |
2324 | 6.87k | status &= CloseBlob(image); |
2325 | 6.87k | return(status); |
2326 | 6.87k | } |