2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % Read/Write Compuserv Graphics Interchange Format %
20 % Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/blob-private.h"
45 #include "magick/cache.h"
46 #include "magick/color.h"
47 #include "magick/color-private.h"
48 #include "magick/colormap.h"
49 #include "magick/colormap-private.h"
50 #include "magick/colorspace.h"
51 #include "magick/exception.h"
52 #include "magick/exception-private.h"
53 #include "magick/image.h"
54 #include "magick/image-private.h"
55 #include "magick/list.h"
56 #include "magick/profile.h"
57 #include "magick/magick.h"
58 #include "magick/memory_.h"
59 #include "magick/monitor.h"
60 #include "magick/monitor-private.h"
61 #include "magick/option.h"
62 #include "magick/property.h"
63 #include "magick/quantize.h"
64 #include "magick/quantum-private.h"
65 #include "magick/static.h"
66 #include "magick/string_.h"
67 #include "magick/module.h"
72 #define MaximumLZWBits 12
73 #define MaximumLZWCode (1UL << MaximumLZWBits)
78 typedef struct _LZWCodeInfo
91 typedef struct _LZWStack
99 typedef struct _LZWInfo
127 Forward declarations.
130 GetNextLZWCode(LZWInfo *,const size_t);
132 static MagickBooleanType
133 WriteGIFImage(const ImageInfo *,Image *);
136 ReadBlobBlock(Image *,unsigned char *);
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 % D e c o d e I m a g e %
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149 % DecodeImage uncompresses an image via GIF-coding.
151 % The format of the DecodeImage method is:
153 % MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
155 % A description of each parameter follows:
157 % o image: the address of a structure of type Image.
159 % o opacity: The colormap index associated with the transparent color.
163 static LZWInfo *RelinquishLZWInfo(LZWInfo *lzw_info)
165 if (lzw_info->table[0] != (size_t *) NULL)
166 lzw_info->table[0]=(size_t *) RelinquishMagickMemory(
168 if (lzw_info->table[1] != (size_t *) NULL)
169 lzw_info->table[1]=(size_t *) RelinquishMagickMemory(
171 if (lzw_info->stack != (LZWStack *) NULL)
173 if (lzw_info->stack->codes != (size_t *) NULL)
174 lzw_info->stack->codes=(size_t *) RelinquishMagickMemory(
175 lzw_info->stack->codes);
176 lzw_info->stack=(LZWStack *) RelinquishMagickMemory(lzw_info->stack);
178 lzw_info=(LZWInfo *) RelinquishMagickMemory(lzw_info);
179 return((LZWInfo *) NULL);
182 static inline void ResetLZWInfo(LZWInfo *lzw_info)
187 lzw_info->bits=lzw_info->data_size+1;
189 lzw_info->maximum_code=one << lzw_info->bits;
190 lzw_info->slot=lzw_info->maximum_data_value+3;
191 lzw_info->genesis=MagickTrue;
194 static LZWInfo *AcquireLZWInfo(Image *image,const size_t data_size)
205 lzw_info=(LZWInfo *) AcquireMagickMemory(sizeof(*lzw_info));
206 if (lzw_info == (LZWInfo *) NULL)
207 return((LZWInfo *) NULL);
208 (void) ResetMagickMemory(lzw_info,0,sizeof(*lzw_info));
209 lzw_info->image=image;
210 lzw_info->data_size=data_size;
212 lzw_info->maximum_data_value=(one << data_size)-1;
213 lzw_info->clear_code=lzw_info->maximum_data_value+1;
214 lzw_info->end_code=lzw_info->maximum_data_value+2;
215 lzw_info->table[0]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
216 sizeof(*lzw_info->table));
217 lzw_info->table[1]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
218 sizeof(*lzw_info->table));
219 if ((lzw_info->table[0] == (size_t *) NULL) ||
220 (lzw_info->table[1] == (size_t *) NULL))
222 lzw_info=RelinquishLZWInfo(lzw_info);
223 return((LZWInfo *) NULL);
225 for (i=0; i <= (ssize_t) lzw_info->maximum_data_value; i++)
227 lzw_info->table[0][i]=0;
228 lzw_info->table[1][i]=(size_t) i;
230 ResetLZWInfo(lzw_info);
231 lzw_info->code_info.buffer[0]='\0';
232 lzw_info->code_info.buffer[1]='\0';
233 lzw_info->code_info.count=2;
234 lzw_info->code_info.bit=8*lzw_info->code_info.count;
235 lzw_info->code_info.eof=MagickFalse;
236 lzw_info->genesis=MagickTrue;
237 lzw_info->stack=(LZWStack *) AcquireMagickMemory(sizeof(*lzw_info->stack));
238 if (lzw_info->stack == (LZWStack *) NULL)
240 lzw_info=RelinquishLZWInfo(lzw_info);
241 return((LZWInfo *) NULL);
243 lzw_info->stack->codes=(size_t *) AcquireQuantumMemory(2UL*
244 MaximumLZWCode,sizeof(*lzw_info->stack->codes));
245 if (lzw_info->stack->codes == (size_t *) NULL)
247 lzw_info=RelinquishLZWInfo(lzw_info);
248 return((LZWInfo *) NULL);
250 lzw_info->stack->index=lzw_info->stack->codes;
251 lzw_info->stack->top=lzw_info->stack->codes+2*MaximumLZWCode;
255 static inline int GetNextLZWCode(LZWInfo *lzw_info,const size_t bits)
266 while (((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count)) &&
267 (lzw_info->code_info.eof == MagickFalse))
272 lzw_info->code_info.buffer[0]=lzw_info->code_info.buffer[
273 lzw_info->code_info.count-2];
274 lzw_info->code_info.buffer[1]=lzw_info->code_info.buffer[
275 lzw_info->code_info.count-1];
276 lzw_info->code_info.bit-=8*(lzw_info->code_info.count-2);
277 lzw_info->code_info.count=2;
278 count=ReadBlobBlock(lzw_info->image,&lzw_info->code_info.buffer[
279 lzw_info->code_info.count]);
281 lzw_info->code_info.count+=count;
283 lzw_info->code_info.eof=MagickTrue;
285 if ((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count))
289 for (i=0; i < (ssize_t) bits; i++)
291 code|=((lzw_info->code_info.buffer[lzw_info->code_info.bit/8] &
292 (one << (lzw_info->code_info.bit % 8))) != 0) << i;
293 lzw_info->code_info.bit++;
298 static inline int PopLZWStack(LZWStack *stack_info)
300 if (stack_info->index <= stack_info->codes)
303 return((int) *stack_info->index);
306 static inline void PushLZWStack(LZWStack *stack_info,const size_t value)
308 if (stack_info->index >= stack_info->top)
310 *stack_info->index=value;
314 static int ReadBlobLZWByte(LZWInfo *lzw_info)
326 if (lzw_info->stack->index != lzw_info->stack->codes)
327 return(PopLZWStack(lzw_info->stack));
328 if (lzw_info->genesis != MagickFalse)
330 lzw_info->genesis=MagickFalse;
333 lzw_info->first_code=(size_t) GetNextLZWCode(lzw_info,
335 lzw_info->last_code=lzw_info->first_code;
336 } while (lzw_info->first_code == lzw_info->clear_code);
337 return((int) lzw_info->first_code);
339 code=GetNextLZWCode(lzw_info,lzw_info->bits);
342 if ((size_t) code == lzw_info->clear_code)
344 ResetLZWInfo(lzw_info);
345 return(ReadBlobLZWByte(lzw_info));
347 if ((size_t) code == lzw_info->end_code)
349 if ((size_t) code < lzw_info->slot)
353 PushLZWStack(lzw_info->stack,lzw_info->first_code);
354 value=lzw_info->last_code;
357 while (value > lzw_info->maximum_data_value)
359 if ((size_t) count > MaximumLZWCode)
362 if ((size_t) value > MaximumLZWCode)
364 PushLZWStack(lzw_info->stack,lzw_info->table[1][value]);
365 value=lzw_info->table[0][value];
367 lzw_info->first_code=lzw_info->table[1][value];
368 PushLZWStack(lzw_info->stack,lzw_info->first_code);
370 if (lzw_info->slot < MaximumLZWCode)
372 lzw_info->table[0][lzw_info->slot]=lzw_info->last_code;
373 lzw_info->table[1][lzw_info->slot]=lzw_info->first_code;
375 if ((lzw_info->slot >= lzw_info->maximum_code) &&
376 (lzw_info->bits < MaximumLZWBits))
379 lzw_info->maximum_code=one << lzw_info->bits;
382 lzw_info->last_code=(size_t) code;
383 return(PopLZWStack(lzw_info->stack));
386 static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
411 Allocate decoder tables.
413 assert(image != (Image *) NULL);
414 assert(image->signature == MagickSignature);
415 if (image->debug != MagickFalse)
416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
417 data_size=(unsigned char) ReadBlobByte(image);
418 if (data_size > MaximumLZWBits)
419 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
420 lzw_info=AcquireLZWInfo(image,data_size);
421 if (lzw_info == (LZWInfo *) NULL)
422 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
424 exception=(&image->exception);
427 for (y=0; y < (ssize_t) image->rows; y++)
438 q=GetAuthenticPixels(image,0,offset,image->columns,1,exception);
439 if (q == (PixelPacket *) NULL)
441 indexes=GetAuthenticIndexQueue(image);
442 for (x=0; x < (ssize_t) image->columns; )
444 c=ReadBlobLZWByte(lzw_info);
447 index=ConstrainColormapIndex(image,(size_t) c);
448 SetIndexPixelComponent(indexes+x,index);
449 SetRedPixelComponent(q,image->colormap[(ssize_t) index].red);
450 SetGreenPixelComponent(q,image->colormap[(ssize_t) index].green);
451 SetBluePixelComponent(q,image->colormap[(ssize_t) index].blue);
452 SetOpacityPixelComponent(q,(ssize_t) index == opacity ?
453 TransparentOpacity : OpaqueOpacity);
457 if (x < (ssize_t) image->columns)
459 if (image->interlace == NoInterlace)
468 if (offset >= (ssize_t) image->rows)
478 if (offset >= (ssize_t) image->rows)
488 if (offset >= (ssize_t) image->rows)
501 if (SyncAuthenticPixels(image,exception) == MagickFalse)
504 lzw_info=RelinquishLZWInfo(lzw_info);
505 if (y < (ssize_t) image->rows)
506 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
515 % E n c o d e I m a g e %
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
521 % EncodeImage compresses an image via GIF-coding.
523 % The format of the EncodeImage method is:
525 % MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
526 % const size_t data_size)
528 % A description of each parameter follows:
530 % o image_info: the image info.
532 % o image: the address of a structure of type Image.
534 % o data_size: The number of bits in the compressed packet.
537 static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
538 const size_t data_size)
540 #define MaxCode(number_bits) ((one << (number_bits))-1)
541 #define MaxHashTable 5003
542 #define MaxGIFBits 12UL
543 #define MaxGIFTable (1UL << MaxGIFBits)
544 #define GIFOutputCode(code) \
550 datum|=(code) << bits; \
557 Add a character to current packet. \
559 packet[length++]=(unsigned char) (datum & 0xff); \
562 (void) WriteBlobByte(image,(unsigned char) length); \
563 (void) WriteBlob(image,length,packet); \
569 if (free_code > max_code) \
572 if (number_bits == MaxGIFBits) \
573 max_code=MaxGIFTable; \
575 max_code=MaxCode(number_bits); \
594 end_of_information_code,
614 Allocate encoder tables.
616 assert(image != (Image *) NULL);
618 packet=(unsigned char *) AcquireQuantumMemory(256,sizeof(*packet));
619 hash_code=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_code));
620 hash_prefix=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_prefix));
621 hash_suffix=(unsigned char *) AcquireQuantumMemory(MaxHashTable,
622 sizeof(*hash_suffix));
623 if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
624 (hash_prefix == (short *) NULL) ||
625 (hash_suffix == (unsigned char *) NULL))
627 if (packet != (unsigned char *) NULL)
628 packet=(unsigned char *) RelinquishMagickMemory(packet);
629 if (hash_code != (short *) NULL)
630 hash_code=(short *) RelinquishMagickMemory(hash_code);
631 if (hash_prefix != (short *) NULL)
632 hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
633 if (hash_suffix != (unsigned char *) NULL)
634 hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
638 Initialize GIF encoder.
640 number_bits=data_size;
641 max_code=MaxCode(number_bits);
642 clear_code=((short) one << (data_size-1));
643 end_of_information_code=clear_code+1;
644 free_code=clear_code+2;
648 for (i=0; i < MaxHashTable; i++)
650 GIFOutputCode(clear_code);
657 for (y=0; y < (ssize_t) image->rows; y++)
659 register const IndexPacket
662 register const PixelPacket
668 p=GetVirtualPixels(image,0,offset,image->columns,1,&image->exception);
669 if (p == (const PixelPacket *) NULL)
671 indexes=GetVirtualIndexQueue(image);
673 waiting_code=(short) (*indexes);
674 for (x=(ssize_t) (y == 0 ? 1 : 0); x < (ssize_t) image->columns; x++)
679 index=(IndexPacket) ((size_t) GetIndexPixelComponent(indexes+x) & 0xff);
681 k=(ssize_t) (((size_t) index << (MaxGIFBits-8))+waiting_code);
682 if (k >= MaxHashTable)
684 next_pixel=MagickFalse;
686 if (hash_code[k] > 0)
688 if ((hash_prefix[k] == waiting_code) &&
689 (hash_suffix[k] == (unsigned char) index))
691 waiting_code=hash_code[k];
695 displacement=MaxHashTable-k;
701 if (hash_code[k] == 0)
703 if ((hash_prefix[k] == waiting_code) &&
704 (hash_suffix[k] == (unsigned char) index))
706 waiting_code=hash_code[k];
707 next_pixel=MagickTrue;
711 if (next_pixel == MagickTrue)
714 GIFOutputCode((size_t) waiting_code);
715 if (free_code < MaxGIFTable)
717 hash_code[k]=(short) free_code++;
718 hash_prefix[k]=waiting_code;
719 hash_suffix[k]=(unsigned char) index;
724 Fill the hash table with empty entries.
726 for (k=0; k < MaxHashTable; k++)
729 Reset compressor and issue a clear code.
731 free_code=clear_code+2;
732 GIFOutputCode(clear_code);
733 number_bits=data_size;
734 max_code=MaxCode(number_bits);
736 waiting_code=(short) index;
738 if (image_info->interlace == NoInterlace)
747 if (offset >= (ssize_t) image->rows)
757 if (offset >= (ssize_t) image->rows)
767 if (offset >= (ssize_t) image->rows)
782 Flush out the buffered code.
784 GIFOutputCode((size_t) waiting_code);
785 GIFOutputCode(end_of_information_code);
789 Add a character to current packet.
791 packet[length++]=(unsigned char) (datum & 0xff);
794 (void) WriteBlobByte(image,(unsigned char) length);
795 (void) WriteBlob(image,length,packet);
800 Flush accumulated data.
804 (void) WriteBlobByte(image,(unsigned char) length);
805 (void) WriteBlob(image,length,packet);
810 hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
811 hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
812 hash_code=(short *) RelinquishMagickMemory(hash_code);
813 packet=(unsigned char *) RelinquishMagickMemory(packet);
818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
828 % IsGIF() returns MagickTrue if the image format type, identified by the
829 % magick string, is GIF.
831 % The format of the IsGIF method is:
833 % MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
835 % A description of each parameter follows:
837 % o magick: compare image format pattern against these bytes.
839 % o length: Specifies the length of the magick string.
842 static MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
846 if (LocaleNCompare((char *) magick,"GIF8",4) == 0)
852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
856 + R e a d B l o b B l o c k %
860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
862 % ReadBlobBlock() reads data from the image file and returns it. The
863 % amount of data is determined by first reading a count byte. The number
864 % of bytes read is returned.
866 % The format of the ReadBlobBlock method is:
868 % size_t ReadBlobBlock(Image *image,unsigned char *data)
870 % A description of each parameter follows:
872 % o image: the image.
874 % o data: Specifies an area to place the information requested from
878 static ssize_t ReadBlobBlock(Image *image,unsigned char *data)
886 assert(image != (Image *) NULL);
887 assert(image->signature == MagickSignature);
888 assert(data != (unsigned char *) NULL);
889 count=ReadBlob(image,1,&block_count);
892 return(ReadBlob(image,(size_t) block_count,data));
896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
900 % R e a d G I F I m a g e %
904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
906 % ReadGIFImage() reads a Compuserve Graphics image file and returns it.
907 % It allocates the memory necessary for the new Image structure and returns a
908 % pointer to the new image.
910 % The format of the ReadGIFImage method is:
912 % Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
914 % A description of each parameter follows:
916 % o image_info: the image info.
918 % o exception: return any errors or warnings in this structure.
922 static inline size_t MagickMax(const size_t x,const size_t y)
929 static inline size_t MagickMin(const size_t x,const size_t y)
936 static MagickBooleanType PingGIFImage(Image *image)
943 assert(image != (Image *) NULL);
944 assert(image->signature == MagickSignature);
945 if (image->debug != MagickFalse)
946 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
947 if (ReadBlob(image,1,&data_size) != 1)
948 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
949 if (data_size > MaximumLZWBits)
950 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
951 if (ReadBlob(image,1,&length) != 1)
952 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
955 if (ReadBlob(image,length,buffer) != (ssize_t) length)
956 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
957 if (ReadBlob(image,1,&length) != 1)
958 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
963 static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
965 #define BitSet(byte,bit) (((byte) & (bit)) == (bit))
966 #define LSBFirstOrder(x,y) (((y) << 8) | (x))
972 number_extensionss=0;
983 register unsigned char
1003 header[MaxTextExtent],
1009 assert(image_info != (const ImageInfo *) NULL);
1010 assert(image_info->signature == MagickSignature);
1011 if (image_info->debug != MagickFalse)
1012 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1013 image_info->filename);
1014 assert(exception != (ExceptionInfo *) NULL);
1015 assert(exception->signature == MagickSignature);
1016 image=AcquireImage(image_info);
1017 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1018 if (status == MagickFalse)
1020 image=DestroyImageList(image);
1021 return((Image *) NULL);
1024 Determine if this a GIF file.
1026 count=ReadBlob(image,6,magick);
1027 if ((count != 6) || ((LocaleNCompare((char *) magick,"GIF87",5) != 0) &&
1028 (LocaleNCompare((char *) magick,"GIF89",5) != 0)))
1029 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1030 page.width=ReadBlobLSBShort(image);
1031 page.height=ReadBlobLSBShort(image);
1032 flag=(unsigned char) ReadBlobByte(image);
1033 background=(unsigned char) ReadBlobByte(image);
1034 c=(unsigned char) ReadBlobByte(image); /* reserved */
1036 global_colors=one << (((size_t) flag & 0x07)+1);
1037 global_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1038 MagickMax(global_colors,256),3UL*sizeof(*global_colormap));
1039 if (global_colormap == (unsigned char *) NULL)
1040 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1041 if (BitSet((int) flag,0x80) != 0)
1042 count=ReadBlob(image,(size_t) (3*global_colors),global_colormap);
1050 count=ReadBlob(image,1,&c);
1053 if (c == (unsigned char) ';')
1054 break; /* terminator */
1055 if (c == (unsigned char) '!')
1058 GIF Extension block.
1061 count=ReadBlob(image,1,&c);
1064 global_colormap=(unsigned char *) RelinquishMagickMemory(
1066 ThrowReaderException(CorruptImageError,
1067 "UnableToReadExtensionBlock");
1074 Read graphics control extension.
1076 while (ReadBlobBlock(image,header) != 0) ;
1077 dispose=(size_t) (header[0] >> 2);
1078 delay=(size_t) ((header[2] << 8) | header[1]);
1079 if ((ssize_t) (header[0] & 0x01) == 0x01)
1080 opacity=(ssize_t) header[3];
1089 Read comment extension.
1091 comments=AcquireString((char *) NULL);
1094 count=(ssize_t) ReadBlobBlock(image,header);
1098 (void) ConcatenateString(&comments,(const char *) header);
1100 (void) SetImageProperty(image,"comment",comments);
1101 comments=DestroyString(comments);
1106 /* Read GIF application extension */
1112 Read Netscape Loop extension.
1115 if (ReadBlobBlock(image,header) != 0)
1116 loop=LocaleNCompare((char *) header,"NETSCAPE2.0",11) == 0 ?
1117 MagickTrue : MagickFalse;
1118 if (loop != MagickFalse)
1120 while (ReadBlobBlock(image,header) != 0)
1121 iterations=(size_t) ((header[2] << 8) | header[1]);
1127 name[MaxTextExtent];
1146 Store GIF application extension as a generic profile.
1148 i8bim=LocaleNCompare((char *) header,"MGK8BIM0000",11) == 0 ?
1149 MagickTrue : MagickFalse;
1150 icc=LocaleNCompare((char *) header,"ICCRGBG1012",11) == 0 ?
1151 MagickTrue : MagickFalse;
1152 iptc=LocaleNCompare((char *) header,"MGKIPTC0000",11) == 0 ?
1153 MagickTrue : MagickFalse;
1154 number_extensionss++;
1155 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1156 " Reading GIF application extension");
1157 info=(unsigned char *) AcquireQuantumMemory(255UL,
1159 reserved_length=255;
1160 for (info_length=0; ; )
1162 block_length=(int) ReadBlobBlock(image,&info[info_length]);
1163 if (block_length == 0)
1165 info_length+=block_length;
1166 if (info_length > (reserved_length-255))
1168 reserved_length+=4096;
1169 info=(unsigned char *) ResizeQuantumMemory(info,
1170 (size_t) reserved_length,sizeof(*info));
1173 info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
1174 (info_length+1),sizeof(*info));
1175 profile=AcquireStringInfo((size_t) info_length);
1176 SetStringInfoDatum(profile,(const unsigned char *) info);
1177 if (i8bim == MagickTrue)
1178 (void) CopyMagickString(name,"8bim",sizeof(name));
1179 else if (icc == MagickTrue)
1180 (void) CopyMagickString(name,"icc",sizeof(name));
1181 else if (iptc == MagickTrue)
1182 (void) CopyMagickString(name,"iptc",sizeof(name));
1184 (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
1186 (void) SetImageProfile(image,name,profile);
1187 info=(unsigned char *) RelinquishMagickMemory(info);
1188 profile=DestroyStringInfo(profile);
1189 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1190 " profile name=%s",name);
1196 while (ReadBlobBlock(image,header) != 0) ;
1201 if (c != (unsigned char) ',')
1203 if (image_count != 0)
1206 Allocate next image structure.
1208 AcquireNextImage(image_info,image);
1209 if (GetNextImageInList(image) == (Image *) NULL)
1211 image=DestroyImageList(image);
1212 global_colormap=(unsigned char *) RelinquishMagickMemory(
1214 return((Image *) NULL);
1216 image=SyncNextImageInList(image);
1220 Read image attributes.
1222 image->storage_class=PseudoClass;
1223 image->compression=LZWCompression;
1224 page.x=(ssize_t) ReadBlobLSBShort(image);
1225 page.y=(ssize_t) ReadBlobLSBShort(image);
1226 image->columns=ReadBlobLSBShort(image);
1227 image->rows=ReadBlobLSBShort(image);
1229 flag=(unsigned char) ReadBlobByte(image);
1230 image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace :
1232 image->colors=BitSet((int) flag,0x80) == 0 ? global_colors :
1233 one << ((size_t) (flag & 0x07)+1);
1234 if (opacity >= (ssize_t) image->colors)
1236 image->page.width=page.width;
1237 image->page.height=page.height;
1238 image->page.y=page.y;
1239 image->page.x=page.x;
1241 image->ticks_per_second=100;
1242 image->dispose=(DisposeType) dispose;
1243 image->iterations=iterations;
1244 image->matte=opacity >= 0 ? MagickTrue : MagickFalse;
1248 if ((image->columns == 0) || (image->rows == 0))
1250 global_colormap=(unsigned char *) RelinquishMagickMemory(
1252 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1255 Inititialize colormap.
1257 if (AcquireImageColormap(image,image->colors) == MagickFalse)
1259 global_colormap=(unsigned char *) RelinquishMagickMemory(
1261 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1263 if (BitSet((int) flag,0x80) == 0)
1266 Use global colormap.
1269 for (i=0; i < (ssize_t) image->colors; i++)
1271 image->colormap[i].red=ScaleCharToQuantum(*p++);
1272 image->colormap[i].green=ScaleCharToQuantum(*p++);
1273 image->colormap[i].blue=ScaleCharToQuantum(*p++);
1276 image->colormap[i].opacity=(Quantum) TransparentOpacity;
1277 image->transparent_color=image->colormap[opacity];
1280 image->background_color=image->colormap[MagickMin(background,
1289 Read local colormap.
1291 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1292 3*sizeof(*colormap));
1293 if (colormap == (unsigned char *) NULL)
1295 global_colormap=(unsigned char *) RelinquishMagickMemory(
1297 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1299 count=ReadBlob(image,(3*image->colors)*sizeof(*colormap),colormap);
1300 if (count != (ssize_t) (3*image->colors))
1302 global_colormap=(unsigned char *) RelinquishMagickMemory(
1304 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1305 ThrowReaderException(CorruptImageError,
1306 "InsufficientImageDataInFile");
1309 for (i=0; i < (ssize_t) image->colors; i++)
1311 image->colormap[i].red=ScaleCharToQuantum(*p++);
1312 image->colormap[i].green=ScaleCharToQuantum(*p++);
1313 image->colormap[i].blue=ScaleCharToQuantum(*p++);
1315 image->colormap[i].opacity=(Quantum) TransparentOpacity;
1317 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1319 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1320 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1325 if (image_info->ping != MagickFalse)
1326 status=PingGIFImage(image);
1328 status=DecodeImage(image,opacity);
1329 if ((image_info->ping == MagickFalse) && (status == MagickFalse))
1331 global_colormap=(unsigned char *) RelinquishMagickMemory(
1333 ThrowReaderException(CorruptImageError,"CorruptImage");
1335 if (image_info->number_scenes != 0)
1336 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1339 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) image->scene-
1341 if (status == MagickFalse)
1344 global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1345 if ((image->columns == 0) || (image->rows == 0))
1346 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1347 (void) CloseBlob(image);
1348 return(GetFirstImageInList(image));
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356 % R e g i s t e r G I F I m a g e %
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 % RegisterGIFImage() adds properties for the GIF image format to
1363 % the list of supported formats. The properties include the image format
1364 % tag, a method to read and/or write the format, whether the format
1365 % supports the saving of more than one frame to the same file or blob,
1366 % whether the format supports native in-memory I/O, and a brief
1367 % description of the format.
1369 % The format of the RegisterGIFImage method is:
1371 % size_t RegisterGIFImage(void)
1374 ModuleExport size_t RegisterGIFImage(void)
1379 entry=SetMagickInfo("GIF");
1380 entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1381 entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1382 entry->magick=(IsImageFormatHandler *) IsGIF;
1383 entry->description=ConstantString("CompuServe graphics interchange format");
1384 entry->module=ConstantString("GIF");
1385 (void) RegisterMagickInfo(entry);
1386 entry=SetMagickInfo("GIF87");
1387 entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1388 entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1389 entry->magick=(IsImageFormatHandler *) IsGIF;
1390 entry->adjoin=MagickFalse;
1391 entry->description=ConstantString("CompuServe graphics interchange format");
1392 entry->version=ConstantString("version 87a");
1393 entry->module=ConstantString("GIF");
1394 (void) RegisterMagickInfo(entry);
1395 return(MagickImageCoderSignature);
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403 % U n r e g i s t e r G I F I m a g e %
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 % UnregisterGIFImage() removes format registrations made by the
1410 % GIF module from the list of supported formats.
1412 % The format of the UnregisterGIFImage method is:
1414 % UnregisterGIFImage(void)
1417 ModuleExport void UnregisterGIFImage(void)
1419 (void) UnregisterMagickInfo("GIF");
1420 (void) UnregisterMagickInfo("GIF87");
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 % W r i t e G I F I m a g e %
1432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434 % WriteGIFImage() writes an image to a file in the Compuserve Graphics
1437 % The format of the WriteGIFImage method is:
1439 % MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image)
1441 % A description of each parameter follows.
1443 % o image_info: the image info.
1445 % o image: The image.
1448 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image)
1474 register unsigned char
1492 Open output image file.
1494 assert(image_info != (const ImageInfo *) NULL);
1495 assert(image_info->signature == MagickSignature);
1496 assert(image != (Image *) NULL);
1497 assert(image->signature == MagickSignature);
1498 if (image->debug != MagickFalse)
1499 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1500 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1501 if (status == MagickFalse)
1506 global_colormap=(unsigned char *) AcquireQuantumMemory(768UL,
1507 sizeof(*global_colormap));
1508 colormap=(unsigned char *) AcquireQuantumMemory(768UL,sizeof(*colormap));
1509 if ((global_colormap == (unsigned char *) NULL) ||
1510 (colormap == (unsigned char *) NULL))
1511 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1512 for (i=0; i < 768; i++)
1513 colormap[i]=(unsigned char) 0;
1517 write_info=CloneImageInfo(image_info);
1518 if (LocaleCompare(write_info->magick,"GIF87") != 0)
1519 (void) WriteBlob(image,6,(unsigned char *) "GIF89a");
1522 (void) WriteBlob(image,6,(unsigned char *) "GIF87a");
1523 write_info->adjoin=MagickFalse;
1526 Determine image bounding box.
1528 page.width=image->columns;
1529 page.height=image->rows;
1532 if (write_info->adjoin != MagickFalse)
1533 for (next_image=image; next_image != (Image *) NULL; )
1535 page.x=next_image->page.x;
1536 page.y=next_image->page.y;
1537 if ((next_image->page.width+page.x) > page.width)
1538 page.width=next_image->page.width+page.x;
1539 if ((next_image->page.height+page.y) > page.height)
1540 page.height=next_image->page.height+page.y;
1541 next_image=GetNextImageInList(next_image);
1543 page.x=image->page.x;
1544 page.y=image->page.y;
1545 if ((image->page.width != 0) && (image->page.height != 0))
1547 (void) WriteBlobLSBShort(image,(unsigned short) page.width);
1548 (void) WriteBlobLSBShort(image,(unsigned short) page.height);
1550 Write images to file.
1552 interlace=write_info->interlace;
1553 if ((write_info->adjoin != MagickFalse) &&
1554 (GetNextImageInList(image) != (Image *) NULL))
1555 interlace=NoInterlace;
1560 if (image->colorspace != RGBColorspace)
1561 (void) TransformImageColorspace(image,RGBColorspace);
1563 if (IsOpaqueImage(image,&image->exception) != MagickFalse)
1565 if ((image->storage_class == DirectClass) || (image->colors > 256))
1566 (void) SetImageType(image,PaletteType);
1575 Identify transparent colormap index.
1577 if ((image->storage_class == DirectClass) || (image->colors > 256))
1578 (void) SetImageType(image,PaletteBilevelMatteType);
1579 for (i=0; i < (ssize_t) image->colors; i++)
1580 if (image->colormap[i].opacity != OpaqueOpacity)
1587 alpha=(MagickRealType) TransparentOpacity-(MagickRealType)
1588 image->colormap[i].opacity;
1589 beta=(MagickRealType) TransparentOpacity-(MagickRealType)
1590 image->colormap[opacity].opacity;
1596 (void) SetImageType(image,PaletteBilevelMatteType);
1597 for (i=0; i < (ssize_t) image->colors; i++)
1598 if (image->colormap[i].opacity != OpaqueOpacity)
1605 alpha=(Quantum) TransparentOpacity-(MagickRealType)
1606 image->colormap[i].opacity;
1607 beta=(Quantum) TransparentOpacity-(MagickRealType)
1608 image->colormap[opacity].opacity;
1615 image->colormap[opacity].red=image->transparent_color.red;
1616 image->colormap[opacity].green=image->transparent_color.green;
1617 image->colormap[opacity].blue=image->transparent_color.blue;
1620 if ((image->storage_class == DirectClass) || (image->colors > 256))
1621 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1622 for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
1623 if ((one << bits_per_pixel) >= image->colors)
1626 for (i=0; i < (ssize_t) image->colors; i++)
1628 *q++=ScaleQuantumToChar(image->colormap[i].red);
1629 *q++=ScaleQuantumToChar(image->colormap[i].green);
1630 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1632 for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
1634 *q++=(unsigned char) 0x0;
1635 *q++=(unsigned char) 0x0;
1636 *q++=(unsigned char) 0x0;
1638 if ((GetPreviousImageInList(image) == (Image *) NULL) ||
1639 (write_info->adjoin == MagickFalse))
1642 Write global colormap.
1645 c|=(8-1) << 4; /* color resolution */
1646 c|=(bits_per_pixel-1); /* size of global colormap */
1647 (void) WriteBlobByte(image,(unsigned char) c);
1648 for (j=0; j < (ssize_t) image->colors; j++)
1649 if (IsColorEqual(&image->background_color,image->colormap+j))
1651 (void) WriteBlobByte(image,(unsigned char)
1652 (j == (ssize_t) image->colors ? 0 : j)); /* background color */
1653 (void) WriteBlobByte(image,(unsigned char) 0x00); /* reserved */
1654 length=(size_t) (3*(one << bits_per_pixel));
1655 (void) WriteBlob(image,length,colormap);
1656 for (j=0; j < 768; j++)
1657 global_colormap[j]=colormap[j];
1659 if (LocaleCompare(write_info->magick,"GIF87") != 0)
1662 Write graphics control extension.
1664 (void) WriteBlobByte(image,(unsigned char) 0x21);
1665 (void) WriteBlobByte(image,(unsigned char) 0xf9);
1666 (void) WriteBlobByte(image,(unsigned char) 0x04);
1667 c=image->dispose << 2;
1670 (void) WriteBlobByte(image,(unsigned char) c);
1671 delay=(size_t) (100*image->delay/MagickMax((size_t)
1672 image->ticks_per_second,1));
1673 (void) WriteBlobLSBShort(image,(unsigned short) delay);
1674 (void) WriteBlobByte(image,(unsigned char) (opacity >= 0 ? opacity :
1676 (void) WriteBlobByte(image,(unsigned char) 0x00);
1677 if ((LocaleCompare(write_info->magick,"GIF87") != 0) &&
1678 (GetImageProperty(image,"comment") != (const char *) NULL))
1690 Write Comment extension.
1692 (void) WriteBlobByte(image,(unsigned char) 0x21);
1693 (void) WriteBlobByte(image,(unsigned char) 0xfe);
1694 value=GetImageProperty(image,"comment");
1696 while (strlen(p) != 0)
1698 count=MagickMin(strlen(p),255);
1699 (void) WriteBlobByte(image,(unsigned char) count);
1700 for (i=0; i < (ssize_t) count; i++)
1701 (void) WriteBlobByte(image,(unsigned char) *p++);
1703 (void) WriteBlobByte(image,(unsigned char) 0x00);
1705 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
1706 (GetNextImageInList(image) != (Image *) NULL) &&
1707 (image->iterations != 1))
1710 Write Netscape Loop extension.
1712 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1713 " Writing GIF Extension %s","NETSCAPE2.0");
1714 (void) WriteBlobByte(image,(unsigned char) 0x21);
1715 (void) WriteBlobByte(image,(unsigned char) 0xff);
1716 (void) WriteBlobByte(image,(unsigned char) 0x0b);
1717 (void) WriteBlob(image,11,(unsigned char *) "NETSCAPE2.0");
1718 (void) WriteBlobByte(image,(unsigned char) 0x03);
1719 (void) WriteBlobByte(image,(unsigned char) 0x01);
1720 (void) WriteBlobLSBShort(image,(unsigned short) image->iterations);
1721 (void) WriteBlobByte(image,(unsigned char) 0x00);
1723 ResetImageProfileIterator(image);
1732 name=GetNextImageProfile(image);
1733 if (name == (const char *) NULL)
1735 profile=GetImageProfile(image,name);
1736 if (profile != (StringInfo *) NULL)
1738 if ((LocaleCompare(name,"ICC") == 0) ||
1739 (LocaleCompare(name,"ICM") == 0) ||
1740 (LocaleCompare(name,"IPTC") == 0) ||
1741 (LocaleCompare(name,"8BIM") == 0) ||
1742 (LocaleNCompare(name,"gif:",4) == 0))
1753 datum=GetStringInfoDatum(profile);
1754 length=GetStringInfoLength(profile);
1755 (void) WriteBlobByte(image,(unsigned char) 0x21);
1756 (void) WriteBlobByte(image,(unsigned char) 0xff);
1757 (void) WriteBlobByte(image,(unsigned char) 0x0b);
1758 if ((LocaleCompare(name,"ICC") == 0) ||
1759 (LocaleCompare(name,"ICM") == 0))
1762 Write ICC extension.
1764 (void) WriteBlob(image,11,(unsigned char *)"ICCRGBG1012");
1765 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1766 " Writing GIF Extension %s","ICCRGBG1012");
1769 if ((LocaleCompare(name,"IPTC") == 0))
1772 write IPTC extension.
1774 (void) WriteBlob(image,11,(unsigned char *)"MGKIPTC0000");
1775 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1776 " Writing GIF Extension %s","MGKIPTC0000");
1779 if ((LocaleCompare(name,"8BIM") == 0))
1782 Write 8BIM extension>
1784 (void) WriteBlob(image,11,(unsigned char *)
1786 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1787 " Writing GIF Extension %s","MGK8BIM0000");
1792 extension[MaxTextExtent];
1794 /* write generic extension */
1795 (void) CopyMagickString(extension,name+4,
1797 (void) WriteBlob(image,11,(unsigned char *) extension);
1798 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1799 " Writing GIF Extension %s",name);
1802 while ((ssize_t) length > offset)
1807 if ((length-offset) < 255)
1808 block_length=length-offset;
1811 (void) WriteBlobByte(image,(unsigned char) block_length);
1812 (void) WriteBlob(image,(size_t) block_length,datum+offset);
1813 offset+=(ssize_t) block_length;
1815 (void) WriteBlobByte(image,(unsigned char) 0x00);
1820 (void) WriteBlobByte(image,','); /* image separator */
1822 Write the image header.
1824 page.x=image->page.x;
1825 page.y=image->page.y;
1826 if ((image->page.width != 0) && (image->page.height != 0))
1828 (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x));
1829 (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y));
1830 (void) WriteBlobLSBShort(image,(unsigned short) image->columns);
1831 (void) WriteBlobLSBShort(image,(unsigned short) image->rows);
1833 if (interlace != NoInterlace)
1834 c|=0x40; /* pixel data is interlaced */
1835 for (j=0; j < (ssize_t) (3*image->colors); j++)
1836 if (colormap[j] != global_colormap[j])
1838 if (j == (ssize_t) (3*image->colors))
1839 (void) WriteBlobByte(image,(unsigned char) c);
1843 c|=(bits_per_pixel-1); /* size of local colormap */
1844 (void) WriteBlobByte(image,(unsigned char) c);
1845 length=(size_t) (3*(one << bits_per_pixel));
1846 (void) WriteBlob(image,length,colormap);
1849 Write the image data.
1851 c=(int) MagickMax(bits_per_pixel,2);
1852 (void) WriteBlobByte(image,(unsigned char) c);
1853 status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1);
1854 if (status == MagickFalse)
1856 global_colormap=(unsigned char *) RelinquishMagickMemory(
1858 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1859 write_info=DestroyImageInfo(write_info);
1860 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1862 (void) WriteBlobByte(image,(unsigned char) 0x00);
1863 if (GetNextImageInList(image) == (Image *) NULL)
1865 image=SyncNextImageInList(image);
1867 status=SetImageProgress(image,SaveImagesTag,scene,
1868 GetImageListLength(image));
1869 if (status == MagickFalse)
1871 } while (write_info->adjoin != MagickFalse);
1872 (void) WriteBlobByte(image,';'); /* terminator */
1873 global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1874 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1875 write_info=DestroyImageInfo(write_info);
1876 (void) CloseBlob(image);