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