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