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 "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/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/image.h"
55 #include "MagickCore/image-private.h"
56 #include "MagickCore/list.h"
57 #include "MagickCore/profile.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/option.h"
63 #include "MagickCore/pixel.h"
64 #include "MagickCore/pixel-accessor.h"
65 #include "MagickCore/property.h"
66 #include "MagickCore/quantize.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/static.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/module.h"
75 #define MaximumLZWBits 12
76 #define MaximumLZWCode (1UL << MaximumLZWBits)
81 typedef struct _LZWCodeInfo
94 typedef struct _LZWStack
102 typedef struct _LZWInfo
130 Forward declarations.
133 GetNextLZWCode(LZWInfo *,const size_t);
135 static MagickBooleanType
136 WriteGIFImage(const ImageInfo *,Image *);
139 ReadBlobBlock(Image *,unsigned char *);
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 % D e c o d e I m a g e %
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 % DecodeImage uncompresses an image via GIF-coding.
154 % The format of the DecodeImage method is:
156 % MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
158 % A description of each parameter follows:
160 % o image: the address of a structure of type Image.
162 % o opacity: The colormap index associated with the transparent color.
166 static LZWInfo *RelinquishLZWInfo(LZWInfo *lzw_info)
168 if (lzw_info->table[0] != (size_t *) NULL)
169 lzw_info->table[0]=(size_t *) RelinquishMagickMemory(
171 if (lzw_info->table[1] != (size_t *) NULL)
172 lzw_info->table[1]=(size_t *) RelinquishMagickMemory(
174 if (lzw_info->stack != (LZWStack *) NULL)
176 if (lzw_info->stack->codes != (size_t *) NULL)
177 lzw_info->stack->codes=(size_t *) RelinquishMagickMemory(
178 lzw_info->stack->codes);
179 lzw_info->stack=(LZWStack *) RelinquishMagickMemory(lzw_info->stack);
181 lzw_info=(LZWInfo *) RelinquishMagickMemory(lzw_info);
182 return((LZWInfo *) NULL);
185 static inline void ResetLZWInfo(LZWInfo *lzw_info)
190 lzw_info->bits=lzw_info->data_size+1;
192 lzw_info->maximum_code=one << lzw_info->bits;
193 lzw_info->slot=lzw_info->maximum_data_value+3;
194 lzw_info->genesis=MagickTrue;
197 static LZWInfo *AcquireLZWInfo(Image *image,const size_t data_size)
208 lzw_info=(LZWInfo *) AcquireMagickMemory(sizeof(*lzw_info));
209 if (lzw_info == (LZWInfo *) NULL)
210 return((LZWInfo *) NULL);
211 (void) ResetMagickMemory(lzw_info,0,sizeof(*lzw_info));
212 lzw_info->image=image;
213 lzw_info->data_size=data_size;
215 lzw_info->maximum_data_value=(one << data_size)-1;
216 lzw_info->clear_code=lzw_info->maximum_data_value+1;
217 lzw_info->end_code=lzw_info->maximum_data_value+2;
218 lzw_info->table[0]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
219 sizeof(*lzw_info->table));
220 lzw_info->table[1]=(size_t *) AcquireQuantumMemory(MaximumLZWCode,
221 sizeof(*lzw_info->table));
222 if ((lzw_info->table[0] == (size_t *) NULL) ||
223 (lzw_info->table[1] == (size_t *) NULL))
225 lzw_info=RelinquishLZWInfo(lzw_info);
226 return((LZWInfo *) NULL);
228 for (i=0; i <= (ssize_t) lzw_info->maximum_data_value; i++)
230 lzw_info->table[0][i]=0;
231 lzw_info->table[1][i]=(size_t) i;
233 ResetLZWInfo(lzw_info);
234 lzw_info->code_info.buffer[0]='\0';
235 lzw_info->code_info.buffer[1]='\0';
236 lzw_info->code_info.count=2;
237 lzw_info->code_info.bit=8*lzw_info->code_info.count;
238 lzw_info->code_info.eof=MagickFalse;
239 lzw_info->genesis=MagickTrue;
240 lzw_info->stack=(LZWStack *) AcquireMagickMemory(sizeof(*lzw_info->stack));
241 if (lzw_info->stack == (LZWStack *) NULL)
243 lzw_info=RelinquishLZWInfo(lzw_info);
244 return((LZWInfo *) NULL);
246 lzw_info->stack->codes=(size_t *) AcquireQuantumMemory(2UL*
247 MaximumLZWCode,sizeof(*lzw_info->stack->codes));
248 if (lzw_info->stack->codes == (size_t *) NULL)
250 lzw_info=RelinquishLZWInfo(lzw_info);
251 return((LZWInfo *) NULL);
253 lzw_info->stack->index=lzw_info->stack->codes;
254 lzw_info->stack->top=lzw_info->stack->codes+2*MaximumLZWCode;
258 static inline int GetNextLZWCode(LZWInfo *lzw_info,const size_t bits)
269 while (((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count)) &&
270 (lzw_info->code_info.eof == MagickFalse))
275 lzw_info->code_info.buffer[0]=lzw_info->code_info.buffer[
276 lzw_info->code_info.count-2];
277 lzw_info->code_info.buffer[1]=lzw_info->code_info.buffer[
278 lzw_info->code_info.count-1];
279 lzw_info->code_info.bit-=8*(lzw_info->code_info.count-2);
280 lzw_info->code_info.count=2;
281 count=ReadBlobBlock(lzw_info->image,&lzw_info->code_info.buffer[
282 lzw_info->code_info.count]);
284 lzw_info->code_info.count+=count;
286 lzw_info->code_info.eof=MagickTrue;
288 if ((lzw_info->code_info.bit+bits) > (8*lzw_info->code_info.count))
292 for (i=0; i < (ssize_t) bits; i++)
294 code|=((lzw_info->code_info.buffer[lzw_info->code_info.bit/8] &
295 (one << (lzw_info->code_info.bit % 8))) != 0) << i;
296 lzw_info->code_info.bit++;
301 static inline int PopLZWStack(LZWStack *stack_info)
303 if (stack_info->index <= stack_info->codes)
306 return((int) *stack_info->index);
309 static inline void PushLZWStack(LZWStack *stack_info,const size_t value)
311 if (stack_info->index >= stack_info->top)
313 *stack_info->index=value;
317 static int ReadBlobLZWByte(LZWInfo *lzw_info)
329 if (lzw_info->stack->index != lzw_info->stack->codes)
330 return(PopLZWStack(lzw_info->stack));
331 if (lzw_info->genesis != MagickFalse)
333 lzw_info->genesis=MagickFalse;
336 lzw_info->first_code=(size_t) GetNextLZWCode(lzw_info,
338 lzw_info->last_code=lzw_info->first_code;
339 } while (lzw_info->first_code == lzw_info->clear_code);
340 return((int) lzw_info->first_code);
342 code=GetNextLZWCode(lzw_info,lzw_info->bits);
345 if ((size_t) code == lzw_info->clear_code)
347 ResetLZWInfo(lzw_info);
348 return(ReadBlobLZWByte(lzw_info));
350 if ((size_t) code == lzw_info->end_code)
352 if ((size_t) code < lzw_info->slot)
356 PushLZWStack(lzw_info->stack,lzw_info->first_code);
357 value=lzw_info->last_code;
360 while (value > lzw_info->maximum_data_value)
362 if ((size_t) count > MaximumLZWCode)
365 if ((size_t) value > MaximumLZWCode)
367 PushLZWStack(lzw_info->stack,lzw_info->table[1][value]);
368 value=lzw_info->table[0][value];
370 lzw_info->first_code=lzw_info->table[1][value];
371 PushLZWStack(lzw_info->stack,lzw_info->first_code);
373 if (lzw_info->slot < MaximumLZWCode)
375 lzw_info->table[0][lzw_info->slot]=lzw_info->last_code;
376 lzw_info->table[1][lzw_info->slot]=lzw_info->first_code;
378 if ((lzw_info->slot >= lzw_info->maximum_code) &&
379 (lzw_info->bits < MaximumLZWBits))
382 lzw_info->maximum_code=one << lzw_info->bits;
385 lzw_info->last_code=(size_t) code;
386 return(PopLZWStack(lzw_info->stack));
389 static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
414 Allocate decoder tables.
416 assert(image != (Image *) NULL);
417 assert(image->signature == MagickSignature);
418 if (image->debug != MagickFalse)
419 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
420 data_size=(unsigned char) ReadBlobByte(image);
421 if (data_size > MaximumLZWBits)
422 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
423 lzw_info=AcquireLZWInfo(image,data_size);
424 if (lzw_info == (LZWInfo *) NULL)
425 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
427 exception=(&image->exception);
430 for (y=0; y < (ssize_t) image->rows; y++)
438 q=GetAuthenticPixels(image,0,offset,image->columns,1,exception);
439 if (q == (const Quantum *) NULL)
441 for (x=0; x < (ssize_t) image->columns; )
443 c=ReadBlobLZWByte(lzw_info);
446 index=ConstrainColormapIndex(image,(size_t) c);
447 SetPixelIndex(image,index,q);
448 SetPixelPacket(image,image->colormap+(ssize_t) index,q);
449 SetPixelAlpha(image,(ssize_t) index == opacity ? TransparentAlpha :
452 q+=GetPixelChannels(image);
454 if (x < (ssize_t) image->columns)
456 if (image->interlace == NoInterlace)
465 if (offset >= (ssize_t) image->rows)
475 if (offset >= (ssize_t) image->rows)
485 if (offset >= (ssize_t) image->rows)
498 if (SyncAuthenticPixels(image,exception) == MagickFalse)
501 lzw_info=RelinquishLZWInfo(lzw_info);
502 if (y < (ssize_t) image->rows)
503 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 % E n c o d e I m a g e %
516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 % EncodeImage compresses an image via GIF-coding.
520 % The format of the EncodeImage method is:
522 % MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
523 % const size_t data_size)
525 % A description of each parameter follows:
527 % o image_info: the image info.
529 % o image: the address of a structure of type Image.
531 % o data_size: The number of bits in the compressed packet.
534 static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
535 const size_t data_size)
537 #define MaxCode(number_bits) ((one << (number_bits))-1)
538 #define MaxHashTable 5003
539 #define MaxGIFBits 12UL
540 #define MaxGIFTable (1UL << MaxGIFBits)
541 #define GIFOutputCode(code) \
547 datum|=(code) << bits; \
554 Add a character to current packet. \
556 packet[length++]=(unsigned char) (datum & 0xff); \
559 (void) WriteBlobByte(image,(unsigned char) length); \
560 (void) WriteBlob(image,length,packet); \
566 if (free_code > max_code) \
569 if (number_bits == MaxGIFBits) \
570 max_code=MaxGIFTable; \
572 max_code=MaxCode(number_bits); \
591 end_of_information_code,
611 Allocate encoder tables.
613 assert(image != (Image *) NULL);
615 packet=(unsigned char *) AcquireQuantumMemory(256,sizeof(*packet));
616 hash_code=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_code));
617 hash_prefix=(short *) AcquireQuantumMemory(MaxHashTable,sizeof(*hash_prefix));
618 hash_suffix=(unsigned char *) AcquireQuantumMemory(MaxHashTable,
619 sizeof(*hash_suffix));
620 if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
621 (hash_prefix == (short *) NULL) ||
622 (hash_suffix == (unsigned char *) NULL))
624 if (packet != (unsigned char *) NULL)
625 packet=(unsigned char *) RelinquishMagickMemory(packet);
626 if (hash_code != (short *) NULL)
627 hash_code=(short *) RelinquishMagickMemory(hash_code);
628 if (hash_prefix != (short *) NULL)
629 hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
630 if (hash_suffix != (unsigned char *) NULL)
631 hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
635 Initialize GIF encoder.
637 number_bits=data_size;
638 max_code=MaxCode(number_bits);
639 clear_code=((short) one << (data_size-1));
640 end_of_information_code=clear_code+1;
641 free_code=clear_code+2;
645 for (i=0; i < MaxHashTable; i++)
647 GIFOutputCode(clear_code);
654 for (y=0; y < (ssize_t) image->rows; y++)
656 register const Quantum
662 p=GetVirtualPixels(image,0,offset,image->columns,1,&image->exception);
663 if (p == (const Quantum *) NULL)
667 waiting_code=(short) GetPixelIndex(image,p);
668 p+=GetPixelChannels(image);
670 for (x=(ssize_t) (y == 0 ? 1 : 0); x < (ssize_t) image->columns; x++)
675 index=(Quantum) ((size_t) GetPixelIndex(image,p) & 0xff);
676 p+=GetPixelChannels(image);
677 k=(ssize_t) (((size_t) index << (MaxGIFBits-8))+waiting_code);
678 if (k >= MaxHashTable)
680 next_pixel=MagickFalse;
682 if (hash_code[k] > 0)
684 if ((hash_prefix[k] == waiting_code) &&
685 (hash_suffix[k] == (unsigned char) index))
687 waiting_code=hash_code[k];
691 displacement=MaxHashTable-k;
697 if (hash_code[k] == 0)
699 if ((hash_prefix[k] == waiting_code) &&
700 (hash_suffix[k] == (unsigned char) index))
702 waiting_code=hash_code[k];
703 next_pixel=MagickTrue;
707 if (next_pixel == MagickTrue)
710 GIFOutputCode((size_t) waiting_code);
711 if (free_code < MaxGIFTable)
713 hash_code[k]=(short) free_code++;
714 hash_prefix[k]=waiting_code;
715 hash_suffix[k]=(unsigned char) index;
720 Fill the hash table with empty entries.
722 for (k=0; k < MaxHashTable; k++)
725 Reset compressor and issue a clear code.
727 free_code=clear_code+2;
728 GIFOutputCode(clear_code);
729 number_bits=data_size;
730 max_code=MaxCode(number_bits);
732 waiting_code=(short) index;
734 if (image_info->interlace == NoInterlace)
743 if (offset >= (ssize_t) image->rows)
753 if (offset >= (ssize_t) image->rows)
763 if (offset >= (ssize_t) image->rows)
778 Flush out the buffered code.
780 GIFOutputCode((size_t) waiting_code);
781 GIFOutputCode(end_of_information_code);
785 Add a character to current packet.
787 packet[length++]=(unsigned char) (datum & 0xff);
790 (void) WriteBlobByte(image,(unsigned char) length);
791 (void) WriteBlob(image,length,packet);
796 Flush accumulated data.
800 (void) WriteBlobByte(image,(unsigned char) length);
801 (void) WriteBlob(image,length,packet);
806 hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix);
807 hash_prefix=(short *) RelinquishMagickMemory(hash_prefix);
808 hash_code=(short *) RelinquishMagickMemory(hash_code);
809 packet=(unsigned char *) RelinquishMagickMemory(packet);
814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 % IsGIF() returns MagickTrue if the image format type, identified by the
825 % magick string, is GIF.
827 % The format of the IsGIF method is:
829 % MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
831 % A description of each parameter follows:
833 % o magick: compare image format pattern against these bytes.
835 % o length: Specifies the length of the magick string.
838 static MagickBooleanType IsGIF(const unsigned char *magick,const size_t length)
842 if (LocaleNCompare((char *) magick,"GIF8",4) == 0)
848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
852 + R e a d B l o b B l o c k %
856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 % ReadBlobBlock() reads data from the image file and returns it. The
859 % amount of data is determined by first reading a count byte. The number
860 % of bytes read is returned.
862 % The format of the ReadBlobBlock method is:
864 % size_t ReadBlobBlock(Image *image,unsigned char *data)
866 % A description of each parameter follows:
868 % o image: the image.
870 % o data: Specifies an area to place the information requested from
874 static ssize_t ReadBlobBlock(Image *image,unsigned char *data)
882 assert(image != (Image *) NULL);
883 assert(image->signature == MagickSignature);
884 assert(data != (unsigned char *) NULL);
885 count=ReadBlob(image,1,&block_count);
888 return(ReadBlob(image,(size_t) block_count,data));
892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
896 % R e a d G I F I m a g e %
900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 % ReadGIFImage() reads a Compuserve Graphics image file and returns it.
903 % It allocates the memory necessary for the new Image structure and returns a
904 % pointer to the new image.
906 % The format of the ReadGIFImage method is:
908 % Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
910 % A description of each parameter follows:
912 % o image_info: the image info.
914 % o exception: return any errors or warnings in this structure.
918 static inline size_t MagickMax(const size_t x,const size_t y)
925 static inline size_t MagickMin(const size_t x,const size_t y)
932 static MagickBooleanType PingGIFImage(Image *image)
939 assert(image != (Image *) NULL);
940 assert(image->signature == MagickSignature);
941 if (image->debug != MagickFalse)
942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
943 if (ReadBlob(image,1,&data_size) != 1)
944 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
945 if (data_size > MaximumLZWBits)
946 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
947 if (ReadBlob(image,1,&length) != 1)
948 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
951 if (ReadBlob(image,length,buffer) != (ssize_t) length)
952 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
953 if (ReadBlob(image,1,&length) != 1)
954 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename);
959 static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
961 #define BitSet(byte,bit) (((byte) & (bit)) == (bit))
962 #define LSBFirstOrder(x,y) (((y) << 8) | (x))
968 number_extensionss=0;
979 register unsigned char
999 header[MaxTextExtent],
1005 assert(image_info != (const ImageInfo *) NULL);
1006 assert(image_info->signature == MagickSignature);
1007 if (image_info->debug != MagickFalse)
1008 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1009 image_info->filename);
1010 assert(exception != (ExceptionInfo *) NULL);
1011 assert(exception->signature == MagickSignature);
1012 image=AcquireImage(image_info);
1013 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1014 if (status == MagickFalse)
1016 image=DestroyImageList(image);
1017 return((Image *) NULL);
1020 Determine if this a GIF file.
1022 count=ReadBlob(image,6,magick);
1023 if ((count != 6) || ((LocaleNCompare((char *) magick,"GIF87",5) != 0) &&
1024 (LocaleNCompare((char *) magick,"GIF89",5) != 0)))
1025 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1026 page.width=ReadBlobLSBShort(image);
1027 page.height=ReadBlobLSBShort(image);
1028 flag=(unsigned char) ReadBlobByte(image);
1029 background=(unsigned char) ReadBlobByte(image);
1030 c=(unsigned char) ReadBlobByte(image); /* reserved */
1032 global_colors=one << (((size_t) flag & 0x07)+1);
1033 global_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
1034 MagickMax(global_colors,256),3UL*sizeof(*global_colormap));
1035 if (global_colormap == (unsigned char *) NULL)
1036 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1037 if (BitSet((int) flag,0x80) != 0)
1038 count=ReadBlob(image,(size_t) (3*global_colors),global_colormap);
1046 count=ReadBlob(image,1,&c);
1049 if (c == (unsigned char) ';')
1050 break; /* terminator */
1051 if (c == (unsigned char) '!')
1054 GIF Extension block.
1057 count=ReadBlob(image,1,&c);
1060 global_colormap=(unsigned char *) RelinquishMagickMemory(
1062 ThrowReaderException(CorruptImageError,
1063 "UnableToReadExtensionBlock");
1070 Read graphics control extension.
1072 while (ReadBlobBlock(image,header) != 0) ;
1073 dispose=(size_t) (header[0] >> 2);
1074 delay=(size_t) ((header[2] << 8) | header[1]);
1075 if ((ssize_t) (header[0] & 0x01) == 0x01)
1076 opacity=(ssize_t) header[3];
1085 Read comment extension.
1087 comments=AcquireString((char *) NULL);
1090 count=(ssize_t) ReadBlobBlock(image,header);
1094 (void) ConcatenateString(&comments,(const char *) header);
1096 (void) SetImageProperty(image,"comment",comments);
1097 comments=DestroyString(comments);
1102 /* Read GIF application extension */
1108 Read Netscape Loop extension.
1111 if (ReadBlobBlock(image,header) != 0)
1112 loop=LocaleNCompare((char *) header,"NETSCAPE2.0",11) == 0 ?
1113 MagickTrue : MagickFalse;
1114 if (loop != MagickFalse)
1116 while (ReadBlobBlock(image,header) != 0)
1117 iterations=(size_t) ((header[2] << 8) | header[1]);
1123 name[MaxTextExtent];
1142 Store GIF application extension as a generic profile.
1144 i8bim=LocaleNCompare((char *) header,"MGK8BIM0000",11) == 0 ?
1145 MagickTrue : MagickFalse;
1146 icc=LocaleNCompare((char *) header,"ICCRGBG1012",11) == 0 ?
1147 MagickTrue : MagickFalse;
1148 iptc=LocaleNCompare((char *) header,"MGKIPTC0000",11) == 0 ?
1149 MagickTrue : MagickFalse;
1150 number_extensionss++;
1151 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1152 " Reading GIF application extension");
1153 info=(unsigned char *) AcquireQuantumMemory(255UL,
1155 reserved_length=255;
1156 for (info_length=0; ; )
1158 block_length=(int) ReadBlobBlock(image,&info[info_length]);
1159 if (block_length == 0)
1161 info_length+=block_length;
1162 if (info_length > (reserved_length-255))
1164 reserved_length+=4096;
1165 info=(unsigned char *) ResizeQuantumMemory(info,
1166 (size_t) reserved_length,sizeof(*info));
1169 info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
1170 (info_length+1),sizeof(*info));
1171 profile=AcquireStringInfo((size_t) info_length);
1172 SetStringInfoDatum(profile,(const unsigned char *) info);
1173 if (i8bim == MagickTrue)
1174 (void) CopyMagickString(name,"8bim",sizeof(name));
1175 else if (icc == MagickTrue)
1176 (void) CopyMagickString(name,"icc",sizeof(name));
1177 else if (iptc == MagickTrue)
1178 (void) CopyMagickString(name,"iptc",sizeof(name));
1180 (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
1182 (void) SetImageProfile(image,name,profile);
1183 info=(unsigned char *) RelinquishMagickMemory(info);
1184 profile=DestroyStringInfo(profile);
1185 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1186 " profile name=%s",name);
1192 while (ReadBlobBlock(image,header) != 0) ;
1197 if (c != (unsigned char) ',')
1199 if (image_count != 0)
1202 Allocate next image structure.
1204 AcquireNextImage(image_info,image);
1205 if (GetNextImageInList(image) == (Image *) NULL)
1207 image=DestroyImageList(image);
1208 global_colormap=(unsigned char *) RelinquishMagickMemory(
1210 return((Image *) NULL);
1212 image=SyncNextImageInList(image);
1216 Read image attributes.
1218 image->storage_class=PseudoClass;
1219 image->compression=LZWCompression;
1220 page.x=(ssize_t) ReadBlobLSBShort(image);
1221 page.y=(ssize_t) ReadBlobLSBShort(image);
1222 image->columns=ReadBlobLSBShort(image);
1223 image->rows=ReadBlobLSBShort(image);
1225 flag=(unsigned char) ReadBlobByte(image);
1226 image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace :
1228 image->colors=BitSet((int) flag,0x80) == 0 ? global_colors :
1229 one << ((size_t) (flag & 0x07)+1);
1230 if (opacity >= (ssize_t) image->colors)
1232 image->page.width=page.width;
1233 image->page.height=page.height;
1234 image->page.y=page.y;
1235 image->page.x=page.x;
1237 image->ticks_per_second=100;
1238 image->dispose=(DisposeType) dispose;
1239 image->iterations=iterations;
1240 image->matte=opacity >= 0 ? MagickTrue : MagickFalse;
1244 if ((image->columns == 0) || (image->rows == 0))
1246 global_colormap=(unsigned char *) RelinquishMagickMemory(
1248 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1251 Inititialize colormap.
1253 if (AcquireImageColormap(image,image->colors) == MagickFalse)
1255 global_colormap=(unsigned char *) RelinquishMagickMemory(
1257 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1259 if (BitSet((int) flag,0x80) == 0)
1262 Use global colormap.
1265 for (i=0; i < (ssize_t) image->colors; i++)
1267 image->colormap[i].red=ScaleCharToQuantum(*p++);
1268 image->colormap[i].green=ScaleCharToQuantum(*p++);
1269 image->colormap[i].blue=ScaleCharToQuantum(*p++);
1272 image->colormap[i].alpha=(Quantum) TransparentAlpha;
1273 image->transparent_color=image->colormap[opacity];
1276 image->background_color=image->colormap[MagickMin(background,
1285 Read local colormap.
1287 colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
1288 3*sizeof(*colormap));
1289 if (colormap == (unsigned char *) NULL)
1291 global_colormap=(unsigned char *) RelinquishMagickMemory(
1293 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1295 count=ReadBlob(image,(3*image->colors)*sizeof(*colormap),colormap);
1296 if (count != (ssize_t) (3*image->colors))
1298 global_colormap=(unsigned char *) RelinquishMagickMemory(
1300 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1301 ThrowReaderException(CorruptImageError,
1302 "InsufficientImageDataInFile");
1305 for (i=0; i < (ssize_t) image->colors; i++)
1307 image->colormap[i].red=ScaleCharToQuantum(*p++);
1308 image->colormap[i].green=ScaleCharToQuantum(*p++);
1309 image->colormap[i].blue=ScaleCharToQuantum(*p++);
1311 image->colormap[i].alpha=(Quantum) TransparentAlpha;
1313 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1315 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
1316 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1321 if (image_info->ping != MagickFalse)
1322 status=PingGIFImage(image);
1324 status=DecodeImage(image,opacity);
1325 if ((image_info->ping == MagickFalse) && (status == MagickFalse))
1327 global_colormap=(unsigned char *) RelinquishMagickMemory(
1329 ThrowReaderException(CorruptImageError,"CorruptImage");
1331 if (image_info->number_scenes != 0)
1332 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1335 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) image->scene-
1337 if (status == MagickFalse)
1340 global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1341 if ((image->columns == 0) || (image->rows == 0))
1342 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");
1343 (void) CloseBlob(image);
1344 return(GetFirstImageInList(image));
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1352 % R e g i s t e r G I F I m a g e %
1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358 % RegisterGIFImage() adds properties for the GIF image format to
1359 % the list of supported formats. The properties include the image format
1360 % tag, a method to read and/or write the format, whether the format
1361 % supports the saving of more than one frame to the same file or blob,
1362 % whether the format supports native in-memory I/O, and a brief
1363 % description of the format.
1365 % The format of the RegisterGIFImage method is:
1367 % size_t RegisterGIFImage(void)
1370 ModuleExport size_t RegisterGIFImage(void)
1375 entry=SetMagickInfo("GIF");
1376 entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1377 entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1378 entry->magick=(IsImageFormatHandler *) IsGIF;
1379 entry->description=ConstantString("CompuServe graphics interchange format");
1380 entry->module=ConstantString("GIF");
1381 (void) RegisterMagickInfo(entry);
1382 entry=SetMagickInfo("GIF87");
1383 entry->decoder=(DecodeImageHandler *) ReadGIFImage;
1384 entry->encoder=(EncodeImageHandler *) WriteGIFImage;
1385 entry->magick=(IsImageFormatHandler *) IsGIF;
1386 entry->adjoin=MagickFalse;
1387 entry->description=ConstantString("CompuServe graphics interchange format");
1388 entry->version=ConstantString("version 87a");
1389 entry->module=ConstantString("GIF");
1390 (void) RegisterMagickInfo(entry);
1391 return(MagickImageCoderSignature);
1395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1399 % U n r e g i s t e r G I F I m a g e %
1403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1405 % UnregisterGIFImage() removes format registrations made by the
1406 % GIF module from the list of supported formats.
1408 % The format of the UnregisterGIFImage method is:
1410 % UnregisterGIFImage(void)
1413 ModuleExport void UnregisterGIFImage(void)
1415 (void) UnregisterMagickInfo("GIF");
1416 (void) UnregisterMagickInfo("GIF87");
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424 % W r i t e G I F I m a g e %
1428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1430 % WriteGIFImage() writes an image to a file in the Compuserve Graphics
1433 % The format of the WriteGIFImage method is:
1435 % MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image)
1437 % A description of each parameter follows.
1439 % o image_info: the image info.
1441 % o image: The image.
1444 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image)
1470 register unsigned char
1488 Open output image file.
1490 assert(image_info != (const ImageInfo *) NULL);
1491 assert(image_info->signature == MagickSignature);
1492 assert(image != (Image *) NULL);
1493 assert(image->signature == MagickSignature);
1494 if (image->debug != MagickFalse)
1495 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1496 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1497 if (status == MagickFalse)
1502 global_colormap=(unsigned char *) AcquireQuantumMemory(768UL,
1503 sizeof(*global_colormap));
1504 colormap=(unsigned char *) AcquireQuantumMemory(768UL,sizeof(*colormap));
1505 if ((global_colormap == (unsigned char *) NULL) ||
1506 (colormap == (unsigned char *) NULL))
1507 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1508 for (i=0; i < 768; i++)
1509 colormap[i]=(unsigned char) 0;
1513 write_info=CloneImageInfo(image_info);
1514 if (LocaleCompare(write_info->magick,"GIF87") != 0)
1515 (void) WriteBlob(image,6,(unsigned char *) "GIF89a");
1518 (void) WriteBlob(image,6,(unsigned char *) "GIF87a");
1519 write_info->adjoin=MagickFalse;
1522 Determine image bounding box.
1524 page.width=image->columns;
1525 page.height=image->rows;
1528 if (write_info->adjoin != MagickFalse)
1529 for (next_image=image; next_image != (Image *) NULL; )
1531 page.x=next_image->page.x;
1532 page.y=next_image->page.y;
1533 if ((next_image->page.width+page.x) > page.width)
1534 page.width=next_image->page.width+page.x;
1535 if ((next_image->page.height+page.y) > page.height)
1536 page.height=next_image->page.height+page.y;
1537 next_image=GetNextImageInList(next_image);
1539 page.x=image->page.x;
1540 page.y=image->page.y;
1541 if ((image->page.width != 0) && (image->page.height != 0))
1543 (void) WriteBlobLSBShort(image,(unsigned short) page.width);
1544 (void) WriteBlobLSBShort(image,(unsigned short) page.height);
1546 Write images to file.
1548 interlace=write_info->interlace;
1549 if ((write_info->adjoin != MagickFalse) &&
1550 (GetNextImageInList(image) != (Image *) NULL))
1551 interlace=NoInterlace;
1556 if (image->colorspace != RGBColorspace)
1557 (void) TransformImageColorspace(image,RGBColorspace);
1559 if (IsImageOpaque(image,&image->exception) != MagickFalse)
1561 if ((image->storage_class == DirectClass) || (image->colors > 256))
1562 (void) SetImageType(image,PaletteType);
1571 Identify transparent colormap index.
1573 if ((image->storage_class == DirectClass) || (image->colors > 256))
1574 (void) SetImageType(image,PaletteBilevelMatteType);
1575 for (i=0; i < (ssize_t) image->colors; i++)
1576 if (image->colormap[i].alpha != OpaqueAlpha)
1583 alpha=(MagickRealType) TransparentAlpha-(MagickRealType)
1584 image->colormap[i].alpha;
1585 beta=(MagickRealType) TransparentAlpha-(MagickRealType)
1586 image->colormap[opacity].alpha;
1592 (void) SetImageType(image,PaletteBilevelMatteType);
1593 for (i=0; i < (ssize_t) image->colors; i++)
1594 if (image->colormap[i].alpha != OpaqueAlpha)
1601 alpha=(Quantum) TransparentAlpha-(MagickRealType)
1602 image->colormap[i].alpha;
1603 beta=(Quantum) TransparentAlpha-(MagickRealType)
1604 image->colormap[opacity].alpha;
1611 image->colormap[opacity].red=image->transparent_color.red;
1612 image->colormap[opacity].green=image->transparent_color.green;
1613 image->colormap[opacity].blue=image->transparent_color.blue;
1616 if ((image->storage_class == DirectClass) || (image->colors > 256))
1617 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1618 for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
1619 if ((one << bits_per_pixel) >= image->colors)
1622 for (i=0; i < (ssize_t) image->colors; i++)
1624 *q++=ScaleQuantumToChar(image->colormap[i].red);
1625 *q++=ScaleQuantumToChar(image->colormap[i].green);
1626 *q++=ScaleQuantumToChar(image->colormap[i].blue);
1628 for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
1630 *q++=(unsigned char) 0x0;
1631 *q++=(unsigned char) 0x0;
1632 *q++=(unsigned char) 0x0;
1634 if ((GetPreviousImageInList(image) == (Image *) NULL) ||
1635 (write_info->adjoin == MagickFalse))
1638 Write global colormap.
1641 c|=(8-1) << 4; /* color resolution */
1642 c|=(bits_per_pixel-1); /* size of global colormap */
1643 (void) WriteBlobByte(image,(unsigned char) c);
1644 for (j=0; j < (ssize_t) image->colors; j++)
1645 if (IsPixelPacketEquivalent(&image->background_color,image->colormap+j))
1647 (void) WriteBlobByte(image,(unsigned char)
1648 (j == (ssize_t) image->colors ? 0 : j)); /* background color */
1649 (void) WriteBlobByte(image,(unsigned char) 0x00); /* reserved */
1650 length=(size_t) (3*(one << bits_per_pixel));
1651 (void) WriteBlob(image,length,colormap);
1652 for (j=0; j < 768; j++)
1653 global_colormap[j]=colormap[j];
1655 if (LocaleCompare(write_info->magick,"GIF87") != 0)
1658 Write graphics control extension.
1660 (void) WriteBlobByte(image,(unsigned char) 0x21);
1661 (void) WriteBlobByte(image,(unsigned char) 0xf9);
1662 (void) WriteBlobByte(image,(unsigned char) 0x04);
1663 c=image->dispose << 2;
1666 (void) WriteBlobByte(image,(unsigned char) c);
1667 delay=(size_t) (100*image->delay/MagickMax((size_t)
1668 image->ticks_per_second,1));
1669 (void) WriteBlobLSBShort(image,(unsigned short) delay);
1670 (void) WriteBlobByte(image,(unsigned char) (opacity >= 0 ? opacity :
1672 (void) WriteBlobByte(image,(unsigned char) 0x00);
1673 if ((LocaleCompare(write_info->magick,"GIF87") != 0) &&
1674 (GetImageProperty(image,"comment") != (const char *) NULL))
1686 Write Comment extension.
1688 (void) WriteBlobByte(image,(unsigned char) 0x21);
1689 (void) WriteBlobByte(image,(unsigned char) 0xfe);
1690 value=GetImageProperty(image,"comment");
1692 while (strlen(p) != 0)
1694 count=MagickMin(strlen(p),255);
1695 (void) WriteBlobByte(image,(unsigned char) count);
1696 for (i=0; i < (ssize_t) count; i++)
1697 (void) WriteBlobByte(image,(unsigned char) *p++);
1699 (void) WriteBlobByte(image,(unsigned char) 0x00);
1701 if ((GetPreviousImageInList(image) == (Image *) NULL) &&
1702 (GetNextImageInList(image) != (Image *) NULL) &&
1703 (image->iterations != 1))
1706 Write Netscape Loop extension.
1708 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1709 " Writing GIF Extension %s","NETSCAPE2.0");
1710 (void) WriteBlobByte(image,(unsigned char) 0x21);
1711 (void) WriteBlobByte(image,(unsigned char) 0xff);
1712 (void) WriteBlobByte(image,(unsigned char) 0x0b);
1713 (void) WriteBlob(image,11,(unsigned char *) "NETSCAPE2.0");
1714 (void) WriteBlobByte(image,(unsigned char) 0x03);
1715 (void) WriteBlobByte(image,(unsigned char) 0x01);
1716 (void) WriteBlobLSBShort(image,(unsigned short) image->iterations);
1717 (void) WriteBlobByte(image,(unsigned char) 0x00);
1719 ResetImageProfileIterator(image);
1728 name=GetNextImageProfile(image);
1729 if (name == (const char *) NULL)
1731 profile=GetImageProfile(image,name);
1732 if (profile != (StringInfo *) NULL)
1734 if ((LocaleCompare(name,"ICC") == 0) ||
1735 (LocaleCompare(name,"ICM") == 0) ||
1736 (LocaleCompare(name,"IPTC") == 0) ||
1737 (LocaleCompare(name,"8BIM") == 0) ||
1738 (LocaleNCompare(name,"gif:",4) == 0))
1749 datum=GetStringInfoDatum(profile);
1750 length=GetStringInfoLength(profile);
1751 (void) WriteBlobByte(image,(unsigned char) 0x21);
1752 (void) WriteBlobByte(image,(unsigned char) 0xff);
1753 (void) WriteBlobByte(image,(unsigned char) 0x0b);
1754 if ((LocaleCompare(name,"ICC") == 0) ||
1755 (LocaleCompare(name,"ICM") == 0))
1758 Write ICC extension.
1760 (void) WriteBlob(image,11,(unsigned char *)"ICCRGBG1012");
1761 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1762 " Writing GIF Extension %s","ICCRGBG1012");
1765 if ((LocaleCompare(name,"IPTC") == 0))
1768 write IPTC extension.
1770 (void) WriteBlob(image,11,(unsigned char *)"MGKIPTC0000");
1771 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1772 " Writing GIF Extension %s","MGKIPTC0000");
1775 if ((LocaleCompare(name,"8BIM") == 0))
1778 Write 8BIM extension>
1780 (void) WriteBlob(image,11,(unsigned char *)
1782 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1783 " Writing GIF Extension %s","MGK8BIM0000");
1788 extension[MaxTextExtent];
1790 /* write generic extension */
1791 (void) CopyMagickString(extension,name+4,
1793 (void) WriteBlob(image,11,(unsigned char *) extension);
1794 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1795 " Writing GIF Extension %s",name);
1798 while ((ssize_t) length > offset)
1803 if ((length-offset) < 255)
1804 block_length=length-offset;
1807 (void) WriteBlobByte(image,(unsigned char) block_length);
1808 (void) WriteBlob(image,(size_t) block_length,datum+offset);
1809 offset+=(ssize_t) block_length;
1811 (void) WriteBlobByte(image,(unsigned char) 0x00);
1816 (void) WriteBlobByte(image,','); /* image separator */
1818 Write the image header.
1820 page.x=image->page.x;
1821 page.y=image->page.y;
1822 if ((image->page.width != 0) && (image->page.height != 0))
1824 (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x));
1825 (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y));
1826 (void) WriteBlobLSBShort(image,(unsigned short) image->columns);
1827 (void) WriteBlobLSBShort(image,(unsigned short) image->rows);
1829 if (interlace != NoInterlace)
1830 c|=0x40; /* pixel data is interlaced */
1831 for (j=0; j < (ssize_t) (3*image->colors); j++)
1832 if (colormap[j] != global_colormap[j])
1834 if (j == (ssize_t) (3*image->colors))
1835 (void) WriteBlobByte(image,(unsigned char) c);
1839 c|=(bits_per_pixel-1); /* size of local colormap */
1840 (void) WriteBlobByte(image,(unsigned char) c);
1841 length=(size_t) (3*(one << bits_per_pixel));
1842 (void) WriteBlob(image,length,colormap);
1845 Write the image data.
1847 c=(int) MagickMax(bits_per_pixel,2);
1848 (void) WriteBlobByte(image,(unsigned char) c);
1849 status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1);
1850 if (status == MagickFalse)
1852 global_colormap=(unsigned char *) RelinquishMagickMemory(
1854 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1855 write_info=DestroyImageInfo(write_info);
1856 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1858 (void) WriteBlobByte(image,(unsigned char) 0x00);
1859 if (GetNextImageInList(image) == (Image *) NULL)
1861 image=SyncNextImageInList(image);
1863 status=SetImageProgress(image,SaveImagesTag,scene,
1864 GetImageListLength(image));
1865 if (status == MagickFalse)
1867 } while (write_info->adjoin != MagickFalse);
1868 (void) WriteBlobByte(image,';'); /* terminator */
1869 global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap);
1870 colormap=(unsigned char *) RelinquishMagickMemory(colormap);
1871 write_info=DestroyImageInfo(write_info);
1872 (void) CloseBlob(image);