blob: f3120eb61425bf19a6b5285855c4a904351f4fdb [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% John Cristy %
17% July 1992 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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 "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/color.h"
47#include "magick/color-private.h"
48#include "magick/colorspace.h"
49#include "magick/exception.h"
50#include "magick/exception-private.h"
51#include "magick/image.h"
52#include "magick/image-private.h"
53#include "magick/list.h"
54#include "magick/magick.h"
55#include "magick/memory_.h"
cristyf2f27272009-12-17 14:48:46 +000056#include "magick/module.h"
cristy3ed852e2009-09-05 21:47:34 +000057#include "magick/monitor.h"
58#include "magick/monitor-private.h"
59#include "magick/pixel-private.h"
60#include "magick/property.h"
61#include "magick/quantum-private.h"
62#include "magick/static.h"
63#include "magick/statistic.h"
64#include "magick/string_.h"
cristyf2f27272009-12-17 14:48:46 +000065#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000066
67/*
68 Forward declarations.
69*/
70static MagickBooleanType
71 WritePNMImage(const ImageInfo *,Image *);
72
73/*
74%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75% %
76% %
77% %
78% I s P N M %
79% %
80% %
81% %
82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83%
84% IsPNM() returns MagickTrue if the image format type, identified by the
85% magick string, is PNM.
86%
87% The format of the IsPNM method is:
88%
89% MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
90%
91% A description of each parameter follows:
92%
93% o magick: compare image format pattern against these bytes.
94%
95% o extent: Specifies the extent of the magick string.
96%
97*/
98static MagickBooleanType IsPNM(const unsigned char *magick,const size_t extent)
99{
100 if (extent < 2)
101 return(MagickFalse);
102 if ((*magick == (unsigned char) 'P') &&
103 ((magick[1] == '1') || (magick[1] == '2') || (magick[1] == '3') ||
104 (magick[1] == '4') || (magick[1] == '5') || (magick[1] == '6') ||
105 (magick[1] == '7') || (magick[1] == 'F') || (magick[1] == 'f')))
106 return(MagickTrue);
107 return(MagickFalse);
108}
109
110/*
111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112% %
113% %
114% %
115% R e a d P N M I m a g e %
116% %
117% %
118% %
119%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120%
121% ReadPNMImage() reads a Portable Anymap image file and returns it.
122% It allocates the memory necessary for the new Image structure and returns
123% a pointer to the new image.
124%
125% The format of the ReadPNMImage method is:
126%
127% Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
128%
129% A description of each parameter follows:
130%
131% o image_info: the image info.
132%
133% o exception: return any errors or warnings in this structure.
134%
135*/
136
137static inline long ConstrainPixel(Image *image,const long offset,
138 const unsigned long extent)
139{
140 if ((offset < 0) || (offset > (long) extent))
141 {
142 (void) ThrowMagickException(&image->exception,GetMagickModule(),
143 CorruptImageError,"InvalidPixel","`%s'",image->filename);
144 return(0);
145 }
146 return(offset);
147}
148
149static unsigned long PNMInteger(Image *image,const unsigned int base)
150{
151 char
152 *comment;
153
154 int
155 c;
156
157 register char
158 *p;
159
160 size_t
161 extent;
162
163 unsigned long
164 value;
165
166 /*
167 Skip any leading whitespace.
168 */
169 extent=MaxTextExtent;
170 comment=(char *) NULL;
171 p=comment;
172 do
173 {
174 c=ReadBlobByte(image);
175 if (c == EOF)
176 return(0);
177 if (c == (int) '#')
178 {
179 /*
180 Read comment.
181 */
182 if (comment == (char *) NULL)
183 comment=AcquireString((char *) NULL);
184 p=comment+strlen(comment);
185 for ( ; (c != EOF) && (c != (int) '\n'); p++)
186 {
187 if ((size_t) (p-comment+1) >= extent)
188 {
189 extent<<=1;
190 comment=(char *) ResizeQuantumMemory(comment,extent+MaxTextExtent,
191 sizeof(*comment));
192 if (comment == (char *) NULL)
193 break;
194 p=comment+strlen(comment);
195 }
196 c=ReadBlobByte(image);
197 *p=(char) c;
198 *(p+1)='\0';
199 }
200 if (comment == (char *) NULL)
201 return(0);
202 continue;
203 }
204 } while (isdigit(c) == MagickFalse);
205 if (comment != (char *) NULL)
206 {
207 (void) SetImageProperty(image,"comment",comment);
208 comment=DestroyString(comment);
209 }
210 if (base == 2)
211 return((unsigned long) (c-(int) '0'));
212 /*
213 Evaluate number.
214 */
215 value=0;
216 do
217 {
218 value*=10;
219 value+=c-(int) '0';
220 c=ReadBlobByte(image);
221 if (c == EOF)
222 return(value);
223 } while (isdigit(c) != MagickFalse);
224 return(value);
225}
226
227static Image *ReadPNMImage(const ImageInfo *image_info,ExceptionInfo *exception)
228{
229 char
230 format;
231
232 double
233 quantum_scale;
234
235 Image
236 *image;
237
238 long
239 row,
240 y;
241
242 MagickBooleanType
243 status;
244
245 Quantum
246 *scale;
247
248 QuantumInfo
249 *quantum_info;
250
251 QuantumType
252 quantum_type;
253
254 register long
255 i;
256
257 size_t
258 extent,
259 packet_size;
260
261 ssize_t
262 count;
263
264 unsigned long
265 depth,
266 max_value;
267
cristy3ed852e2009-09-05 21:47:34 +0000268 /*
269 Open image file.
270 */
271 assert(image_info != (const ImageInfo *) NULL);
272 assert(image_info->signature == MagickSignature);
273 if (image_info->debug != MagickFalse)
274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
275 image_info->filename);
276 assert(exception != (ExceptionInfo *) NULL);
277 assert(exception->signature == MagickSignature);
278 image=AcquireImage(image_info);
279 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
280 if (status == MagickFalse)
281 {
282 image=DestroyImageList(image);
283 return((Image *) NULL);
284 }
285 /*
286 Read PNM image.
287 */
288 count=ReadBlob(image,1,(unsigned char *) &format);
289 do
290 {
291 /*
292 Initialize image structure.
293 */
294 if ((count != 1) || (format != 'P'))
295 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
296 max_value=1;
297 quantum_type=RGBQuantum;
298 quantum_scale=1.0;
299 format=(char) ReadBlobByte(image);
300 if (format != '7')
301 {
302 /*
303 PBM, PGM, PPM, and PNM.
304 */
305 image->columns=PNMInteger(image,10);
306 image->rows=PNMInteger(image,10);
307 if ((format == 'f') || (format == 'F'))
308 {
309 char
310 scale[MaxTextExtent];
311
312 (void) ReadBlobString(image,scale);
cristyf2f27272009-12-17 14:48:46 +0000313 quantum_scale=StringToDouble(scale);
cristy3ed852e2009-09-05 21:47:34 +0000314 }
315 else
316 {
317 if ((format == '1') || (format == '4'))
318 max_value=1; /* bitmap */
319 else
320 max_value=PNMInteger(image,10);
321 }
322 }
323 else
324 {
325 char
326 keyword[MaxTextExtent],
327 value[MaxTextExtent];
328
329 int
330 c;
331
332 register char
333 *p;
334
335 /*
336 PAM.
337 */
338 for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
339 {
340 while (isspace((int) ((unsigned char) c)) != 0)
341 c=ReadBlobByte(image);
342 p=keyword;
343 do
344 {
345 if ((size_t) (p-keyword) < (MaxTextExtent-1))
346 *p++=c;
347 c=ReadBlobByte(image);
348 } while (isalnum(c));
349 *p='\0';
350 if (LocaleCompare(keyword,"endhdr") == 0)
351 break;
352 while (isspace((int) ((unsigned char) c)) != 0)
353 c=ReadBlobByte(image);
354 p=value;
355 while (isalnum(c) || (c == '_'))
356 {
357 if ((size_t) (p-value) < (MaxTextExtent-1))
358 *p++=c;
359 c=ReadBlobByte(image);
360 }
361 *p='\0';
362 /*
363 Assign a value to the specified keyword.
364 */
365 if (LocaleCompare(keyword,"depth") == 0)
cristye27293e2009-12-18 02:53:20 +0000366 packet_size=StringToUnsignedLong(value);
cristy3ed852e2009-09-05 21:47:34 +0000367 if (LocaleCompare(keyword,"height") == 0)
cristye27293e2009-12-18 02:53:20 +0000368 image->rows=StringToUnsignedLong(value);
cristy3ed852e2009-09-05 21:47:34 +0000369 if (LocaleCompare(keyword,"maxval") == 0)
cristye27293e2009-12-18 02:53:20 +0000370 max_value=StringToUnsignedLong(value);
cristy3ed852e2009-09-05 21:47:34 +0000371 if (LocaleCompare(keyword,"TUPLTYPE") == 0)
372 {
373 if (LocaleCompare(value,"BLACKANDWHITE") == 0)
374 quantum_type=GrayQuantum;
375 if (LocaleCompare(value,"BLACKANDWHITE_ALPHA") == 0)
376 {
377 quantum_type=GrayAlphaQuantum;
378 image->matte=MagickTrue;
379 }
380 if (LocaleCompare(value,"GRAYSCALE") == 0)
381 quantum_type=GrayQuantum;
382 if (LocaleCompare(value,"GRAYSCALE_ALPHA") == 0)
383 {
384 quantum_type=GrayAlphaQuantum;
385 image->matte=MagickTrue;
386 }
387 if (LocaleCompare(value,"RGB_ALPHA") == 0)
388 {
389 quantum_type=RGBAQuantum;
390 image->matte=MagickTrue;
391 }
392 if (LocaleCompare(value,"CMYK") == 0)
393 {
394 quantum_type=CMYKQuantum;
395 image->colorspace=CMYKColorspace;
396 }
397 if (LocaleCompare(value,"CMYK_ALPHA") == 0)
398 {
399 quantum_type=CMYKAQuantum;
400 image->colorspace=CMYKColorspace;
401 image->matte=MagickTrue;
402 }
403 }
404 if (LocaleCompare(keyword,"width") == 0)
cristye27293e2009-12-18 02:53:20 +0000405 image->columns=StringToUnsignedLong(value);
cristy3ed852e2009-09-05 21:47:34 +0000406 }
407 }
408 if ((image->columns == 0) || (image->rows == 0))
409 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
410 if (max_value >= 65536)
411 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
412 for (depth=1; GetQuantumRange(depth) < max_value; depth++) ;
413 image->depth=depth;
414 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
415 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
416 break;
417 /*
418 Convert PNM pixels to runextent-encoded MIFF packets.
419 */
420 status=MagickTrue;
421 row=0;
422 switch (format)
423 {
424 case '1':
425 {
426 /*
427 Convert PBM image to pixel packets.
428 */
429 for (y=0; y < (long) image->rows; y++)
430 {
431 register long
432 x;
433
434 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000435 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000436
437 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
438 if (q == (PixelPacket *) NULL)
439 break;
440 for (x=0; x < (long) image->columns; x++)
441 {
442 q->red=(Quantum) (PNMInteger(image,2) == 0 ? QuantumRange : 0);
443 q->green=q->red;
444 q->blue=q->red;
445 q++;
446 }
447 if (SyncAuthenticPixels(image,exception) == MagickFalse)
448 break;
449 if (image->previous == (Image *) NULL)
450 {
451 status=SetImageProgress(image,LoadImageTag,y,image->rows);
452 if (status == MagickFalse)
453 break;
454 }
455 }
456 image->type=BilevelType;
457 break;
458 }
459 case '2':
460 {
461 unsigned long
462 intensity;
463
464 /*
465 Convert PGM image to pixel packets.
466 */
467 scale=(Quantum *) NULL;
468 if (max_value != (1U*QuantumRange))
469 {
470 /*
471 Compute pixel scaling table.
472 */
473 scale=(Quantum *) AcquireQuantumMemory((size_t) max_value+1UL,
474 sizeof(*scale));
475 if (scale == (Quantum *) NULL)
476 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
477 for (i=0; i <= (long) max_value; i++)
478 scale[i]=(Quantum) (((double) QuantumRange*i)/max_value+0.5);
479 }
480 for (y=0; y < (long) image->rows; y++)
481 {
482 register long
483 x;
484
485 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000486 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000487
488 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
489 if (q == (PixelPacket *) NULL)
490 break;
491 for (x=0; x < (long) image->columns; x++)
492 {
493 intensity=PNMInteger(image,10);
494 if (scale != (Quantum *) NULL)
495 intensity=(unsigned long) scale[ConstrainPixel(image,(long)
496 intensity,max_value)];
497 q->red=(Quantum) intensity;
498 q->green=q->red;
499 q->blue=q->red;
500 q++;
501 }
502 if (SyncAuthenticPixels(image,exception) == MagickFalse)
503 break;
504 if (image->previous == (Image *) NULL)
505 {
506 status=SetImageProgress(image,LoadImageTag,y,image->rows);
507 if (status == MagickFalse)
508 break;
509 }
510 }
511 image->type=GrayscaleType;
512 if (scale != (Quantum *) NULL)
513 scale=(Quantum *) RelinquishMagickMemory(scale);
514 break;
515 }
516 case '3':
517 {
518 MagickPixelPacket
519 pixel;
520
521 /*
522 Convert PNM image to pixel packets.
523 */
524 scale=(Quantum *) NULL;
525 if (max_value != (1U*QuantumRange))
526 {
527 /*
528 Compute pixel scaling table.
529 */
530 scale=(Quantum *) AcquireQuantumMemory((size_t) max_value+1UL,
531 sizeof(*scale));
532 if (scale == (Quantum *) NULL)
533 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
534 for (i=0; i <= (long) max_value; i++)
535 scale[i]=(Quantum) (((double) QuantumRange*i)/max_value+0.5);
536 }
537 for (y=0; y < (long) image->rows; y++)
538 {
539 register long
540 x;
541
542 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000543 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000544
545 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
546 if (q == (PixelPacket *) NULL)
547 break;
548 for (x=0; x < (long) image->columns; x++)
549 {
550 pixel.red=(MagickRealType) PNMInteger(image,10);
551 pixel.green=(MagickRealType) PNMInteger(image,10);
552 pixel.blue=(MagickRealType) PNMInteger(image,10);
553 if (scale != (Quantum *) NULL)
554 {
555 pixel.red=(MagickRealType) scale[ConstrainPixel(image,(long)
556 pixel.red,max_value)];
557 pixel.green=(MagickRealType) scale[ConstrainPixel(image,(long)
558 pixel.green,max_value)];
559 pixel.blue=(MagickRealType) scale[ConstrainPixel(image,(long)
560 pixel.blue,max_value)];
561 }
562 q->red=(Quantum) pixel.red;
563 q->green=(Quantum) pixel.green;
564 q->blue=(Quantum) pixel.blue;
565 q++;
566 }
567 if (SyncAuthenticPixels(image,exception) == MagickFalse)
568 break;
569 if (image->previous == (Image *) NULL)
570 {
571 status=SetImageProgress(image,LoadImageTag,y,image->rows);
572 if (status == MagickFalse)
573 break;
574 }
575 }
576 if (scale != (Quantum *) NULL)
577 scale=(Quantum *) RelinquishMagickMemory(scale);
578 break;
579 }
580 case '4':
581 {
582 /*
583 Convert PBM raw image to pixel packets.
584 */
585 quantum_type=GrayQuantum;
586 if (image->storage_class == PseudoClass)
587 quantum_type=IndexQuantum;
588 quantum_info=AcquireQuantumInfo(image_info,image);
589 if (quantum_info == (QuantumInfo *) NULL)
590 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
591 SetQuantumMinIsWhite(quantum_info,MagickTrue);
592 extent=GetQuantumExtent(image,quantum_info,quantum_type);
cristy3ed852e2009-09-05 21:47:34 +0000593 for (y=0; y < (long) image->rows; y++)
594 {
595 long
596 offset;
597
598 MagickBooleanType
599 sync;
600
601 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000602 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000603
604 ssize_t
605 count;
606
607 size_t
608 length;
609
610 unsigned char
611 *pixels;
612
613 if (status == MagickFalse)
614 continue;
615 pixels=GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +0000616 {
617 count=ReadBlob(image,extent,pixels);
618 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
619 (image->previous == (Image *) NULL))
620 {
621 MagickBooleanType
622 proceed;
623
624 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
625 if (proceed == MagickFalse)
626 status=MagickFalse;
627 }
628 offset=row++;
629 }
630 if (count != (ssize_t) extent)
631 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +0000632 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000633 if (q == (PixelPacket *) NULL)
634 {
635 status=MagickFalse;
636 continue;
637 }
cristyaa740112010-03-30 17:58:44 +0000638 length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
639 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +0000640 if (length != extent)
641 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +0000642 sync=SyncAuthenticPixels(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000643 if (sync == MagickFalse)
644 status=MagickFalse;
645 }
cristy3ed852e2009-09-05 21:47:34 +0000646 quantum_info=DestroyQuantumInfo(quantum_info);
647 if (status == MagickFalse)
648 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
649 SetQuantumImageType(image,quantum_type);
650 break;
651 }
652 case '5':
653 {
654 QuantumAny
655 range;
656
657 /*
658 Convert PGM raw image to pixel packets.
659 */
660 range=GetQuantumRange(image->depth);
661 quantum_type=GrayQuantum;
662 extent=(image->depth <= 8 ? 1 : 2)*image->columns;
663 quantum_info=AcquireQuantumInfo(image_info,image);
664 if (quantum_info == (QuantumInfo *) NULL)
665 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000666 for (y=0; y < (long) image->rows; y++)
667 {
668 long
669 offset;
670
671 MagickBooleanType
672 sync;
673
674 register const unsigned char
cristy3f2302b2010-03-11 03:16:37 +0000675 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000676
677 register long
678 x;
679
680 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000681 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000682
683 ssize_t
684 count;
685
686 unsigned char
687 *pixels;
688
689 if (status == MagickFalse)
690 continue;
691 pixels=GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +0000692 {
693 count=ReadBlob(image,extent,pixels);
694 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
695 (image->previous == (Image *) NULL))
696 {
697 MagickBooleanType
698 proceed;
699
700 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
701 if (proceed == MagickFalse)
702 status=MagickFalse;
703 }
704 offset=row++;
705 }
706 if (count != (ssize_t) extent)
707 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +0000708 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000709 if (q == (PixelPacket *) NULL)
710 {
711 status=MagickFalse;
712 continue;
713 }
714 p=pixels;
715 if ((image->depth == 8) || (image->depth == 16))
cristyaa740112010-03-30 17:58:44 +0000716 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3ed852e2009-09-05 21:47:34 +0000717 quantum_type,pixels,exception);
718 else
719 if (image->depth <= 8)
720 {
721 unsigned char
722 pixel;
723
724 for (x=0; x < (long) image->columns; x++)
725 {
726 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +0000727 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +0000728 q->green=q->red;
729 q->blue=q->red;
730 q++;
731 }
732 }
733 else
734 {
735 unsigned short
736 pixel;
737
738 for (x=0; x < (long) image->columns; x++)
739 {
740 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +0000741 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +0000742 q->green=q->red;
743 q->blue=q->red;
744 q++;
745 }
746 }
cristyaa740112010-03-30 17:58:44 +0000747 sync=SyncAuthenticPixels(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000748 if (sync == MagickFalse)
749 status=MagickFalse;
750 }
cristy3ed852e2009-09-05 21:47:34 +0000751 quantum_info=DestroyQuantumInfo(quantum_info);
752 if (status == MagickFalse)
753 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
754 SetQuantumImageType(image,quantum_type);
755 break;
756 }
757 case '6':
758 {
759 ImageType
760 type;
761
762 QuantumAny
763 range;
764
765 /*
766 Convert PNM raster image to pixel packets.
767 */
768 type=BilevelType;
769 quantum_type=RGBQuantum;
770 extent=3*(image->depth <= 8 ? 1 : 2)*image->columns;
771 range=GetQuantumRange(image->depth);
772 quantum_info=AcquireQuantumInfo(image_info,image);
773 if (quantum_info == (QuantumInfo *) NULL)
774 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000775 for (y=0; y < (long) image->rows; y++)
776 {
777 long
778 offset;
779
780 MagickBooleanType
781 sync;
782
783 register const unsigned char
cristy3f2302b2010-03-11 03:16:37 +0000784 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000785
786 register long
787 x;
788
789 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000790 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000791
792 ssize_t
793 count;
794
cristy3ed852e2009-09-05 21:47:34 +0000795 unsigned char
796 *pixels;
797
798 if (status == MagickFalse)
799 continue;
800 pixels=GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +0000801 {
802 count=ReadBlob(image,extent,pixels);
803 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
804 (image->previous == (Image *) NULL))
805 {
806 MagickBooleanType
807 proceed;
808
809 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
810 if (proceed == MagickFalse)
811 status=MagickFalse;
812 }
813 offset=row++;
814 }
815 if (count != (ssize_t) extent)
816 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +0000817 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000818 if (q == (PixelPacket *) NULL)
819 {
820 status=MagickFalse;
821 continue;
822 }
823 p=pixels;
cristye90d7402010-03-14 18:21:29 +0000824 if (image->depth == 8)
825 for (x=0; x < (long) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000826 {
cristye90d7402010-03-14 18:21:29 +0000827 q->red=ScaleCharToQuantum(*p++);
828 q->green=ScaleCharToQuantum(*p++);
829 q->blue=ScaleCharToQuantum(*p++);
830 q->opacity=OpaqueOpacity;
831 q++;
cristy3ed852e2009-09-05 21:47:34 +0000832 }
833 else
cristye90d7402010-03-14 18:21:29 +0000834 if (image->depth == 16)
cristy3ed852e2009-09-05 21:47:34 +0000835 {
836 unsigned short
837 pixel;
838
cristy3ed852e2009-09-05 21:47:34 +0000839 for (x=0; x < (long) image->columns; x++)
840 {
841 p=PushShortPixel(MSBEndian,p,&pixel);
cristye90d7402010-03-14 18:21:29 +0000842 q->red=ScaleShortToQuantum(pixel);
cristy3ed852e2009-09-05 21:47:34 +0000843 p=PushShortPixel(MSBEndian,p,&pixel);
cristye90d7402010-03-14 18:21:29 +0000844 q->green=ScaleShortToQuantum(pixel);
cristy3ed852e2009-09-05 21:47:34 +0000845 p=PushShortPixel(MSBEndian,p,&pixel);
cristye90d7402010-03-14 18:21:29 +0000846 q->blue=ScaleShortToQuantum(pixel);
847 q->opacity=OpaqueOpacity;
848 q++;
cristy3ed852e2009-09-05 21:47:34 +0000849 }
850 }
cristye90d7402010-03-14 18:21:29 +0000851 else
852 if (image->depth <= 8)
853 {
854 unsigned char
855 pixel;
856
857 for (x=0; x < (long) image->columns; x++)
858 {
859 p=PushCharPixel(p,&pixel);
860 q->red=ScaleAnyToQuantum(pixel,range);
861 p=PushCharPixel(p,&pixel);
862 q->green=ScaleAnyToQuantum(pixel,range);
863 p=PushCharPixel(p,&pixel);
864 q->blue=ScaleAnyToQuantum(pixel,range);
865 q->opacity=OpaqueOpacity;
866 q++;
867 }
868 }
869 else
870 {
871 unsigned short
872 pixel;
873
874 for (x=0; x < (long) image->columns; x++)
875 {
876 p=PushShortPixel(MSBEndian,p,&pixel);
877 q->red=ScaleAnyToQuantum(pixel,range);
878 p=PushShortPixel(MSBEndian,p,&pixel);
879 q->green=ScaleAnyToQuantum(pixel,range);
880 p=PushShortPixel(MSBEndian,p,&pixel);
881 q->blue=ScaleAnyToQuantum(pixel,range);
882 q->opacity=OpaqueOpacity;
883 q++;
884 }
885 }
cristy3ed852e2009-09-05 21:47:34 +0000886 if ((type == BilevelType) || (type == GrayscaleType))
cristy3ed852e2009-09-05 21:47:34 +0000887 {
cristyaa740112010-03-30 17:58:44 +0000888 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
cristye90d7402010-03-14 18:21:29 +0000889 for (x=0; x < (long) image->columns; x++)
890 {
891 if ((type == BilevelType) &&
892 (IsMonochromePixel(q) == MagickFalse))
893 type=IsGrayPixel(q) == MagickFalse ? UndefinedType :
894 GrayscaleType;
895 if ((type == GrayscaleType) && (IsGrayPixel(q) == MagickFalse))
896 type=UndefinedType;
897 if ((type != BilevelType) && (type != GrayscaleType))
898 break;
899 q++;
900 }
cristy3ed852e2009-09-05 21:47:34 +0000901 }
cristyaa740112010-03-30 17:58:44 +0000902 sync=SyncAuthenticPixels(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000903 if (sync == MagickFalse)
904 status=MagickFalse;
905 }
cristy3ed852e2009-09-05 21:47:34 +0000906 quantum_info=DestroyQuantumInfo(quantum_info);
907 if (status == MagickFalse)
908 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
909 if (type != UndefinedType)
910 image->type=type;
911 break;
912 }
913 case '7':
914 {
915 register IndexPacket
916 *indexes;
917
918 QuantumAny
919 range;
920
921 unsigned long
922 channels;
923
924 /*
925 Convert PAM raster image to pixel packets.
926 */
927 range=GetQuantumRange(image->depth);
928 switch (quantum_type)
929 {
930 case GrayQuantum:
931 case GrayAlphaQuantum:
932 {
933 channels=1;
934 break;
935 }
936 case CMYKQuantum:
937 case CMYKAQuantum:
938 {
939 channels=4;
940 break;
941 }
942 default:
943 {
944 channels=3;
945 break;
946 }
947 }
948 if (image->matte != MagickFalse)
949 channels++;
950 extent=channels*(image->depth <= 8 ? 1 : 2)*image->columns;
951 quantum_info=AcquireQuantumInfo(image_info,image);
952 if (quantum_info == (QuantumInfo *) NULL)
953 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +0000954 for (y=0; y < (long) image->rows; y++)
955 {
956 long
957 offset;
958
959 MagickBooleanType
960 sync;
961
962 register const unsigned char
cristy3f2302b2010-03-11 03:16:37 +0000963 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +0000964
965 register long
966 x;
967
968 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000969 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000970
971 ssize_t
972 count;
973
974 unsigned char
975 *pixels;
976
977 if (status == MagickFalse)
978 continue;
979 pixels=GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +0000980 {
981 count=ReadBlob(image,extent,pixels);
982 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
983 (image->previous == (Image *) NULL))
984 {
985 MagickBooleanType
986 proceed;
987
988 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
989 if (proceed == MagickFalse)
990 status=MagickFalse;
991 }
992 offset=row++;
993 }
994 if (count != (ssize_t) extent)
995 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +0000996 q=QueueAuthenticPixels(image,0,offset,image->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +0000997 if (q == (PixelPacket *) NULL)
998 {
999 status=MagickFalse;
1000 continue;
1001 }
cristyaa740112010-03-30 17:58:44 +00001002 indexes=GetAuthenticIndexQueue(image);
cristy3ed852e2009-09-05 21:47:34 +00001003 p=pixels;
1004 if ((image->depth == 8) || (image->depth == 16))
cristyaa740112010-03-30 17:58:44 +00001005 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3ed852e2009-09-05 21:47:34 +00001006 quantum_type,pixels,exception);
1007 else
1008 switch (quantum_type)
1009 {
1010 case GrayQuantum:
1011 case GrayAlphaQuantum:
1012 {
1013 if (image->depth <= 8)
1014 {
1015 unsigned char
1016 pixel;
1017
1018 for (x=0; x < (long) image->columns; x++)
1019 {
1020 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001021 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001022 q->green=q->red;
1023 q->blue=q->red;
cristyce70c172010-01-07 17:15:30 +00001024 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001025 if (image->matte != MagickFalse)
1026 {
1027 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001028 SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001029 }
1030 q++;
1031 }
1032 }
1033 else
1034 {
1035 unsigned short
1036 pixel;
1037
1038 for (x=0; x < (long) image->columns; x++)
1039 {
1040 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001041 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001042 q->green=q->red;
1043 q->blue=q->red;
cristyce70c172010-01-07 17:15:30 +00001044 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001045 if (image->matte != MagickFalse)
1046 {
1047 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001048 SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001049 }
1050 q++;
1051 }
1052 }
1053 break;
1054 }
1055 case CMYKQuantum:
1056 case CMYKAQuantum:
1057 {
1058 if (image->depth <= 8)
1059 {
1060 unsigned char
1061 pixel;
1062
1063 for (x=0; x < (long) image->columns; x++)
1064 {
1065 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001066 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001067 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001068 SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001069 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001070 SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001071 p=PushCharPixel(p,&pixel);
1072 indexes[x]=ScaleAnyToQuantum(pixel,range);
cristyce70c172010-01-07 17:15:30 +00001073 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001074 if (image->matte != MagickFalse)
1075 {
1076 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001077 SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001078 }
1079 q++;
1080 }
1081 }
1082 else
1083 {
1084 unsigned short
1085 pixel;
1086
1087 for (x=0; x < (long) image->columns; x++)
1088 {
1089 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001090 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001091 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001092 SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001093 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001094 SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001095 p=PushShortPixel(MSBEndian,p,&pixel);
1096 indexes[x]=ScaleAnyToQuantum(pixel,range);
cristyce70c172010-01-07 17:15:30 +00001097 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001098 if (image->matte != MagickFalse)
1099 {
1100 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001101 SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001102 }
1103 q++;
1104 }
1105 }
1106 break;
1107 }
1108 default:
1109 {
1110 if (image->depth <= 8)
1111 {
1112 unsigned char
1113 pixel;
1114
1115 for (x=0; x < (long) image->columns; x++)
1116 {
1117 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001118 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001119 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001120 SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001121 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001122 SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
1123 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001124 if (image->matte != MagickFalse)
1125 {
1126 p=PushCharPixel(p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001127 SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001128 }
1129 q++;
1130 }
1131 }
1132 else
1133 {
1134 unsigned short
1135 pixel;
1136
1137 for (x=0; x < (long) image->columns; x++)
1138 {
1139 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001140 SetRedPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001141 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001142 SetGreenPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001143 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001144 SetBluePixelComponent(q,ScaleAnyToQuantum(pixel,range));
1145 SetOpacityPixelComponent(q,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00001146 if (image->matte != MagickFalse)
1147 {
1148 p=PushShortPixel(MSBEndian,p,&pixel);
cristyce70c172010-01-07 17:15:30 +00001149 SetOpacityPixelComponent(q,ScaleAnyToQuantum(pixel,range));
cristy3ed852e2009-09-05 21:47:34 +00001150 }
1151 q++;
1152 }
1153 }
1154 break;
1155 }
1156 }
cristyaa740112010-03-30 17:58:44 +00001157 sync=SyncAuthenticPixels(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001158 if (sync == MagickFalse)
1159 status=MagickFalse;
1160 }
cristy3ed852e2009-09-05 21:47:34 +00001161 quantum_info=DestroyQuantumInfo(quantum_info);
1162 if (status == MagickFalse)
1163 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1164 SetQuantumImageType(image,quantum_type);
1165 break;
1166 }
1167 case 'F':
1168 case 'f':
1169 {
1170 /*
1171 Convert PFM raster image to pixel packets.
1172 */
1173 quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
1174 image->endian=quantum_scale < 0.0 ? LSBEndian : MSBEndian;
1175 image->depth=32;
1176 quantum_info=AcquireQuantumInfo(image_info,image);
1177 if (quantum_info == (QuantumInfo *) NULL)
1178 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1179 status=SetQuantumDepth(image,quantum_info,32);
1180 if (status == MagickFalse)
1181 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1182 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1183 if (status == MagickFalse)
1184 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1185 SetQuantumScale(quantum_info,(MagickRealType) QuantumRange*
1186 fabs(quantum_scale));
1187 extent=GetQuantumExtent(image,quantum_info,quantum_type);
cristy3ed852e2009-09-05 21:47:34 +00001188 for (y=0; y < (long) image->rows; y++)
1189 {
1190 long
1191 offset;
1192
1193 MagickBooleanType
1194 sync;
1195
1196 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001197 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001198
1199 ssize_t
1200 count;
1201
1202 size_t
1203 length;
1204
1205 unsigned char
1206 *pixels;
1207
1208 if (status == MagickFalse)
1209 continue;
1210 pixels=GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +00001211 {
1212 count=ReadBlob(image,extent,pixels);
1213 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1214 (image->previous == (Image *) NULL))
1215 {
1216 MagickBooleanType
1217 proceed;
1218
1219 proceed=SetImageProgress(image,LoadImageTag,row,image->rows);
1220 if (proceed == MagickFalse)
1221 status=MagickFalse;
1222 }
1223 offset=row++;
1224 }
1225 if ((size_t) count != extent)
1226 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +00001227 q=QueueAuthenticPixels(image,0,(long) (image->rows-offset-1),
1228 image->columns,1,exception);
cristy3ed852e2009-09-05 21:47:34 +00001229 if (q == (PixelPacket *) NULL)
1230 {
1231 status=MagickFalse;
1232 continue;
1233 }
cristyaa740112010-03-30 17:58:44 +00001234 length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1235 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001236 if (length != extent)
1237 status=MagickFalse;
cristyaa740112010-03-30 17:58:44 +00001238 sync=SyncAuthenticPixels(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001239 if (sync == MagickFalse)
1240 status=MagickFalse;
1241 }
cristy3ed852e2009-09-05 21:47:34 +00001242 quantum_info=DestroyQuantumInfo(quantum_info);
1243 if (status == MagickFalse)
1244 ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1245 SetQuantumImageType(image,quantum_type);
1246 break;
1247 }
1248 default:
1249 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1250 }
1251 if (EOFBlob(image) != MagickFalse)
1252 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
1253 "UnexpectedEndOfFile","`%s'",image->filename);
1254 /*
1255 Proceed to next image.
1256 */
1257 if (image_info->number_scenes != 0)
1258 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1259 break;
1260 if ((format == '1') || (format == '2') || (format == '3'))
1261 do
1262 {
1263 /*
1264 Skip to end of line.
1265 */
1266 count=ReadBlob(image,1,(unsigned char *) &format);
1267 if (count == 0)
1268 break;
1269 if ((count != 0) && (format == 'P'))
1270 break;
1271 } while (format != '\n');
1272 count=ReadBlob(image,1,(unsigned char *) &format);
1273 if ((count == 1) && (format == 'P'))
1274 {
1275 /*
1276 Allocate next image structure.
1277 */
1278 AcquireNextImage(image_info,image);
1279 if (GetNextImageInList(image) == (Image *) NULL)
1280 {
1281 image=DestroyImageList(image);
1282 return((Image *) NULL);
1283 }
1284 image=SyncNextImageInList(image);
1285 status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1286 GetBlobSize(image));
1287 if (status == MagickFalse)
1288 break;
1289 }
1290 } while ((count == 1) && (format == 'P'));
1291 (void) CloseBlob(image);
1292 return(GetFirstImageInList(image));
1293}
1294
1295/*
1296%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297% %
1298% %
1299% %
1300% R e g i s t e r P N M I m a g e %
1301% %
1302% %
1303% %
1304%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305%
1306% RegisterPNMImage() adds properties for the PNM image format to
1307% the list of supported formats. The properties include the image format
1308% tag, a method to read and/or write the format, whether the format
1309% supports the saving of more than one frame to the same file or blob,
1310% whether the format supports native in-memory I/O, and a brief
1311% description of the format.
1312%
1313% The format of the RegisterPNMImage method is:
1314%
1315% unsigned long RegisterPNMImage(void)
1316%
1317*/
1318ModuleExport unsigned long RegisterPNMImage(void)
1319{
1320 MagickInfo
1321 *entry;
1322
1323 entry=SetMagickInfo("PAM");
1324 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1325 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1326 entry->description=ConstantString("Common 2-dimensional bitmap format");
1327 entry->module=ConstantString("PNM");
1328 (void) RegisterMagickInfo(entry);
1329 entry=SetMagickInfo("PBM");
1330 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1331 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1332 entry->description=ConstantString("Portable bitmap format (black and white)");
1333 entry->module=ConstantString("PNM");
1334 (void) RegisterMagickInfo(entry);
1335 entry=SetMagickInfo("PFM");
1336 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1337 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1338 entry->description=ConstantString("Portable float format");
1339 entry->module=ConstantString("PFM");
1340 (void) RegisterMagickInfo(entry);
1341 entry=SetMagickInfo("PGM");
1342 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1343 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1344 entry->description=ConstantString("Portable graymap format (gray scale)");
1345 entry->module=ConstantString("PNM");
1346 (void) RegisterMagickInfo(entry);
1347 entry=SetMagickInfo("PNM");
1348 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1349 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1350 entry->magick=(IsImageFormatHandler *) IsPNM;
1351 entry->description=ConstantString("Portable anymap");
1352 entry->module=ConstantString("PNM");
1353 (void) RegisterMagickInfo(entry);
1354 entry=SetMagickInfo("PPM");
1355 entry->decoder=(DecodeImageHandler *) ReadPNMImage;
1356 entry->encoder=(EncodeImageHandler *) WritePNMImage;
1357 entry->description=ConstantString("Portable pixmap format (color)");
1358 entry->module=ConstantString("PNM");
1359 (void) RegisterMagickInfo(entry);
1360 return(MagickImageCoderSignature);
1361}
1362
1363/*
1364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365% %
1366% %
1367% %
1368% U n r e g i s t e r P N M I m a g e %
1369% %
1370% %
1371% %
1372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373%
1374% UnregisterPNMImage() removes format registrations made by the
1375% PNM module from the list of supported formats.
1376%
1377% The format of the UnregisterPNMImage method is:
1378%
1379% UnregisterPNMImage(void)
1380%
1381*/
1382ModuleExport void UnregisterPNMImage(void)
1383{
1384 (void) UnregisterMagickInfo("PAM");
1385 (void) UnregisterMagickInfo("PBM");
1386 (void) UnregisterMagickInfo("PGM");
1387 (void) UnregisterMagickInfo("PNM");
1388 (void) UnregisterMagickInfo("PPM");
1389}
1390
1391/*
1392%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393% %
1394% %
1395% %
1396% W r i t e P N M I m a g e %
1397% %
1398% %
1399% %
1400%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401%
cristy661b5ad2010-01-13 00:54:42 +00001402% WritePNMImage() writes an image to a file in the PNM rasterfile format.
cristy3ed852e2009-09-05 21:47:34 +00001403%
1404% The format of the WritePNMImage method is:
1405%
1406% MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
1407%
1408% A description of each parameter follows.
1409%
1410% o image_info: the image info.
1411%
1412% o image: The image.
1413%
1414*/
1415static MagickBooleanType WritePNMImage(const ImageInfo *image_info,Image *image)
1416{
1417 char
1418 buffer[MaxTextExtent],
1419 format,
1420 magick[MaxTextExtent];
1421
1422 const char
1423 *value;
1424
1425 IndexPacket
1426 index;
1427
1428 long
1429 y;
1430
1431 MagickBooleanType
1432 status;
1433
1434 MagickOffsetType
1435 scene;
1436
1437 QuantumAny
1438 pixel;
1439
1440 QuantumInfo
1441 *quantum_info;
1442
1443 QuantumType
1444 quantum_type;
1445
cristy661b5ad2010-01-13 00:54:42 +00001446 register long
1447 i;
1448
cristy3ed852e2009-09-05 21:47:34 +00001449 register unsigned char
1450 *pixels,
1451 *q;
1452
1453 ssize_t
1454 count;
1455
1456 size_t
1457 extent,
1458 packet_size;
1459
1460 /*
1461 Open output image file.
1462 */
1463 assert(image_info != (const ImageInfo *) NULL);
1464 assert(image_info->signature == MagickSignature);
1465 assert(image != (Image *) NULL);
1466 assert(image->signature == MagickSignature);
1467 if (image->debug != MagickFalse)
1468 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1469 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1470 if (status == MagickFalse)
1471 return(status);
1472 scene=0;
1473 do
1474 {
1475 /*
1476 Write PNM file header.
1477 */
1478 packet_size=3;
1479 quantum_type=RGBQuantum;
1480 (void) CopyMagickString(magick,image_info->magick,MaxTextExtent);
1481 switch (magick[1])
1482 {
1483 case 'A':
1484 case 'a':
1485 {
1486 format='7';
1487 break;
1488 }
1489 case 'B':
1490 case 'b':
1491 {
1492 format='4';
1493 if (image_info->compression == NoCompression)
1494 format='1';
1495 break;
1496 }
1497 case 'F':
1498 case 'f':
1499 {
1500 format='F';
1501 if (IsGrayImage(image,&image->exception) != MagickFalse)
1502 format='f';
1503 break;
1504 }
1505 case 'G':
1506 case 'g':
1507 {
1508 format='5';
1509 if (image_info->compression == NoCompression)
1510 format='2';
1511 break;
1512 }
1513 case 'N':
1514 case 'n':
1515 {
1516 if ((image_info->type != TrueColorType) &&
1517 (IsGrayImage(image,&image->exception) != MagickFalse))
1518 {
1519 format='5';
1520 if (image_info->compression == NoCompression)
1521 format='2';
1522 if (IsMonochromeImage(image,&image->exception) != MagickFalse)
1523 {
1524 format='4';
1525 if (image_info->compression == NoCompression)
1526 format='1';
1527 }
1528 break;
1529 }
1530 }
1531 default:
1532 {
1533 format='6';
1534 if (image_info->compression == NoCompression)
1535 format='3';
1536 break;
1537 }
1538 }
1539 (void) FormatMagickString(buffer,MaxTextExtent,"P%c\n",format);
1540 (void) WriteBlobString(image,buffer);
1541 value=GetImageProperty(image,"comment");
1542 if (value != (const char *) NULL)
1543 {
1544 register const char
1545 *p;
1546
1547 /*
1548 Write comments to file.
1549 */
1550 (void) WriteBlobByte(image,'#');
1551 for (p=value; *p != '\0'; p++)
1552 {
1553 (void) WriteBlobByte(image,(unsigned char) *p);
1554 if ((*p == '\r') && (*(p+1) != '\0'))
1555 (void) WriteBlobByte(image,'#');
1556 if ((*p == '\n') && (*(p+1) != '\0'))
1557 (void) WriteBlobByte(image,'#');
1558 }
1559 (void) WriteBlobByte(image,'\n');
1560 }
1561 if (format != '7')
1562 {
1563 if (image->colorspace != RGBColorspace)
1564 (void) TransformImageColorspace(image,RGBColorspace);
1565 (void) FormatMagickString(buffer,MaxTextExtent,"%lu %lu\n",
1566 image->columns,image->rows);
1567 (void) WriteBlobString(image,buffer);
1568 }
1569 else
1570 {
1571 char
1572 type[MaxTextExtent];
1573
1574 /*
1575 PAM header.
1576 */
1577 (void) FormatMagickString(buffer,MaxTextExtent,
1578 "WIDTH %lu\nHEIGHT %lu\n",image->columns,image->rows);
1579 (void) WriteBlobString(image,buffer);
1580 quantum_type=GetQuantumType(image,&image->exception);
1581 switch (quantum_type)
1582 {
1583 case CMYKQuantum:
1584 case CMYKAQuantum:
1585 {
1586 packet_size=4;
1587 (void) CopyMagickString(type,"CMYK",MaxTextExtent);
1588 break;
1589 }
1590 case GrayQuantum:
1591 case GrayAlphaQuantum:
1592 {
1593 packet_size=1;
1594 (void) CopyMagickString(type,"GRAYSCALE",MaxTextExtent);
1595 break;
1596 }
1597 default:
1598 {
1599 quantum_type=RGBQuantum;
1600 if (image->matte != MagickFalse)
1601 quantum_type=RGBAQuantum;
1602 packet_size=3;
1603 (void) CopyMagickString(type,"RGB",MaxTextExtent);
1604 break;
1605 }
1606 }
1607 if (image->matte != MagickFalse)
1608 {
1609 packet_size++;
1610 (void) ConcatenateMagickString(type,"_ALPHA",MaxTextExtent);
1611 }
1612 if (image->depth > 16)
1613 image->depth=16;
1614 (void) FormatMagickString(buffer,MaxTextExtent,
1615 "DEPTH %lu\nMAXVAL %lu\n",(unsigned long) packet_size,(unsigned long)
1616 GetQuantumRange(image->depth));
1617 (void) WriteBlobString(image,buffer);
1618 (void) FormatMagickString(buffer,MaxTextExtent,"TUPLTYPE %s\nENDHDR\n",
1619 type);
1620 (void) WriteBlobString(image,buffer);
1621 }
1622 /*
1623 Convert runextent encoded to PNM raster pixels.
1624 */
1625 switch (format)
1626 {
1627 case '1':
1628 {
cristy661b5ad2010-01-13 00:54:42 +00001629 unsigned char
1630 pixels[2048];
cristy3ed852e2009-09-05 21:47:34 +00001631
1632 /*
1633 Convert image to a PBM image.
1634 */
cristy661b5ad2010-01-13 00:54:42 +00001635 q=pixels;
cristy3ed852e2009-09-05 21:47:34 +00001636 for (y=0; y < (long) image->rows; y++)
1637 {
1638 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00001639 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00001640
1641 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001642 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001643
1644 register long
1645 x;
1646
1647 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1648 if (p == (const PixelPacket *) NULL)
1649 break;
1650 indexes=GetVirtualIndexQueue(image);
1651 for (x=0; x < (long) image->columns; x++)
1652 {
1653 pixel=PixelIntensityToQuantum(p);
cristy661b5ad2010-01-13 00:54:42 +00001654 *q++=(unsigned char) (pixel >= (Quantum) (QuantumRange/2) ?
1655 '0' : '1');
1656 *q++=' ';
1657 if ((q-pixels+2) >= 80)
1658 {
1659 *q++='\n';
1660 (void) WriteBlob(image,q-pixels,pixels);
1661 q=pixels;
1662 i=0;
1663 }
cristy3ed852e2009-09-05 21:47:34 +00001664 p++;
1665 }
1666 if (image->previous == (Image *) NULL)
1667 {
1668 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1669 if (status == MagickFalse)
1670 break;
1671 }
1672 }
cristy661b5ad2010-01-13 00:54:42 +00001673 if (q != pixels)
1674 {
1675 *q++='\n';
1676 (void) WriteBlob(image,q-pixels,pixels);
1677 }
cristy3ed852e2009-09-05 21:47:34 +00001678 break;
1679 }
1680 case '2':
1681 {
cristy661b5ad2010-01-13 00:54:42 +00001682 unsigned char
1683 pixels[2048];
cristy3ed852e2009-09-05 21:47:34 +00001684
1685 /*
1686 Convert image to a PGM image.
1687 */
1688 if (image->depth <= 8)
1689 (void) WriteBlobString(image,"255\n");
1690 else
1691 (void) WriteBlobString(image,"65535\n");
cristy661b5ad2010-01-13 00:54:42 +00001692 q=pixels;
cristy3ed852e2009-09-05 21:47:34 +00001693 for (y=0; y < (long) image->rows; y++)
1694 {
1695 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001696 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001697
1698 register long
1699 x;
1700
1701 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1702 if (p == (const PixelPacket *) NULL)
1703 break;
1704 for (x=0; x < (long) image->columns; x++)
1705 {
1706 index=PixelIntensityToQuantum(p);
1707 if (image->depth <= 8)
1708 count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,"%u ",
1709 ScaleQuantumToChar(index));
1710 else
1711 count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,"%u ",
1712 ScaleQuantumToShort(index));
cristy661b5ad2010-01-13 00:54:42 +00001713 extent=(size_t) count;
1714 (void) strncpy((char *) q,buffer,extent);
1715 q+=extent;
1716 if ((q-pixels+extent) >= 80)
1717 {
1718 *q++='\n';
1719 (void) WriteBlob(image,q-pixels,pixels);
1720 q=pixels;
1721 }
cristy3ed852e2009-09-05 21:47:34 +00001722 p++;
1723 }
1724 if (image->previous == (Image *) NULL)
1725 {
1726 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1727 if (status == MagickFalse)
1728 break;
1729 }
1730 }
cristy661b5ad2010-01-13 00:54:42 +00001731 if (q != pixels)
1732 {
1733 *q++='\n';
1734 (void) WriteBlob(image,q-pixels,pixels);
1735 }
cristy3ed852e2009-09-05 21:47:34 +00001736 break;
1737 }
1738 case '3':
1739 {
cristy661b5ad2010-01-13 00:54:42 +00001740 unsigned char
1741 pixels[2048];
cristy3ed852e2009-09-05 21:47:34 +00001742
1743 /*
1744 Convert image to a PNM image.
1745 */
1746 if (image->depth <= 8)
1747 (void) WriteBlobString(image,"255\n");
1748 else
1749 (void) WriteBlobString(image,"65535\n");
cristy661b5ad2010-01-13 00:54:42 +00001750 q=pixels;
cristy3ed852e2009-09-05 21:47:34 +00001751 for (y=0; y < (long) image->rows; y++)
1752 {
1753 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001754 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001755
1756 register long
1757 x;
1758
1759 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1760 if (p == (const PixelPacket *) NULL)
1761 break;
1762 for (x=0; x < (long) image->columns; x++)
1763 {
1764 if (image->depth <= 8)
1765 count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,
cristyce70c172010-01-07 17:15:30 +00001766 "%u %u %u ",ScaleQuantumToChar(GetRedPixelComponent(p)),
cristy375dc4b2010-01-12 20:24:58 +00001767 ScaleQuantumToChar(GetGreenPixelComponent(p)),
1768 ScaleQuantumToChar(GetBluePixelComponent(p)));
cristy3ed852e2009-09-05 21:47:34 +00001769 else
1770 count=(ssize_t) FormatMagickString(buffer,MaxTextExtent,
cristyce70c172010-01-07 17:15:30 +00001771 "%u %u %u ",ScaleQuantumToShort(GetRedPixelComponent(p)),
cristy375dc4b2010-01-12 20:24:58 +00001772 ScaleQuantumToShort(GetGreenPixelComponent(p)),
1773 ScaleQuantumToShort(GetBluePixelComponent(p)));
cristy661b5ad2010-01-13 00:54:42 +00001774 extent=(size_t) count;
1775 (void) strncpy((char *) q,buffer,extent);
1776 q+=extent;
1777 if ((q-pixels+extent) >= 80)
1778 {
1779 *q++='\n';
1780 (void) WriteBlob(image,q-pixels,pixels);
1781 q=pixels;
1782 }
cristy3ed852e2009-09-05 21:47:34 +00001783 p++;
1784 }
1785 if (image->previous == (Image *) NULL)
1786 {
1787 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1788 if (status == MagickFalse)
1789 break;
1790 }
1791 }
cristy661b5ad2010-01-13 00:54:42 +00001792 if (q != pixels)
1793 {
1794 *q++='\n';
1795 (void) WriteBlob(image,q-pixels,pixels);
1796 }
cristy3ed852e2009-09-05 21:47:34 +00001797 break;
1798 }
1799 case '4':
1800 {
1801 /*
1802 Convert image to a PBM image.
1803 */
1804 image->depth=1;
1805 quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1806 if (quantum_info == (QuantumInfo *) NULL)
1807 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1808 quantum_info->min_is_white=MagickTrue;
1809 pixels=GetQuantumPixels(quantum_info);
1810 for (y=0; y < (long) image->rows; y++)
1811 {
1812 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001813 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001814
1815 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1816 if (p == (const PixelPacket *) NULL)
1817 break;
1818 extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1819 quantum_info,GrayQuantum,pixels,&image->exception);
1820 count=WriteBlob(image,extent,pixels);
1821 if (count != (ssize_t) extent)
1822 break;
1823 if (image->previous == (Image *) NULL)
1824 {
1825 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1826 if (status == MagickFalse)
1827 break;
1828 }
1829 }
1830 quantum_info=DestroyQuantumInfo(quantum_info);
1831 break;
1832 }
1833 case '5':
1834 {
1835 QuantumAny
1836 range;
1837
1838 /*
1839 Convert image to a PGM image.
1840 */
1841 if (image->depth > 8)
1842 image->depth=16;
1843 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
1844 GetQuantumRange(image->depth));
1845 (void) WriteBlobString(image,buffer);
1846 quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1847 if (quantum_info == (QuantumInfo *) NULL)
1848 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1849 quantum_info->min_is_white=MagickTrue;
1850 pixels=GetQuantumPixels(quantum_info);
1851 extent=GetQuantumExtent(image,quantum_info,GrayQuantum);
1852 range=GetQuantumRange(image->depth);
1853 for (y=0; y < (long) image->rows; y++)
1854 {
1855 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001856 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001857
1858 register long
1859 x;
1860
1861 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1862 if (p == (const PixelPacket *) NULL)
1863 break;
1864 q=pixels;
1865 if ((image->depth == 8) || (image->depth == 16))
1866 extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1867 quantum_info,GrayQuantum,pixels,&image->exception);
1868 else
1869 {
1870 if (image->depth <= 8)
1871 for (x=0; x < (long) image->columns; x++)
1872 {
1873 if (IsGrayPixel(p) == MagickFalse)
1874 pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
1875 else
1876 {
1877 if (image->depth == 8)
cristyce70c172010-01-07 17:15:30 +00001878 pixel=ScaleQuantumToChar(GetRedPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001879 else
1880 pixel=ScaleQuantumToAny(p->red,range);
1881 }
1882 q=PopCharPixel((unsigned char) pixel,q);
1883 p++;
1884 }
1885 else
1886 for (x=0; x < (long) image->columns; x++)
1887 {
1888 if (IsGrayPixel(p) == MagickFalse)
1889 pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
1890 else
1891 {
1892 if (image->depth == 16)
cristyce70c172010-01-07 17:15:30 +00001893 pixel=ScaleQuantumToShort(GetRedPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +00001894 else
1895 pixel=ScaleQuantumToAny(p->red,range);
1896 }
1897 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1898 p++;
1899 }
1900 extent=(size_t) (q-pixels);
1901 }
1902 count=WriteBlob(image,extent,pixels);
1903 if (count != (ssize_t) extent)
1904 break;
1905 if (image->previous == (Image *) NULL)
1906 {
1907 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1908 if (status == MagickFalse)
1909 break;
1910 }
1911 }
1912 quantum_info=DestroyQuantumInfo(quantum_info);
1913 break;
1914 }
1915 case '6':
1916 {
1917 QuantumAny
1918 range;
1919
1920 /*
1921 Convert image to a PNM image.
1922 */
1923 if (image->depth > 8)
1924 image->depth=16;
1925 (void) FormatMagickString(buffer,MaxTextExtent,"%lu\n",(unsigned long)
1926 GetQuantumRange(image->depth));
1927 (void) WriteBlobString(image,buffer);
1928 quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1929 if (quantum_info == (QuantumInfo *) NULL)
1930 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1931 pixels=GetQuantumPixels(quantum_info);
1932 extent=GetQuantumExtent(image,quantum_info,quantum_type);
1933 range=GetQuantumRange(image->depth);
1934 for (y=0; y < (long) image->rows; y++)
1935 {
1936 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001937 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00001938
1939 register long
1940 x;
1941
1942 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1943 if (p == (const PixelPacket *) NULL)
1944 break;
1945 q=pixels;
1946 if ((image->depth == 8) || (image->depth == 16))
1947 extent=ExportQuantumPixels(image,(const CacheView *) NULL,
1948 quantum_info,quantum_type,pixels,&image->exception);
1949 else
1950 {
1951 if (image->depth <= 8)
1952 for (x=0; x < (long) image->columns; x++)
1953 {
1954 pixel=ScaleQuantumToAny(p->red,range);
1955 q=PopCharPixel((unsigned char) pixel,q);
1956 pixel=ScaleQuantumToAny(p->green,range);
1957 q=PopCharPixel((unsigned char) pixel,q);
1958 pixel=ScaleQuantumToAny(p->blue,range);
1959 q=PopCharPixel((unsigned char) pixel,q);
cristy3ed852e2009-09-05 21:47:34 +00001960 p++;
1961 }
1962 else
1963 for (x=0; x < (long) image->columns; x++)
1964 {
1965 pixel=ScaleQuantumToAny(p->red,range);
1966 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1967 pixel=ScaleQuantumToAny(p->green,range);
1968 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
1969 pixel=ScaleQuantumToAny(p->blue,range);
1970 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
cristy3ed852e2009-09-05 21:47:34 +00001971 p++;
1972 }
1973 extent=(size_t) (q-pixels);
1974 }
1975 count=WriteBlob(image,extent,pixels);
1976 if (count != (ssize_t) extent)
1977 break;
1978 if (image->previous == (Image *) NULL)
1979 {
1980 status=SetImageProgress(image,SaveImageTag,y,image->rows);
1981 if (status == MagickFalse)
1982 break;
1983 }
1984 }
1985 quantum_info=DestroyQuantumInfo(quantum_info);
1986 break;
1987 }
1988 case '7':
1989 {
1990 QuantumAny
1991 range;
1992
1993 /*
1994 Convert image to a PAM.
1995 */
1996 if (image->depth > 16)
1997 image->depth=16;
1998 quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
1999 pixels=GetQuantumPixels(quantum_info);
2000 range=GetQuantumRange(image->depth);
2001 for (y=0; y < (long) image->rows; y++)
2002 {
2003 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00002004 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00002005
2006 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002007 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00002008
2009 register long
2010 x;
2011
2012 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2013 if (p == (const PixelPacket *) NULL)
2014 break;
2015 indexes=GetVirtualIndexQueue(image);
2016 q=pixels;
2017 if ((image->depth == 8) || (image->depth == 16))
2018 extent=ExportQuantumPixels(image,(const CacheView *) NULL,
2019 quantum_info,quantum_type,pixels,&image->exception);
2020 else
2021 {
2022 switch (quantum_type)
2023 {
2024 case GrayQuantum:
2025 case GrayAlphaQuantum:
2026 {
2027 if (image->depth <= 8)
2028 for (x=0; x < (long) image->columns; x++)
2029 {
2030 pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
2031 q=PopCharPixel((unsigned char) pixel,q);
2032 if (image->matte != MagickFalse)
2033 {
2034 pixel=(unsigned char) ScaleQuantumToAny(p->opacity,
2035 range);
2036 q=PopCharPixel((unsigned char) pixel,q);
2037 }
2038 p++;
2039 }
2040 else
2041 for (x=0; x < (long) image->columns; x++)
2042 {
2043 pixel=ScaleQuantumToAny(PixelIntensityToQuantum(p),range);
2044 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2045 if (image->matte != MagickFalse)
2046 {
2047 pixel=(unsigned char) ScaleQuantumToAny(p->opacity,
2048 range);
2049 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2050 }
2051 p++;
2052 }
2053 break;
2054 }
2055 case CMYKQuantum:
2056 case CMYKAQuantum:
2057 {
2058 if (image->depth <= 8)
2059 for (x=0; x < (long) image->columns; x++)
2060 {
2061 pixel=ScaleQuantumToAny(p->red,range);
2062 q=PopCharPixel((unsigned char) pixel,q);
2063 pixel=ScaleQuantumToAny(p->green,range);
2064 q=PopCharPixel((unsigned char) pixel,q);
2065 pixel=ScaleQuantumToAny(p->blue,range);
2066 q=PopCharPixel((unsigned char) pixel,q);
2067 pixel=ScaleQuantumToAny(indexes[x],range);
2068 q=PopCharPixel((unsigned char) pixel,q);
2069 if (image->matte != MagickFalse)
2070 {
2071 pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002072 GetOpacityPixelComponent(p)),range);
cristy3ed852e2009-09-05 21:47:34 +00002073 q=PopCharPixel((unsigned char) pixel,q);
2074 }
2075 p++;
2076 }
2077 else
2078 for (x=0; x < (long) image->columns; x++)
2079 {
2080 pixel=ScaleQuantumToAny(p->red,range);
2081 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2082 pixel=ScaleQuantumToAny(p->green,range);
2083 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2084 pixel=ScaleQuantumToAny(p->blue,range);
2085 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2086 pixel=ScaleQuantumToAny(indexes[x],range);
2087 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2088 if (image->matte != MagickFalse)
2089 {
2090 pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002091 GetOpacityPixelComponent(p)),range);
cristy3ed852e2009-09-05 21:47:34 +00002092 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2093 }
2094 p++;
2095 }
2096 break;
2097 }
2098 default:
2099 {
2100 if (image->depth <= 8)
2101 for (x=0; x < (long) image->columns; x++)
2102 {
2103 pixel=ScaleQuantumToAny(p->red,range);
2104 q=PopCharPixel((unsigned char) pixel,q);
2105 pixel=ScaleQuantumToAny(p->green,range);
2106 q=PopCharPixel((unsigned char) pixel,q);
2107 pixel=ScaleQuantumToAny(p->blue,range);
2108 q=PopCharPixel((unsigned char) pixel,q);
2109 if (image->matte != MagickFalse)
2110 {
2111 pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002112 GetOpacityPixelComponent(p)),range);
cristy3ed852e2009-09-05 21:47:34 +00002113 q=PopCharPixel((unsigned char) pixel,q);
2114 }
2115 p++;
2116 }
2117 else
2118 for (x=0; x < (long) image->columns; x++)
2119 {
2120 pixel=ScaleQuantumToAny(p->red,range);
2121 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2122 pixel=ScaleQuantumToAny(p->green,range);
2123 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2124 pixel=ScaleQuantumToAny(p->blue,range);
2125 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2126 if (image->matte != MagickFalse)
2127 {
2128 pixel=ScaleQuantumToAny((Quantum) (QuantumRange-
cristyce70c172010-01-07 17:15:30 +00002129 GetOpacityPixelComponent(p)),range);
cristy3ed852e2009-09-05 21:47:34 +00002130 q=PopShortPixel(MSBEndian,(unsigned short) pixel,q);
2131 }
2132 p++;
2133 }
2134 break;
2135 }
2136 }
2137 extent=(size_t) (q-pixels);
2138 }
2139 count=WriteBlob(image,extent,pixels);
2140 if (count != (ssize_t) extent)
2141 break;
2142 if (image->previous == (Image *) NULL)
2143 {
2144 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2145 if (status == MagickFalse)
2146 break;
2147 }
2148 }
2149 quantum_info=DestroyQuantumInfo(quantum_info);
2150 break;
2151 }
2152 case 'F':
2153 case 'f':
2154 {
2155 (void) WriteBlobString(image,image->endian != LSBEndian ? "1.0\n" :
2156 "-1.0\n");
2157 image->depth=32;
2158 quantum_type=format == 'f' ? GrayQuantum : RGBQuantum;
2159 quantum_info=AcquireQuantumInfo((const ImageInfo *) NULL,image);
2160 if (quantum_info == (QuantumInfo *) NULL)
2161 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2162 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2163 if (status == MagickFalse)
2164 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2165 pixels=GetQuantumPixels(quantum_info);
2166 for (y=(long) image->rows-1; y >= 0; y--)
2167 {
2168 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00002169 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00002170
2171 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
2172 if (p == (const PixelPacket *) NULL)
2173 break;
2174 extent=ExportQuantumPixels(image,(const CacheView *) NULL,
2175 quantum_info,quantum_type,pixels,&image->exception);
2176 (void) WriteBlob(image,extent,pixels);
2177 if (image->previous == (Image *) NULL)
2178 {
2179 status=SetImageProgress(image,SaveImageTag,y,image->rows);
2180 if (status == MagickFalse)
2181 break;
2182 }
2183 }
2184 quantum_info=DestroyQuantumInfo(quantum_info);
2185 break;
2186 }
2187 }
2188 if (GetNextImageInList(image) == (Image *) NULL)
2189 break;
2190 image=SyncNextImageInList(image);
2191 status=SetImageProgress(image,SaveImagesTag,scene++,
2192 GetImageListLength(image));
2193 if (status == MagickFalse)
2194 break;
2195 } while (image_info->adjoin != MagickFalse);
2196 (void) CloseBlob(image);
2197 return(MagickTrue);
2198}