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