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