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