1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % PPPP N N M M %
7 % P P NN N MM MM %
8 % PPPP N N N M M M %
9 % P N NN M M %
10 % P N N M M %
11 % %
12 % %
13 % Read/Write PBMPlus Portable Anymap Image Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace.h"
50 #include "MagickCore/colorspace-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/image.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/module.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/property.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/static.h"
65 #include "MagickCore/statistic.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/string-private.h"
68
69 /*
70 Typedef declarations.
71 */
72 typedef struct _CommentInfo
73 {
74 char
75 *comment;
76
77 size_t
78 extent;
79 } CommentInfo;
80
81 /*
82 Forward declarations.
83 */
84 static MagickBooleanType
85 WritePNMImage(const ImageInfo *,Image *,ExceptionInfo *);
86
87 /*
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 % %
90 % %
91 % %
92 % I s P N M %
93 % %
94 % %
95 % %
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %
98 % IsPNM() returns MagickTrue if the image format type, identified by the
99 % magick string, is PNM.
100 %
101 % The format of the IsPNM method is:
102 %
103 % MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
104 %
105 % A description of each parameter follows:
106 %
107 % o magick: compare image format pattern against these bytes.
108 %
109 % o extent: Specifies the extent of the magick string.
110 %
111 */
IsPNM(const unsigned char * magick,const size_t extent)112 static MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
113 {
114 if (extent < 2)
115 return(MagickFalse);
116 if ((*magick == (unsigned char) 'P') &&
117 ((magick[1] == '1') || (magick[1] == '2') || (magick[1] == '3') ||
118 (magick[1] == '4') || (magick[1] == '5') || (magick[1] == '6') ||
119 (magick[1] == '7') || (magick[1] == 'F') || (magick[1] == 'f')))
120 return(MagickTrue);
121 return(MagickFalse);
122 }
123
124 /*
125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % %
127 % %
128 % %
129 % R e a d P N M I m a g e %
130 % %
131 % %
132 % %
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 %
135 % ReadPNMImage() reads a Portable Anymap image file and returns it.
136 % It allocates the memory necessary for the new Image structure and returns
137 % a pointer to the new image.
138 %
139 % The format of the ReadPNMImage method is:
140 %
141 % Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
142 %
143 % A description of each parameter follows:
144 %
145 % o image_info: the image info.
146 %
147 % o exception: return any errors or warnings in this structure.
148 %
149 */
150
PNMComment(Image * image,CommentInfo * comment_info,ExceptionInfo * exception)151 static int PNMComment(Image *image,CommentInfo *comment_info,
152 ExceptionInfo *exception)
153 {
154 int
155 c;
156
157 register char
158 *p;
159
160 /*
161 Read comment.
162 */
163 p=comment_info->comment+strlen(comment_info->comment);
164 for (c='#'; (c != EOF) && (c != (int) '\n') && (c != (int) '\r'); p++)
165 {
166 if ((size_t) (p-comment_info->comment+1) >= comment_info->extent)
167 {
168 comment_info->extent<<=1;
169 comment_info->comment=(char *) ResizeQuantumMemory(
170 comment_info->comment,comment_info->extent,
171 sizeof(*comment_info->comment));
172 if (comment_info->comment == (char *) NULL)
173 return(-1);
174 p=comment_info->comment+strlen(comment_info->comment);
175 }
176 c=ReadBlobByte(image);
177 if (c != EOF)
178 {
179 *p=(char) c;
180 *(p+1)='\0';
181 }
182 }
183 return(c);
184 }
185
PNMInteger(Image * image,CommentInfo * comment_info,const unsigned int base,ExceptionInfo * exception)186 static unsigned int PNMInteger(Image *image,CommentInfo *comment_info,
187 const unsigned int base,ExceptionInfo *exception)
188 {
189 int
190 c;
191
192 unsigned int
193 value;
194
195 /*
196 Skip any leading whitespace.
197 */
198 do
199 {
200 c=ReadBlobByte(image);
201 if (c == EOF)
202 return(0);
203 if (c == (int) '#')
204 c=PNMComment(image,comment_info,exception);
205 } while ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
206 if (base == 2)
207 return((unsigned int) (c-(int) '0'));
208 /*
209 Evaluate number.
210 */
211 value=0;
212 while (isdigit(c) != 0)
213 {
214 if (value <= (unsigned int) (INT_MAX/10))
215 {
216 value*=10;
217 if (value <= (unsigned int) (INT_MAX-(c-(int) '0')))
218 value+=c-(int) '0';
219 }
220 c=ReadBlobByte(image);
221 if (c == EOF)
222 return(0);
223 }
224 if (c == (int) '#')
225 c=PNMComment(image,comment_info,exception);
226 return(value);
227 }
228
ReadPNMImage(const ImageInfo * image_info,ExceptionInfo * exception)229 static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
230 {
231 #define ThrowPNMException(exception,message) \
232 { \
233 if (comment_info.comment != (char *) NULL) \
234 comment_info.comment=DestroyString(comment_info.comment); \
235 ThrowReaderException((exception),(message)); \
236 }
237
238 char
239 format;
240
241 CommentInfo
242 comment_info;
243
244 double
245 quantum_scale;
246
247 Image
248 *image;
249
250 MagickBooleanType
251 status;
252
253 QuantumAny
254 max_value;
255
256 QuantumInfo
257 *quantum_info;
258
259 QuantumType
260 quantum_type;
261
262 size_t
263 depth,
264 extent,
265 packet_size;
266
267 ssize_t
268 count,
269 row,
270 y;
271
272 /*
273 Open image file.
274 */
275 assert(image_info != (const ImageInfo *) NULL);
276 assert(image_info->signature == MagickCoreSignature);
277 if (image_info->debug != MagickFalse)
278 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
279 image_info->filename);
280 assert(exception != (ExceptionInfo *) NULL);
281 assert(exception->signature == MagickCoreSignature);
282 image=AcquireImage(image_info,exception);
283 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
284 if (status == MagickFalse)
285 {
286 image=DestroyImageList(image);
287 return((Image *) NULL);
288 }
289 /*
290 Read PNM image.
291 */
292 count=ReadBlob(image,1,(unsigned char *) &format);
293 do
294 {
295 /*
296 Initialize image structure.
297 */
298 comment_info.comment=AcquireString(NULL);
299 comment_info.extent=MagickPathExtent;
300 if ((count != 1) || (format != 'P'))
301 ThrowPNMException(CorruptImageError,"ImproperImageHeader");
302 max_value=1;
303 quantum_type=RGBQuantum;
304 quantum_scale=1.0;
305 format=(char) ReadBlobByte(image);
306 if (format != '7')
307 {
308 /*
309 PBM, PGM, PPM, and PNM.
310 */
311 image->columns=(size_t) PNMInteger(image,&comment_info,10,exception);
312 image->rows=(size_t) PNMInteger(image,&comment_info,10,exception);
313 if ((format == 'f') || (format == 'F'))
314 {
315 char
316 scale[MagickPathExtent];
317
318 if (ReadBlobString(image,scale) != (char *) NULL)
319 quantum_scale=StringToDouble(scale,(char **) NULL);
320 }
321 else
322 {
323 if ((format == '1') || (format == '4'))
324 max_value=1; /* bitmap */
325 else
326 max_value=(QuantumAny) PNMInteger(image,&comment_info,10,
327 exception);
328 }
329 }
330 else
331 {
332 char
333 keyword[MagickPathExtent],
334 value[MagickPathExtent];
335
336 int
337 c;
338
339 register char
340 *p;
341
342 /*
343 PAM.
344 */
345 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
346 {
347 while (isspace((int) ((unsigned char) c)) != 0)
348 c=ReadBlobByte(image);
349 if (c == '#')
350 {
351 /*
352 Comment.
353 */
354 c=PNMComment(image,&comment_info,exception);
355 c=ReadBlobByte(image);
356 while (isspace((int) ((unsigned char) c)) != 0)
357 c=ReadBlobByte(image);
358 }
359 p=keyword;
360 do
361 {
362 if ((size_t) (p-keyword) < (MagickPathExtent-1))
363 *p++=c;
364 c=ReadBlobByte(image);
365 } while (isalnum(c));
366 *p='\0';
367 if (LocaleCompare(keyword,"endhdr") == 0)
368 break;
369 while (isspace((int) ((unsigned char) c)) != 0)
370 c=ReadBlobByte(image);
371 p=value;
372 while (isalnum(c) || (c == '_'))
373 {
374 if ((size_t) (p-value) < (MagickPathExtent-1))
375 *p++=c;
376 c=ReadBlobByte(image);
377 }
378 *p='\0';
379 /*
380 Assign a value to the specified keyword.
381 */
382 if (LocaleCompare(keyword,"depth") == 0)
383 packet_size=StringToUnsignedLong(value);
384 (void) packet_size;
385 if (LocaleCompare(keyword,"height") == 0)
386 image->rows=StringToUnsignedLong(value);
387 if (LocaleCompare(keyword,"maxval") == 0)
388 max_value=StringToUnsignedLong(value);
389 if (LocaleCompare(keyword,"TUPLTYPE") == 0)
390 {
391 if (LocaleCompare(value,"BLACKANDWHITE") == 0)
392 {
393 (void) SetImageColorspace(image,GRAYColorspace,exception);
394 quantum_type=GrayQuantum;
395 }
396 if (LocaleCompare(value,"BLACKANDWHITE_ALPHA") == 0)
397 {
398 (void) SetImageColorspace(image,GRAYColorspace,exception);
399 image->alpha_trait=BlendPixelTrait;
400 quantum_type=GrayAlphaQuantum;
401 }
402 if (LocaleCompare(value,"GRAYSCALE") == 0)
403 {
404 quantum_type=GrayQuantum;
405 (void) SetImageColorspace(image,GRAYColorspace,exception);
406 }
407 if (LocaleCompare(value,"GRAYSCALE_ALPHA") == 0)
408 {
409 (void) SetImageColorspace(image,GRAYColorspace,exception);
410 image->alpha_trait=BlendPixelTrait;
411 quantum_type=GrayAlphaQuantum;
412 }
413 if (LocaleCompare(value,"RGB_ALPHA") == 0)
414 {
415 image->alpha_trait=BlendPixelTrait;
416 quantum_type=RGBAQuantum;
417 }
418 if (LocaleCompare(value,"CMYK") == 0)
419 {
420 (void) SetImageColorspace(image,CMYKColorspace,exception);
421 quantum_type=CMYKQuantum;
422 }
423 if (LocaleCompare(value,"CMYK_ALPHA") == 0)
424 {
425 (void) SetImageColorspace(image,CMYKColorspace,exception);
426 image->alpha_trait=BlendPixelTrait;
427 quantum_type=CMYKAQuantum;
428 }
429 }
430 if (LocaleCompare(keyword,"width") == 0)
431 image->columns=StringToUnsignedLong(value);
432 }
433 }
434 if ((image->columns == 0) || (image->rows == 0))
435 ThrowPNMException(CorruptImageError,"NegativeOrZeroImageSize");
436 if ((max_value == 0) || (max_value > 4294967295UL))
437 ThrowPNMException(CorruptImageError,"ImproperImageHeader");
438 for (depth=1; GetQuantumRange(depth) < max_value; depth++) ;
439 image->depth=depth;
440 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
441 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
442 break;
443 if ((MagickSizeType) (image->columns*image->rows/8) > GetBlobSize(image))
444 ThrowPNMException(CorruptImageError,"InsufficientImageDataInFile");
445 status=SetImageExtent(image,image->columns,image->rows,exception);
446 if (status == MagickFalse)
447 {
448 comment_info.comment=DestroyString(comment_info.comment); \
449 return(DestroyImageList(image));
450 }
451 (void) SetImageBackgroundColor(image,exception);
452 /*
453 Convert PNM pixels to runextent-encoded MIFF packets.
454 */
455 row=0;
456 y=0;
457 switch (format)
458 {
459 case '1':
460 {
461 /*
462 Convert PBM image to pixel packets.
463 */
464 (void) SetImageColorspace(image,GRAYColorspace,exception);
465 for (y=0; y < (ssize_t) image->rows; y++)
466 {
467 register ssize_t
468 x;
469
470 register Quantum
471 *magick_restrict q;
472
473 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
474 if (q == (Quantum *) NULL)
475 break;
476 for (x=0; x < (ssize_t) image->columns; x++)
477 {
478 SetPixelGray(image,PNMInteger(image,&comment_info,2,exception) ==
479 0 ? QuantumRange : 0,q);
480 if (EOFBlob(image) != MagickFalse)
481 break;
482 q+=GetPixelChannels(image);
483 }
484 if (SyncAuthenticPixels(image,exception) == MagickFalse)
485 break;
486 if (image->previous == (Image *) NULL)
487 {
488 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
489 image->rows);
490 if (status == MagickFalse)
491 break;
492 }
493 if (EOFBlob(image) != MagickFalse)
494 break;
495 }
496 image->type=BilevelType;
497 break;
498 }
499 case '2':
500 {
501 Quantum
502 intensity;
503
504 /*
505 Convert PGM image to pixel packets.
506 */
507 (void) SetImageColorspace(image,GRAYColorspace,exception);
508 for (y=0; y < (ssize_t) image->rows; y++)
509 {
510 register ssize_t
511 x;
512
513 register Quantum
514 *magick_restrict q;
515
516 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
517 if (q == (Quantum *) NULL)
518 break;
519 for (x=0; x < (ssize_t) image->columns; x++)
520 {
521 intensity=ScaleAnyToQuantum(PNMInteger(image,&comment_info,10,
522 exception),max_value);
523 if (EOFBlob(image) != MagickFalse)
524 break;
525 SetPixelGray(image,intensity,q);
526 q+=GetPixelChannels(image);
527 }
528 if (SyncAuthenticPixels(image,exception) == MagickFalse)
529 break;
530 if (image->previous == (Image *) NULL)
531 {
532 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
533 image->rows);
534 if (status == MagickFalse)
535 break;
536 }
537 if (EOFBlob(image) != MagickFalse)
538 break;
539 }
540 image->type=GrayscaleType;
541 break;
542 }
543 case '3':
544 {
545 /*
546 Convert PNM image to pixel packets.
547 */
548 for (y=0; y < (ssize_t) image->rows; y++)
549 {
550 register ssize_t
551 x;
552
553 register Quantum
554 *magick_restrict q;
555
556 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
557 if (q == (Quantum *) NULL)
558 break;
559 for (x=0; x < (ssize_t) image->columns; x++)
560 {
561 Quantum
562 pixel;
563
564 pixel=ScaleAnyToQuantum(PNMInteger(image,&comment_info,10,
565 exception),max_value);
566 if (EOFBlob(image) != MagickFalse)
567 break;
568 SetPixelRed(image,pixel,q);
569 pixel=ScaleAnyToQuantum(PNMInteger(image,&comment_info,10,
570 exception),max_value);
571 SetPixelGreen(image,pixel,q);
572 pixel=ScaleAnyToQuantum(PNMInteger(image,&comment_info,10,
573 exception),max_value);
574 SetPixelBlue(image,pixel,q);
575 q+=GetPixelChannels(image);
576 }
577 if (SyncAuthenticPixels(image,exception) == MagickFalse)
578 break;
579 if (image->previous == (Image *) NULL)
580 {
581 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
582 image->rows);
583 if (status == MagickFalse)
584 break;
585 }
586 if (EOFBlob(image) != MagickFalse)
587 break;
588 }
589 break;
590 }
591 case '4':
592 {
593 /*
594 Convert PBM raw image to pixel packets.
595 */
596 (void) SetImageColorspace(image,GRAYColorspace,exception);
597 quantum_type=GrayQuantum;
598 if (image->storage_class == PseudoClass)
599 quantum_type=IndexQuantum;
600 quantum_info=AcquireQuantumInfo(image_info,image);
601 if (quantum_info == (QuantumInfo *) NULL)
602 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
603 SetQuantumMinIsWhite(quantum_info,MagickTrue);
604 extent=GetQuantumExtent(image,quantum_info,quantum_type);
605 for (y=0; y < (ssize_t) image->rows; y++)
606 {
607 const unsigned char
608 *pixels;
609
610 MagickBooleanType
611 sync;
612
613 register Quantum
614 *magick_restrict q;
615
616 ssize_t
617 offset;
618
619 size_t
620 length;
621
622 pixels=(unsigned char *) ReadBlobStream(image,extent,
623 GetQuantumPixels(quantum_info),&count);
624 if (count != (ssize_t) extent)
625 break;
626 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
627 (image->previous == (Image *) NULL))
628 {
629 MagickBooleanType
630 proceed;
631
632 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
633 row,image->rows);
634 if (proceed == MagickFalse)
635 break;
636 }
637 offset=row++;
638 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
639 if (q == (Quantum *) NULL)
640 break;
641 length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
642 quantum_type,pixels,exception);
643 if (length != extent)
644 break;
645 sync=SyncAuthenticPixels(image,exception);
646 if (sync == MagickFalse)
647 break;
648 }
649 quantum_info=DestroyQuantumInfo(quantum_info);
650 SetQuantumImageType(image,quantum_type);
651 break;
652 }
653 case '5':
654 {
655 /*
656 Convert PGM raw image to pixel packets.
657 */
658 (void) SetImageColorspace(image,GRAYColorspace,exception);
659 quantum_type=GrayQuantum;
660 extent=(image->depth <= 8 ? 1 : image->depth <= 16 ? 2 : 4)*
661 image->columns;
662 quantum_info=AcquireQuantumInfo(image_info,image);
663 if (quantum_info == (QuantumInfo *) NULL)
664 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
665 for (y=0; y < (ssize_t) image->rows; y++)
666 {
667 const unsigned char
668 *pixels;
669
670 MagickBooleanType
671 sync;
672
673 register const unsigned char
674 *magick_restrict p;
675
676 register ssize_t
677 x;
678
679 register Quantum
680 *magick_restrict q;
681
682 ssize_t
683 offset;
684
685 pixels=(unsigned char *) ReadBlobStream(image,extent,
686 GetQuantumPixels(quantum_info),&count);
687 if (count != (ssize_t) extent)
688 break;
689 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
690 (image->previous == (Image *) NULL))
691 {
692 MagickBooleanType
693 proceed;
694
695 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
696 row,image->rows);
697 if (proceed == MagickFalse)
698 break;
699 }
700 offset=row++;
701 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
702 if (q == (Quantum *) NULL)
703 break;
704 p=pixels;
705 switch (image->depth)
706 {
707 case 8:
708 case 16:
709 case 32:
710 {
711 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
712 quantum_type,pixels,exception);
713 break;
714 }
715 default:
716 {
717 if (image->depth <= 8)
718 {
719 unsigned char
720 pixel;
721
722 for (x=0; x < (ssize_t) image->columns; x++)
723 {
724 p=PushCharPixel(p,&pixel);
725 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
726 q+=GetPixelChannels(image);
727 }
728 }
729 else if (image->depth <= 16)
730 {
731 unsigned short
732 pixel;
733
734 for (x=0; x < (ssize_t) image->columns; x++)
735 {
736 p=PushShortPixel(MSBEndian,p,&pixel);
737 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
738 q+=GetPixelChannels(image);
739 }
740 }
741 else
742 {
743 unsigned int
744 pixel;
745
746 for (x=0; x < (ssize_t) image->columns; x++)
747 {
748 p=PushLongPixel(MSBEndian,p,&pixel);
749 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),q);
750 q+=GetPixelChannels(image);
751 }
752 }
753 break;
754 }
755 }
756 sync=SyncAuthenticPixels(image,exception);
757 if (sync == MagickFalse)
758 break;
759 }
760 quantum_info=DestroyQuantumInfo(quantum_info);
761 SetQuantumImageType(image,quantum_type);
762 break;
763 }
764 case '6':
765 {
766 /*
767 Convert PNM raster image to pixel packets.
768 */
769 quantum_type=RGBQuantum;
770 extent=3*(image->depth <= 8 ? 1 : image->depth <= 16 ? 2 : 4)*
771 image->columns;
772 quantum_info=AcquireQuantumInfo(image_info,image);
773 if (quantum_info == (QuantumInfo *) NULL)
774 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
775 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
776 for (y=0; y < (ssize_t) image->rows; y++)
777 {
778 const unsigned char
779 *pixels;
780
781 MagickBooleanType
782 sync;
783
784 register const unsigned char
785 *magick_restrict p;
786
787 register ssize_t
788 x;
789
790 register Quantum
791 *magick_restrict q;
792
793 ssize_t
794 offset;
795
796 pixels=(unsigned char *) ReadBlobStream(image,extent,
797 GetQuantumPixels(quantum_info),&count);
798 if (count != (ssize_t) extent)
799 break;
800 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
801 (image->previous == (Image *) NULL))
802 {
803 MagickBooleanType
804 proceed;
805
806 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
807 row,image->rows);
808 if (proceed == MagickFalse)
809 break;
810 }
811 offset=row++;
812 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
813 if (q == (Quantum *) NULL)
814 break;
815 p=pixels;
816 switch (image->depth)
817 {
818 case 8:
819 {
820 for (x=0; x < (ssize_t) image->columns; x++)
821 {
822 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
823 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
824 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
825 SetPixelAlpha(image,OpaqueAlpha,q);
826 q+=GetPixelChannels(image);
827 }
828 break;
829 }
830 case 16:
831 {
832 unsigned short
833 pixel;
834
835 for (x=0; x < (ssize_t) image->columns; x++)
836 {
837 p=PushShortPixel(MSBEndian,p,&pixel);
838 SetPixelRed(image,ScaleShortToQuantum(pixel),q);
839 p=PushShortPixel(MSBEndian,p,&pixel);
840 SetPixelGreen(image,ScaleShortToQuantum(pixel),q);
841 p=PushShortPixel(MSBEndian,p,&pixel);
842 SetPixelBlue(image,ScaleShortToQuantum(pixel),q);
843 SetPixelAlpha(image,OpaqueAlpha,q);
844 q+=GetPixelChannels(image);
845 }
846 break;
847 }
848 case 32:
849 {
850 unsigned int
851 pixel;
852
853 for (x=0; x < (ssize_t) image->columns; x++)
854 {
855 p=PushLongPixel(MSBEndian,p,&pixel);
856 SetPixelRed(image,ScaleLongToQuantum(pixel),q);
857 p=PushLongPixel(MSBEndian,p,&pixel);
858 SetPixelGreen(image,ScaleLongToQuantum(pixel),q);
859 p=PushLongPixel(MSBEndian,p,&pixel);
860 SetPixelBlue(image,ScaleLongToQuantum(pixel),q);
861 SetPixelAlpha(image,OpaqueAlpha,q);
862 q+=GetPixelChannels(image);
863 }
864 break;
865 }
866 default:
867 {
868 if (image->depth <= 8)
869 {
870 unsigned char
871 pixel;
872
873 for (x=0; x < (ssize_t) image->columns; x++)
874 {
875 p=PushCharPixel(p,&pixel);
876 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
877 p=PushCharPixel(p,&pixel);
878 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
879 p=PushCharPixel(p,&pixel);
880 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
881 SetPixelAlpha(image,OpaqueAlpha,q);
882 q+=GetPixelChannels(image);
883 }
884 }
885 else if (image->depth <= 16)
886 {
887 unsigned short
888 pixel;
889
890 for (x=0; x < (ssize_t) image->columns; x++)
891 {
892 p=PushShortPixel(MSBEndian,p,&pixel);
893 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
894 p=PushShortPixel(MSBEndian,p,&pixel);
895 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
896 p=PushShortPixel(MSBEndian,p,&pixel);
897 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
898 SetPixelAlpha(image,OpaqueAlpha,q);
899 q+=GetPixelChannels(image);
900 }
901 }
902 else
903 {
904 unsigned int
905 pixel;
906
907 for (x=0; x < (ssize_t) image->columns; x++)
908 {
909 p=PushLongPixel(MSBEndian,p,&pixel);
910 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
911 p=PushLongPixel(MSBEndian,p,&pixel);
912 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),q);
913 p=PushLongPixel(MSBEndian,p,&pixel);
914 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),q);
915 SetPixelAlpha(image,OpaqueAlpha,q);
916 q+=GetPixelChannels(image);
917 }
918 }
919 break;
920 }
921 }
922 sync=SyncAuthenticPixels(image,exception);
923 if (sync == MagickFalse)
924 break;
925 }
926 quantum_info=DestroyQuantumInfo(quantum_info);
927 break;
928 }
929 case '7':
930 {
931 size_t
932 channels;
933
934 /*
935 Convert PAM raster image to pixel packets.
936 */
937 switch (quantum_type)
938 {
939 case GrayQuantum:
940 case GrayAlphaQuantum:
941 {
942 channels=1;
943 break;
944 }
945 case CMYKQuantum:
946 case CMYKAQuantum:
947 {
948 channels=4;
949 break;
950 }
951 default:
952 {
953 channels=3;
954 break;
955 }
956 }
957 if (image->alpha_trait != UndefinedPixelTrait)
958 channels++;
959 extent=channels*(image->depth <= 8 ? 1 : image->depth <= 16 ? 2 : 4)*
960 image->columns;
961 quantum_info=AcquireQuantumInfo(image_info,image);
962 if (quantum_info == (QuantumInfo *) NULL)
963 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
964 for (y=0; y < (ssize_t) image->rows; y++)
965 {
966 const unsigned char
967 *pixels;
968
969 MagickBooleanType
970 sync;
971
972 register const unsigned char
973 *magick_restrict p;
974
975 register ssize_t
976 x;
977
978 register Quantum
979 *magick_restrict q;
980
981 ssize_t
982 offset;
983
984 pixels=(unsigned char *) ReadBlobStream(image,extent,
985 GetQuantumPixels(quantum_info),&count);
986 if (count != (ssize_t) extent)
987 break;
988 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
989 (image->previous == (Image *) NULL))
990 {
991 MagickBooleanType
992 proceed;
993
994 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
995 row,image->rows);
996 if (proceed == MagickFalse)
997 break;
998 }
999 offset=row++;
1000 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
1001 if (q == (Quantum *) NULL)
1002 break;
1003 p=pixels;
1004 switch (image->depth)
1005 {
1006 case 8:
1007 case 16:
1008 case 32:
1009 {
1010 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1011 quantum_type,pixels,exception);
1012 break;
1013 }
1014 default:
1015 {
1016 switch (quantum_type)
1017 {
1018 case GrayQuantum:
1019 case GrayAlphaQuantum:
1020 {
1021 if (image->depth <= 8)
1022 {
1023 unsigned char
1024 pixel;
1025
1026 for (x=0; x < (ssize_t) image->columns; x++)
1027 {
1028 p=PushCharPixel(p,&pixel);
1029 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),
1030 q);
1031 SetPixelAlpha(image,OpaqueAlpha,q);
1032 if (image->alpha_trait != UndefinedPixelTrait)
1033 {
1034 p=PushCharPixel(p,&pixel);
1035 if (image->depth != 1)
1036 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1037 max_value),q);
1038 else
1039 SetPixelAlpha(image,QuantumRange-
1040 ScaleAnyToQuantum(pixel,max_value),q);
1041 }
1042 q+=GetPixelChannels(image);
1043 }
1044 }
1045 else if (image->depth <= 16)
1046 {
1047 unsigned short
1048 pixel;
1049
1050 for (x=0; x < (ssize_t) image->columns; x++)
1051 {
1052 p=PushShortPixel(MSBEndian,p,&pixel);
1053 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),
1054 q);
1055 SetPixelAlpha(image,OpaqueAlpha,q);
1056 if (image->alpha_trait != UndefinedPixelTrait)
1057 {
1058 p=PushShortPixel(MSBEndian,p,&pixel);
1059 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1060 max_value),q);
1061 }
1062 q+=GetPixelChannels(image);
1063 }
1064 }
1065 else
1066 {
1067 unsigned int
1068 pixel;
1069
1070 for (x=0; x < (ssize_t) image->columns; x++)
1071 {
1072 p=PushLongPixel(MSBEndian,p,&pixel);
1073 SetPixelGray(image,ScaleAnyToQuantum(pixel,max_value),
1074 q);
1075 SetPixelAlpha(image,OpaqueAlpha,q);
1076 if (image->alpha_trait != UndefinedPixelTrait)
1077 {
1078 p=PushLongPixel(MSBEndian,p,&pixel);
1079 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1080 max_value),q);
1081 }
1082 q+=GetPixelChannels(image);
1083 }
1084 }
1085 break;
1086 }
1087 case CMYKQuantum:
1088 case CMYKAQuantum:
1089 {
1090 if (image->depth <= 8)
1091 {
1092 unsigned char
1093 pixel;
1094
1095 for (x=0; x < (ssize_t) image->columns; x++)
1096 {
1097 p=PushCharPixel(p,&pixel);
1098 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1099 p=PushCharPixel(p,&pixel);
1100 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1101 q);
1102 p=PushCharPixel(p,&pixel);
1103 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1104 q);
1105 p=PushCharPixel(p,&pixel);
1106 SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),
1107 q);
1108 SetPixelAlpha(image,OpaqueAlpha,q);
1109 if (image->alpha_trait != UndefinedPixelTrait)
1110 {
1111 p=PushCharPixel(p,&pixel);
1112 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1113 max_value),q);
1114 }
1115 q+=GetPixelChannels(image);
1116 }
1117 }
1118 else if (image->depth <= 16)
1119 {
1120 unsigned short
1121 pixel;
1122
1123 for (x=0; x < (ssize_t) image->columns; x++)
1124 {
1125 p=PushShortPixel(MSBEndian,p,&pixel);
1126 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1127 p=PushShortPixel(MSBEndian,p,&pixel);
1128 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1129 q);
1130 p=PushShortPixel(MSBEndian,p,&pixel);
1131 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1132 q);
1133 p=PushShortPixel(MSBEndian,p,&pixel);
1134 SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),
1135 q);
1136 SetPixelAlpha(image,OpaqueAlpha,q);
1137 if (image->alpha_trait != UndefinedPixelTrait)
1138 {
1139 p=PushShortPixel(MSBEndian,p,&pixel);
1140 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1141 max_value),q);
1142 }
1143 q+=GetPixelChannels(image);
1144 }
1145 }
1146 else
1147 {
1148 unsigned int
1149 pixel;
1150
1151 for (x=0; x < (ssize_t) image->columns; x++)
1152 {
1153 p=PushLongPixel(MSBEndian,p,&pixel);
1154 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),
1155 q);
1156 p=PushLongPixel(MSBEndian,p,&pixel);
1157 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1158 q);
1159 p=PushLongPixel(MSBEndian,p,&pixel);
1160 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1161 q);
1162 p=PushLongPixel(MSBEndian,p,&pixel);
1163 SetPixelBlack(image,ScaleAnyToQuantum(pixel,max_value),
1164 q);
1165 SetPixelAlpha(image,OpaqueAlpha,q);
1166 if (image->alpha_trait != UndefinedPixelTrait)
1167 {
1168 p=PushLongPixel(MSBEndian,p,&pixel);
1169 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1170 max_value),q);
1171 }
1172 q+=GetPixelChannels(image);
1173 }
1174 }
1175 break;
1176 }
1177 default:
1178 {
1179 if (image->depth <= 8)
1180 {
1181 unsigned char
1182 pixel;
1183
1184 for (x=0; x < (ssize_t) image->columns; x++)
1185 {
1186 p=PushCharPixel(p,&pixel);
1187 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1188 p=PushCharPixel(p,&pixel);
1189 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1190 q);
1191 p=PushCharPixel(p,&pixel);
1192 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1193 q);
1194 SetPixelAlpha(image,OpaqueAlpha,q);
1195 if (image->alpha_trait != UndefinedPixelTrait)
1196 {
1197 p=PushCharPixel(p,&pixel);
1198 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1199 max_value),q);
1200 }
1201 q+=GetPixelChannels(image);
1202 }
1203 }
1204 else if (image->depth <= 16)
1205 {
1206 unsigned short
1207 pixel;
1208
1209 for (x=0; x < (ssize_t) image->columns; x++)
1210 {
1211 p=PushShortPixel(MSBEndian,p,&pixel);
1212 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),q);
1213 p=PushShortPixel(MSBEndian,p,&pixel);
1214 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1215 q);
1216 p=PushShortPixel(MSBEndian,p,&pixel);
1217 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1218 q);
1219 SetPixelAlpha(image,OpaqueAlpha,q);
1220 if (image->alpha_trait != UndefinedPixelTrait)
1221 {
1222 p=PushShortPixel(MSBEndian,p,&pixel);
1223 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1224 max_value),q);
1225 }
1226 q+=GetPixelChannels(image);
1227 }
1228 }
1229 else
1230 {
1231 unsigned int
1232 pixel;
1233
1234 for (x=0; x < (ssize_t) image->columns; x++)
1235 {
1236 p=PushLongPixel(MSBEndian,p,&pixel);
1237 SetPixelRed(image,ScaleAnyToQuantum(pixel,max_value),
1238 q);
1239 p=PushLongPixel(MSBEndian,p,&pixel);
1240 SetPixelGreen(image,ScaleAnyToQuantum(pixel,max_value),
1241 q);
1242 p=PushLongPixel(MSBEndian,p,&pixel);
1243 SetPixelBlue(image,ScaleAnyToQuantum(pixel,max_value),
1244 q);
1245 SetPixelAlpha(image,OpaqueAlpha,q);
1246 if (image->alpha_trait != UndefinedPixelTrait)
1247 {
1248 p=PushLongPixel(MSBEndian,p,&pixel);
1249 SetPixelAlpha(image,ScaleAnyToQuantum(pixel,
1250 max_value),q);
1251 }
1252 q+=GetPixelChannels(image);
1253 }
1254 }
1255 break;
1256 }
1257 }
1258 }
1259 }
1260 sync=SyncAuthenticPixels(image,exception);
1261 if (sync == MagickFalse)
1262 break;
1263 }
1264 quantum_info=DestroyQuantumInfo(quantum_info);
1265 SetQuantumImageType(image,quantum_type);
1266 break;
1267 }
1268 case 'F':
1269 case 'f':
1270 {
1271 /*
1272 Convert PFM raster image to pixel packets.
1273 */
1274 if (format == 'f')
1275 (void) SetImageColorspace(image,GRAYColorspace,exception);
1276 quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
1277 image->endian=quantum_scale < 0.0 ? LSBEndian : MSBEndian;
1278 image->depth=32;
1279 quantum_info=AcquireQuantumInfo(image_info,image);
1280 if (quantum_info == (QuantumInfo *) NULL)
1281 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
1282 status=SetQuantumDepth(image,quantum_info,32);
1283 if (status == MagickFalse)
1284 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
1285 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1286 if (status == MagickFalse)
1287 ThrowPNMException(ResourceLimitError,"MemoryAllocationFailed");
1288 SetQuantumScale(quantum_info,(double) QuantumRange*fabs(quantum_scale));
1289 extent=GetQuantumExtent(image,quantum_info,quantum_type);
1290 for (y=0; y < (ssize_t) image->rows; y++)
1291 {
1292 const unsigned char
1293 *pixels;
1294
1295 MagickBooleanType
1296 sync;
1297
1298 register Quantum
1299 *magick_restrict q;
1300
1301 ssize_t
1302 offset;
1303
1304 size_t
1305 length;
1306
1307 pixels=(unsigned char *) ReadBlobStream(image,extent,
1308 GetQuantumPixels(quantum_info),&count);
1309 if (count != (ssize_t) extent)
1310 break;
1311 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1312 (image->previous == (Image *) NULL))
1313 {
1314 MagickBooleanType
1315 proceed;
1316
1317 proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType)
1318 row,image->rows);
1319 if (proceed == MagickFalse)
1320 break;
1321 }
1322 offset=row++;
1323 q=QueueAuthenticPixels(image,0,(ssize_t) (image->rows-offset-1),
1324 image->columns,1,exception);
1325 if (q == (Quantum *) NULL)
1326 break;
1327 length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1328 quantum_type,pixels,exception);
1329 if (length != extent)
1330 break;
1331 sync=SyncAuthenticPixels(image,exception);
1332 if (sync == MagickFalse)
1333 break;
1334 }
1335 quantum_info=DestroyQuantumInfo(quantum_info);
1336 SetQuantumImageType(image,quantum_type);
1337 break;
1338 }
1339 default:
1340 ThrowPNMException(CorruptImageError,"ImproperImageHeader");
1341 }
1342 if (*comment_info.comment != '\0')
1343 (void) SetImageProperty(image,"comment",comment_info.comment,exception);
1344 comment_info.comment=DestroyString(comment_info.comment);
1345 if (y < (ssize_t) image->rows)
1346 ThrowPNMException(CorruptImageError,"UnableToReadImageData");
1347 if (EOFBlob(image) != MagickFalse)
1348 {
1349 (void) ThrowMagickException(exception,GetMagickModule(),
1350 CorruptImageError,"UnexpectedEndOfFile","`%s'",image->filename);
1351 break;
1352 }
1353 /*
1354 Proceed to next image.
1355 */
1356 if (image_info->number_scenes != 0)
1357 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1358 break;
1359 if ((format == '1') || (format == '2') || (format == '3'))
1360 do
1361 {
1362 /*
1363 Skip to end of line.
1364 */
1365 count=ReadBlob(image,1,(unsigned char *) &format);
1366 if (count != 1)
1367 break;
1368 if (format == 'P')
1369 break;
1370 } while (format != '\n');
1371 count=ReadBlob(image,1,(unsigned char *) &format);
1372 if ((count == 1) && (format == 'P'))
1373 {
1374 /*
1375 Allocate next image structure.
1376 */
1377 AcquireNextImage(image_info,image,exception);
1378 if (GetNextImageInList(image) == (Image *) NULL)
1379 {
1380 status=MagickFalse;
1381 break;
1382 }
1383 image=SyncNextImageInList(image);
1384 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1385 GetBlobSize(image));
1386 if (status == MagickFalse)
1387 break;
1388 }
1389 } while ((count == 1) && (format == 'P'));
1390 (void) CloseBlob(image);
1391 if (status == MagickFalse)
1392 return(DestroyImageList(image));
1393 return(GetFirstImageInList(image));
1394 }
1395
1396 /*
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 % %
1399 % %
1400 % %
1401 % R e g i s t e r P N M I m a g e %
1402 % %
1403 % %
1404 % %
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 %
1407 % RegisterPNMImage() adds properties for the PNM image format to
1408 % the list of supported formats. The properties include the image format
1409 % tag, a method to read and/or write the format, whether the format
1410 % supports the saving of more than one frame to the same file or blob,
1411 % whether the format supports native in-memory I/O, and a brief
1412 % description of the format.
1413 %
1414 % The format of the RegisterPNMImage method is:
1415 %
1416 % size_t RegisterPNMImage(void)
1417 %
1418 */
RegisterPNMImage(void)1419 ModuleExport size_t RegisterPNMImage(void)
1420 {
1421 MagickInfo
1422 *entry;
1423
1424 entry=AcquireMagickInfo("PNM","PAM","Common 2-dimensional bitmap format");
1425 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1426 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1427 entry->mime_type=ConstantString("image/x-portable-pixmap");
1428 entry->flags|=CoderDecoderSeekableStreamFlag;
1429 (void) RegisterMagickInfo(entry);
1430 entry=AcquireMagickInfo("PNM","PBM",
1431 "Portable bitmap format (black and white)");
1432 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1433 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1434 entry->mime_type=ConstantString("image/x-portable-bitmap");
1435 entry->flags|=CoderDecoderSeekableStreamFlag;
1436 (void) RegisterMagickInfo(entry);
1437 entry=AcquireMagickInfo("PNM","PFM","Portable float format");
1438 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1439 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1440 entry->flags|=CoderEndianSupportFlag;
1441 entry->flags|=CoderDecoderSeekableStreamFlag;
1442 (void) RegisterMagickInfo(entry);
1443 entry=AcquireMagickInfo("PNM","PGM","Portable graymap format (gray scale)");
1444 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1445 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1446 entry->mime_type=ConstantString("image/x-portable-greymap");
1447 entry->flags|=CoderDecoderSeekableStreamFlag;
1448 (void) RegisterMagickInfo(entry);
1449 entry=AcquireMagickInfo("PNM","PNM","Portable anymap");
1450 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1451 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1452 entry->magick=(IsImageFormatHandler *) IsPNM;
1453 entry->mime_type=ConstantString("image/x-portable-pixmap");
1454 entry->flags|=CoderDecoderSeekableStreamFlag;
1455 (void) RegisterMagickInfo(entry);
1456 entry=AcquireMagickInfo("PNM","PPM","Portable pixmap format (color)");
1457 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1458 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1459 entry->mime_type=ConstantString("image/x-portable-pixmap");
1460 entry->flags|=CoderDecoderSeekableStreamFlag;
1461 (void) RegisterMagickInfo(entry);
1462 return(MagickImageCoderSignature);
1463 }
1464
1465 /*
1466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467 % %
1468 % %
1469 % %
1470 % U n r e g i s t e r P N M I m a g e %
1471 % %
1472 % %
1473 % %
1474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475 %
1476 % UnregisterPNMImage() removes format registrations made by the
1477 % PNM module from the list of supported formats.
1478 %
1479 % The format of the UnregisterPNMImage method is:
1480 %
1481 % UnregisterPNMImage(void)
1482 %
1483 */
UnregisterPNMImage(void)1484 ModuleExport void UnregisterPNMImage(void)
1485 {
1486 (void) UnregisterMagickInfo("PAM");
1487 (void) UnregisterMagickInfo("PBM");
1488 (void) UnregisterMagickInfo("PGM");
1489 (void) UnregisterMagickInfo("PNM");
1490 (void) UnregisterMagickInfo("PPM");
1491 }
1492
1493 /*
1494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495 % %
1496 % %
1497 % %
1498 % W r i t e P N M I m a g e %
1499 % %
1500 % %
1501 % %
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503 %
1504 % WritePNMImage() writes an image to a file in the PNM rasterfile format.
1505 %
1506 % The format of the WritePNMImage method is:
1507 %
1508 % MagickBooleanType WritePNMImage(const ImageInfo *image_info,
1509 % Image *image,ExceptionInfo *exception)
1510 %
1511 % A description of each parameter follows.
1512 %
1513 % o image_info: the image info.
1514 %
1515 % o image: The image.
1516 %
1517 % o exception: return any errors or warnings in this structure.
1518 %
1519 */
WritePNMImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1520 static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image,
1521 ExceptionInfo *exception)
1522 {
1523 char
1524 buffer[MagickPathExtent],
1525 format,
1526 magick[MagickPathExtent];
1527
1528 const char
1529 *value;
1530
1531 MagickBooleanType
1532 status;
1533
1534 MagickOffsetType
1535 scene;
1536
1537 Quantum
1538 index;
1539
1540 QuantumAny
1541 pixel;
1542
1543 QuantumInfo
1544 *quantum_info;
1545
1546 QuantumType
1547 quantum_type;
1548
1549 register unsigned char
1550 *q;
1551
1552 size_t
1553 extent,
1554 imageListLength,
1555 packet_size;
1556
1557 ssize_t
1558 count,
1559 y;
1560
1561 /*
1562 Open output image file.
1563 */
1564 assert(image_info != (const ImageInfo *) NULL);
1565 assert(image_info->signature == MagickCoreSignature);
1566 assert(image != (Image *) NULL);
1567 assert(image->signature == MagickCoreSignature);
1568 if (image->debug != MagickFalse)
1569 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1570 assert(exception != (ExceptionInfo *) NULL);
1571 assert(exception->signature == MagickCoreSignature);
1572 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1573 if (status == MagickFalse)
1574 return(status);
1575 scene=0;
1576 imageListLength=GetImageListLength(image);
1577 do
1578 {
1579 QuantumAny
1580 max_value;
1581
1582 /*
1583 Write PNM file header.
1584 */
1585 packet_size=3;
1586 quantum_type=RGBQuantum;
1587 (void) CopyMagickString(magick,image_info->magick,MagickPathExtent);
1588 max_value=GetQuantumRange(image->depth);
1589 switch (magick[1])
1590 {
1591 case 'A':
1592 case 'a':
1593 {
1594 format='7';
1595 break;
1596 }
1597 case 'B':
1598 case 'b':
1599 {
1600 format='4';
1601 if (image_info->compression == NoCompression)
1602 format='1';
1603 break;
1604 }
1605 case 'F':
1606 case 'f':
1607 {
1608 format='F';
1609 if (SetImageGray(image,exception) != MagickFalse)
1610 format='f';
1611 break;
1612 }
1613 case 'G':
1614 case 'g':
1615 {
1616 format='5';
1617 if (image_info->compression == NoCompression)
1618 format='2';
1619 break;
1620 }
1621 case 'N':
1622 case 'n':
1623 {
1624 if ((image_info->type != TrueColorType) &&
1625 (SetImageGray(image,exception) != MagickFalse))
1626 {
1627 format='5';
1628 if (image_info->compression == NoCompression)
1629 format='2';
1630 if (SetImageMonochrome(image,exception) != MagickFalse)
1631 {
1632 format='4';
1633 if (image_info->compression == NoCompression)
1634 format='1';
1635 }
1636 break;
1637 }
1638 }
1639 default:
1640 {
1641 format='6';
1642 if (image_info->compression == NoCompression)
1643 format='3';
1644 break;
1645 }
1646 }
1647 (void) FormatLocaleString(buffer,MagickPathExtent,"P%c\n",format);
1648 (void) WriteBlobString(image,buffer);
1649 value=GetImageProperty(image,"comment",exception);
1650 if (value != (const char *) NULL)
1651 {
1652 register const char
1653 *p;
1654
1655 /*
1656 Write comments to file.
1657 */
1658 (void) WriteBlobByte(image,'#');
1659 for (p=value; *p != '\0'; p++)
1660 {
1661 (void) WriteBlobByte(image,(unsigned char) *p);
1662 if ((*p == '\n') || (*p == '\r'))
1663 (void) WriteBlobByte(image,'#');
1664 }
1665 (void) WriteBlobByte(image,'\n');
1666 }
1667 if (format != '7')
1668 {
1669 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g %.20g\n",
1670 (double) image->columns,(double) image->rows);
1671 (void) WriteBlobString(image,buffer);
1672 }
1673 else
1674 {
1675 char
1676 type[MagickPathExtent];
1677
1678 /*
1679 PAM header.
1680 */
1681 (void) FormatLocaleString(buffer,MagickPathExtent,
1682 "WIDTH %.20g\nHEIGHT %.20g\n",(double) image->columns,(double)
1683 image->rows);
1684 (void) WriteBlobString(image,buffer);
1685 quantum_type=GetQuantumType(image,exception);
1686 switch (quantum_type)
1687 {
1688 case CMYKQuantum:
1689 case CMYKAQuantum:
1690 {
1691 packet_size=4;
1692 (void) CopyMagickString(type,"CMYK",MagickPathExtent);
1693 break;
1694 }
1695 case GrayQuantum:
1696 case GrayAlphaQuantum:
1697 {
1698 packet_size=1;
1699 (void) CopyMagickString(type,"GRAYSCALE",MagickPathExtent);
1700 if (IdentifyImageMonochrome(image,exception) != MagickFalse)
1701 (void) CopyMagickString(type,"BLACKANDWHITE",MagickPathExtent);
1702 break;
1703 }
1704 default:
1705 {
1706 quantum_type=RGBQuantum;
1707 if (image->alpha_trait != UndefinedPixelTrait)
1708 quantum_type=RGBAQuantum;
1709 packet_size=3;
1710 (void) CopyMagickString(type,"RGB",MagickPathExtent);
1711 break;
1712 }
1713 }
1714 if (image->alpha_trait != UndefinedPixelTrait)
1715 {
1716 packet_size++;
1717 (void) ConcatenateMagickString(type,"_ALPHA",MagickPathExtent);
1718 }
1719 if (image->depth > 32)
1720 image->depth=32;
1721 (void) FormatLocaleString(buffer,MagickPathExtent,
1722 "DEPTH %.20g\nMAXVAL %.20g\n",(double) packet_size,(double)
1723 ((MagickOffsetType) GetQuantumRange(image->depth)));
1724 (void) WriteBlobString(image,buffer);
1725 (void) FormatLocaleString(buffer,MagickPathExtent,
1726 "TUPLTYPE %s\nENDHDR\n",type);
1727 (void) WriteBlobString(image,buffer);
1728 }
1729 /*
1730 Convert runextent encoded to PNM raster pixels.
1731 */
1732 switch (format)
1733 {
1734 case '1':
1735 {
1736 unsigned char
1737 pixels[2048];
1738
1739 /*
1740 Convert image to a PBM image.
1741 */
1742 (void) SetImageType(image,BilevelType,exception);
1743 q=pixels;
1744 for (y=0; y < (ssize_t) image->rows; y++)
1745 {
1746 register const Quantum
1747 *magick_restrict p;
1748
1749 register ssize_t
1750 x;
1751
1752 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1753 if (p == (const Quantum *) NULL)
1754 break;
1755 for (x=0; x < (ssize_t) image->columns; x++)
1756 {
1757 *q++=(unsigned char) (GetPixelLuma(image,p) >= (QuantumRange/2.0) ?
1758 '0' : '1');
1759 *q++=' ';
1760 if ((q-pixels+1) >= (ssize_t) sizeof(pixels))
1761 {
1762 *q++='\n';
1763 (void) WriteBlob(image,q-pixels,pixels);
1764 q=pixels;
1765 }
1766 p+=GetPixelChannels(image);
1767 }
1768 *q++='\n';
1769 (void) WriteBlob(image,q-pixels,pixels);
1770 q=pixels;
1771 if (image->previous == (Image *) NULL)
1772 {
1773 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1774 image->rows);
1775 if (status == MagickFalse)
1776 break;
1777 }
1778 }
1779 if (q != pixels)
1780 {
1781 *q++='\n';
1782 (void) WriteBlob(image,q-pixels,pixels);
1783 }
1784 break;
1785 }
1786 case '2':
1787 {
1788 unsigned char
1789 pixels[2048];
1790
1791 /*
1792 Convert image to a PGM image.
1793 */
1794 if (image->depth <= 8)
1795 (void) WriteBlobString(image,"255\n");
1796 else
1797 if (image->depth <= 16)
1798 (void) WriteBlobString(image,"65535\n");
1799 else
1800 (void) WriteBlobString(image,"4294967295\n");
1801 q=pixels;
1802 for (y=0; y < (ssize_t) image->rows; y++)
1803 {
1804 register const Quantum
1805 *magick_restrict p;
1806
1807 register ssize_t
1808 x;
1809
1810 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1811 if (p == (const Quantum *) NULL)
1812 break;
1813 for (x=0; x < (ssize_t) image->columns; x++)
1814 {
1815 index=ClampToQuantum(GetPixelLuma(image,p));
1816 if (image->depth <= 8)
1817 count=(ssize_t) FormatLocaleString(buffer,MagickPathExtent,"%u ",
1818 ScaleQuantumToChar(index));
1819 else
1820 if (image->depth <= 16)
1821 count=(ssize_t) FormatLocaleString(buffer,MagickPathExtent,
1822 "%u ",ScaleQuantumToShort(index));
1823 else
1824 count=(ssize_t) FormatLocaleString(buffer,MagickPathExtent,
1825 "%u ",ScaleQuantumToLong(index));
1826 extent=(size_t) count;
1827 (void) strncpy((char *) q,buffer,extent);
1828 q+=extent;
1829 if ((q-pixels+extent+1) >= sizeof(pixels))
1830 {
1831 *q++='\n';
1832 (void) WriteBlob(image,q-pixels,pixels);
1833 q=pixels;
1834 }
1835 p+=GetPixelChannels(image);
1836 }
1837 *q++='\n';
1838 (void) WriteBlob(image,q-pixels,pixels);
1839 q=pixels;
1840 if (image->previous == (Image *) NULL)
1841 {
1842 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1843 image->rows);
1844 if (status == MagickFalse)
1845 break;
1846 }
1847 }
1848 if (q != pixels)
1849 {
1850 *q++='\n';
1851 (void) WriteBlob(image,q-pixels,pixels);
1852 }
1853 break;
1854 }
1855 case '3':
1856 {
1857 unsigned char
1858 pixels[2048];
1859
1860 /*
1861 Convert image to a PNM image.
1862 */
1863 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1864 if (image->depth <= 8)
1865 (void) WriteBlobString(image,"255\n");
1866 else
1867 if (image->depth <= 16)
1868 (void) WriteBlobString(image,"65535\n");
1869 else
1870 (void) WriteBlobString(image,"4294967295\n");
1871 q=pixels;
1872 for (y=0; y < (ssize_t) image->rows; y++)
1873 {
1874 register const Quantum
1875 *magick_restrict p;
1876
1877 register ssize_t
1878 x;
1879
1880 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1881 if (p == (const Quantum *) NULL)
1882 break;
1883 for (x=0; x < (ssize_t) image->columns; x++)
1884 {
1885 if (image->depth <= 8)
1886 count=(ssize_t) FormatLocaleString(buffer,MagickPathExtent,
1887 "%u %u %u ",ScaleQuantumToChar(GetPixelRed(image,p)),
1888 ScaleQuantumToChar(GetPixelGreen(image,p)),
1889 ScaleQuantumToChar(GetPixelBlue(image,p)));
1890 else
1891 if (image->depth <= 16)
1892 count=(ssize_t) FormatLocaleString(buffer,MagickPathExtent,
1893 "%u %u %u ",ScaleQuantumToShort(GetPixelRed(image,p)),
1894 ScaleQuantumToShort(GetPixelGreen(image,p)),
1895 ScaleQuantumToShort(GetPixelBlue(image,p)));
1896 else
1897 count=(ssize_t) FormatLocaleString(buffer,MagickPathExtent,
1898 "%u %u %u ",ScaleQuantumToLong(GetPixelRed(image,p)),
1899 ScaleQuantumToLong(GetPixelGreen(image,p)),
1900 ScaleQuantumToLong(GetPixelBlue(image,p)));
1901 extent=(size_t) count;
1902 (void) strncpy((char *) q,buffer,extent);
1903 q+=extent;
1904 if ((q-pixels+extent+1) >= sizeof(pixels))
1905 {
1906 *q++='\n';
1907 (void) WriteBlob(image,q-pixels,pixels);
1908 q=pixels;
1909 }
1910 p+=GetPixelChannels(image);
1911 }
1912 *q++='\n';
1913 (void) WriteBlob(image,q-pixels,pixels);
1914 q=pixels;
1915 if (image->previous == (Image *) NULL)
1916 {
1917 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1918 image->rows);
1919 if (status == MagickFalse)
1920 break;
1921 }
1922 }
1923 if (q != pixels)
1924 {
1925 *q++='\n';
1926 (void) WriteBlob(image,q-pixels,pixels);
1927 }
1928 break;
1929 }
1930 case '4':
1931 {
1932 register unsigned char
1933 *pixels;
1934
1935 /*
1936 Convert image to a PBM image.
1937 */
1938 (void) SetImageType(image,BilevelType,exception);
1939 image->depth=1;
1940 quantum_info=AcquireQuantumInfo(image_info,image);
1941 if (quantum_info == (QuantumInfo *) NULL)
1942 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1943 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
1944 quantum_info->min_is_white=MagickTrue;
1945 pixels=GetQuantumPixels(quantum_info);
1946 for (y=0; y < (ssize_t) image->rows; y++)
1947 {
1948 register const Quantum
1949 *magick_restrict p;
1950
1951 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1952 if (p == (const Quantum *) NULL)
1953 break;
1954 extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1955 GrayQuantum,pixels,exception);
1956 count=WriteBlob(image,extent,pixels);
1957 if (count != (ssize_t) extent)
1958 break;
1959 if (image->previous == (Image *) NULL)
1960 {
1961 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1962 image->rows);
1963 if (status == MagickFalse)
1964 break;
1965 }
1966 }
1967 quantum_info=DestroyQuantumInfo(quantum_info);
1968 break;
1969 }
1970 case '5':
1971 {
1972 register unsigned char
1973 *pixels;
1974
1975 /*
1976 Convert image to a PGM image.
1977 */
1978 if (image->depth > 32)
1979 image->depth=32;
1980 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
1981 ((MagickOffsetType) GetQuantumRange(image->depth)));
1982 (void) WriteBlobString(image,buffer);
1983 quantum_info=AcquireQuantumInfo(image_info,image);
1984 if (quantum_info == (QuantumInfo *) NULL)
1985 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1986 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
1987 quantum_info->min_is_white=MagickTrue;
1988 pixels=GetQuantumPixels(quantum_info);
1989 extent=GetQuantumExtent(image,quantum_info,GrayQuantum);
1990 for (y=0; y < (ssize_t) image->rows; y++)
1991 {
1992 register const Quantum
1993 *magick_restrict p;
1994
1995 register ssize_t
1996 x;
1997
1998 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1999 if (p == (const Quantum *) NULL)
2000 break;
2001 q=pixels;
2002 switch (image->depth)
2003 {
2004 case 8:
2005 case 16:
2006 case 32:
2007 {
2008 extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2009 GrayQuantum,pixels,exception);
2010 break;
2011 }
2012 default:
2013 {
2014 if (image->depth <= 8)
2015 {
2016 for (x=0; x < (ssize_t) image->columns; x++)
2017 {
2018 if (IsPixelGray(image,p) == MagickFalse)
2019 pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2020 image,p)),max_value);
2021 else
2022 {
2023 if (image->depth == 8)
2024 pixel=ScaleQuantumToChar(GetPixelRed(image,p));
2025 else
2026 pixel=ScaleQuantumToAny(GetPixelRed(image,p),
2027 max_value);
2028 }
2029 q=PopCharPixel((unsigned char) pixel,q);
2030 p+=GetPixelChannels(image);
2031 }
2032 extent=(size_t) (q-pixels);
2033 break;
2034 }
2035 if (image->depth <= 16)
2036 {
2037 for (x=0; x < (ssize_t) image->columns; x++)
2038 {
2039 if (IsPixelGray(image,p) == MagickFalse)
2040 pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,
2041 p)),max_value);
2042 else
2043 {
2044 if (image->depth == 16)
2045 pixel=ScaleQuantumToShort(GetPixelRed(image,p));
2046 else
2047 pixel=ScaleQuantumToAny(GetPixelRed(image,p),
2048 max_value);
2049 }
2050 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2051 p+=GetPixelChannels(image);
2052 }
2053 extent=(size_t) (q-pixels);
2054 break;
2055 }
2056 for (x=0; x < (ssize_t) image->columns; x++)
2057 {
2058 if (IsPixelGray(image,p) == MagickFalse)
2059 pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,p)),
2060 max_value);
2061 else
2062 {
2063 if (image->depth == 16)
2064 pixel=ScaleQuantumToLong(GetPixelRed(image,p));
2065 else
2066 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2067 }
2068 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2069 p+=GetPixelChannels(image);
2070 }
2071 extent=(size_t) (q-pixels);
2072 break;
2073 }
2074 }
2075 count=WriteBlob(image,extent,pixels);
2076 if (count != (ssize_t) extent)
2077 break;
2078 if (image->previous == (Image *) NULL)
2079 {
2080 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2081 image->rows);
2082 if (status == MagickFalse)
2083 break;
2084 }
2085 }
2086 quantum_info=DestroyQuantumInfo(quantum_info);
2087 break;
2088 }
2089 case '6':
2090 {
2091 register unsigned char
2092 *pixels;
2093
2094 /*
2095 Convert image to a PNM image.
2096 */
2097 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2098 if (image->depth > 32)
2099 image->depth=32;
2100 (void) FormatLocaleString(buffer,MagickPathExtent,"%.20g\n",(double)
2101 ((MagickOffsetType) GetQuantumRange(image->depth)));
2102 (void) WriteBlobString(image,buffer);
2103 quantum_info=AcquireQuantumInfo(image_info,image);
2104 if (quantum_info == (QuantumInfo *) NULL)
2105 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2106 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
2107 pixels=GetQuantumPixels(quantum_info);
2108 extent=GetQuantumExtent(image,quantum_info,quantum_type);
2109 for (y=0; y < (ssize_t) image->rows; y++)
2110 {
2111 register const Quantum
2112 *magick_restrict p;
2113
2114 register ssize_t
2115 x;
2116
2117 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2118 if (p == (const Quantum *) NULL)
2119 break;
2120 q=pixels;
2121 switch (image->depth)
2122 {
2123 case 8:
2124 case 16:
2125 case 32:
2126 {
2127 extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2128 quantum_type,pixels,exception);
2129 break;
2130 }
2131 default:
2132 {
2133 if (image->depth <= 8)
2134 {
2135 for (x=0; x < (ssize_t) image->columns; x++)
2136 {
2137 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2138 q=PopCharPixel((unsigned char) pixel,q);
2139 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2140 q=PopCharPixel((unsigned char) pixel,q);
2141 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2142 q=PopCharPixel((unsigned char) pixel,q);
2143 p+=GetPixelChannels(image);
2144 }
2145 extent=(size_t) (q-pixels);
2146 break;
2147 }
2148 if (image->depth <= 16)
2149 {
2150 for (x=0; x < (ssize_t) image->columns; x++)
2151 {
2152 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2153 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2154 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2155 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2156 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2157 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2158 p+=GetPixelChannels(image);
2159 }
2160 extent=(size_t) (q-pixels);
2161 break;
2162 }
2163 for (x=0; x < (ssize_t) image->columns; x++)
2164 {
2165 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2166 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2167 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2168 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2169 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2170 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2171 p+=GetPixelChannels(image);
2172 }
2173 extent=(size_t) (q-pixels);
2174 break;
2175 }
2176 }
2177 count=WriteBlob(image,extent,pixels);
2178 if (count != (ssize_t) extent)
2179 break;
2180 if (image->previous == (Image *) NULL)
2181 {
2182 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2183 image->rows);
2184 if (status == MagickFalse)
2185 break;
2186 }
2187 }
2188 quantum_info=DestroyQuantumInfo(quantum_info);
2189 break;
2190 }
2191 case '7':
2192 {
2193 register unsigned char
2194 *pixels;
2195
2196 /*
2197 Convert image to a PAM.
2198 */
2199 if (image->depth > 32)
2200 image->depth=32;
2201 quantum_info=AcquireQuantumInfo(image_info,image);
2202 if (quantum_info == (QuantumInfo *) NULL)
2203 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2204 (void) SetQuantumEndian(image,quantum_info,MSBEndian);
2205 pixels=GetQuantumPixels(quantum_info);
2206 for (y=0; y < (ssize_t) image->rows; y++)
2207 {
2208 register const Quantum
2209 *magick_restrict p;
2210
2211 register ssize_t
2212 x;
2213
2214 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2215 if (p == (const Quantum *) NULL)
2216 break;
2217 q=pixels;
2218 switch (image->depth)
2219 {
2220 case 8:
2221 case 16:
2222 case 32:
2223 {
2224 extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2225 quantum_type,pixels,exception);
2226 break;
2227 }
2228 default:
2229 {
2230 switch (quantum_type)
2231 {
2232 case GrayQuantum:
2233 case GrayAlphaQuantum:
2234 {
2235 if (image->depth <= 8)
2236 {
2237 for (x=0; x < (ssize_t) image->columns; x++)
2238 {
2239 pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2240 image,p)),max_value);
2241 q=PopCharPixel((unsigned char) pixel,q);
2242 if (image->alpha_trait != UndefinedPixelTrait)
2243 {
2244 pixel=(unsigned char) ScaleQuantumToAny(
2245 GetPixelAlpha(image,p),max_value);
2246 q=PopCharPixel((unsigned char) pixel,q);
2247 }
2248 p+=GetPixelChannels(image);
2249 }
2250 break;
2251 }
2252 if (image->depth <= 16)
2253 {
2254 for (x=0; x < (ssize_t) image->columns; x++)
2255 {
2256 pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(
2257 image,p)),max_value);
2258 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2259 if (image->alpha_trait != UndefinedPixelTrait)
2260 {
2261 pixel=(unsigned char) ScaleQuantumToAny(
2262 GetPixelAlpha(image,p),max_value);
2263 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2264 }
2265 p+=GetPixelChannels(image);
2266 }
2267 break;
2268 }
2269 for (x=0; x < (ssize_t) image->columns; x++)
2270 {
2271 pixel=ScaleQuantumToAny(ClampToQuantum(GetPixelLuma(image,
2272 p)),max_value);
2273 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2274 if (image->alpha_trait != UndefinedPixelTrait)
2275 {
2276 pixel=(unsigned char) ScaleQuantumToAny(
2277 GetPixelAlpha(image,p),max_value);
2278 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2279 }
2280 p+=GetPixelChannels(image);
2281 }
2282 break;
2283 }
2284 case CMYKQuantum:
2285 case CMYKAQuantum:
2286 {
2287 if (image->depth <= 8)
2288 {
2289 for (x=0; x < (ssize_t) image->columns; x++)
2290 {
2291 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2292 q=PopCharPixel((unsigned char) pixel,q);
2293 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2294 max_value);
2295 q=PopCharPixel((unsigned char) pixel,q);
2296 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2297 max_value);
2298 q=PopCharPixel((unsigned char) pixel,q);
2299 pixel=ScaleQuantumToAny(GetPixelBlack(image,p),
2300 max_value);
2301 q=PopCharPixel((unsigned char) pixel,q);
2302 if (image->alpha_trait != UndefinedPixelTrait)
2303 {
2304 pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2305 max_value);
2306 q=PopCharPixel((unsigned char) pixel,q);
2307 }
2308 p+=GetPixelChannels(image);
2309 }
2310 break;
2311 }
2312 if (image->depth <= 16)
2313 {
2314 for (x=0; x < (ssize_t) image->columns; x++)
2315 {
2316 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2317 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2318 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2319 max_value);
2320 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2321 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2322 max_value);
2323 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2324 pixel=ScaleQuantumToAny(GetPixelBlack(image,p),
2325 max_value);
2326 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2327 if (image->alpha_trait != UndefinedPixelTrait)
2328 {
2329 pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2330 max_value);
2331 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2332 }
2333 p+=GetPixelChannels(image);
2334 }
2335 break;
2336 }
2337 for (x=0; x < (ssize_t) image->columns; x++)
2338 {
2339 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2340 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2341 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2342 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2343 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2344 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2345 pixel=ScaleQuantumToAny(GetPixelBlack(image,p),max_value);
2346 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2347 if (image->alpha_trait != UndefinedPixelTrait)
2348 {
2349 pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2350 max_value);
2351 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2352 }
2353 p+=GetPixelChannels(image);
2354 }
2355 break;
2356 }
2357 default:
2358 {
2359 if (image->depth <= 8)
2360 {
2361 for (x=0; x < (ssize_t) image->columns; x++)
2362 {
2363 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2364 q=PopCharPixel((unsigned char) pixel,q);
2365 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2366 max_value);
2367 q=PopCharPixel((unsigned char) pixel,q);
2368 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2369 max_value);
2370 q=PopCharPixel((unsigned char) pixel,q);
2371 if (image->alpha_trait != UndefinedPixelTrait)
2372 {
2373 pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2374 max_value);
2375 q=PopCharPixel((unsigned char) pixel,q);
2376 }
2377 p+=GetPixelChannels(image);
2378 }
2379 break;
2380 }
2381 if (image->depth <= 16)
2382 {
2383 for (x=0; x < (ssize_t) image->columns; x++)
2384 {
2385 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2386 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2387 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),
2388 max_value);
2389 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2390 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),
2391 max_value);
2392 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2393 if (image->alpha_trait != UndefinedPixelTrait)
2394 {
2395 pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2396 max_value);
2397 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2398 }
2399 p+=GetPixelChannels(image);
2400 }
2401 break;
2402 }
2403 for (x=0; x < (ssize_t) image->columns; x++)
2404 {
2405 pixel=ScaleQuantumToAny(GetPixelRed(image,p),max_value);
2406 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2407 pixel=ScaleQuantumToAny(GetPixelGreen(image,p),max_value);
2408 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2409 pixel=ScaleQuantumToAny(GetPixelBlue(image,p),max_value);
2410 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2411 if (image->alpha_trait != UndefinedPixelTrait)
2412 {
2413 pixel=ScaleQuantumToAny(GetPixelAlpha(image,p),
2414 max_value);
2415 q=PopLongPixel(MSBEndian,(unsigned int) pixel,q);
2416 }
2417 p+=GetPixelChannels(image);
2418 }
2419 break;
2420 }
2421 }
2422 extent=(size_t) (q-pixels);
2423 break;
2424 }
2425 }
2426 count=WriteBlob(image,extent,pixels);
2427 if (count != (ssize_t) extent)
2428 break;
2429 if (image->previous == (Image *) NULL)
2430 {
2431 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2432 image->rows);
2433 if (status == MagickFalse)
2434 break;
2435 }
2436 }
2437 quantum_info=DestroyQuantumInfo(quantum_info);
2438 break;
2439 }
2440 case 'F':
2441 case 'f':
2442 {
2443 register unsigned char
2444 *pixels;
2445
2446 (void) WriteBlobString(image,image->endian == LSBEndian ? "-1.0\n" :
2447 "1.0\n");
2448 image->depth=32;
2449 quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
2450 quantum_info=AcquireQuantumInfo(image_info,image);
2451 if (quantum_info == (QuantumInfo *) NULL)
2452 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2453 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2454 if (status == MagickFalse)
2455 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2456 pixels=GetQuantumPixels(quantum_info);
2457 for (y=(ssize_t) image->rows-1; y >= 0; y--)
2458 {
2459 register const Quantum
2460 *magick_restrict p;
2461
2462 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2463 if (p == (const Quantum *) NULL)
2464 break;
2465 extent=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2466 quantum_type,pixels,exception);
2467 (void) WriteBlob(image,extent,pixels);
2468 if (image->previous == (Image *) NULL)
2469 {
2470 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2471 image->rows);
2472 if (status == MagickFalse)
2473 break;
2474 }
2475 }
2476 quantum_info=DestroyQuantumInfo(quantum_info);
2477 break;
2478 }
2479 }
2480 if (GetNextImageInList(image) == (Image *) NULL)
2481 break;
2482 image=SyncNextImageInList(image);
2483 status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
2484 if (status == MagickFalse)
2485 break;
2486 } while (image_info->adjoin != MagickFalse);
2487 (void) CloseBlob(image);
2488 return(MagickTrue);
2489 }
2490