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