2
% Copyright (C) 2003 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21
% Read/Write Compuserv Graphics Interchange Format. %
30
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38
#include "magick/studio.h"
39
#include "magick/attribute.h"
40
#include "magick/blob.h"
41
#include "magick/cache.h"
42
#include "magick/color.h"
43
#include "magick/magick.h"
44
#include "magick/monitor.h"
45
#include "magick/quantize.h"
46
#include "magick/utility.h"
52
ReadBlobBlock(Image *,unsigned char *);
55
WriteGIFImage(const ImageInfo *,Image *);
58
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
62
% D e c o d e I m a g e %
66
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
68
% Method DecodeImage uncompresses an image via GIF-coding.
70
% The format of the DecodeImage method is:
72
% MagickPassFail DecodeImage(Image *image,const long opacity)
74
% A description of each parameter follows:
76
% o status: Method DecodeImage returns MagickPass if all the pixels are
77
% uncompressed without error, otherwise MagickFail.
79
% o image: The address of a structure of type Image.
81
% o opacity: The colormap index associated with the transparent
86
#define MaxStackSize 4096
88
static MagickPassFail DecodeImage(Image *image,const long opacity)
115
register unsigned char
118
register unsigned long
139
assert(image != (Image *) NULL);
141
data_size=ReadBlobByte(image);
143
ThrowBinaryException(CorruptImageError,CorruptImage,image->filename);
145
Allocate decoder tables.
147
packet=MagickAllocateMemory(unsigned char *,256);
148
prefix=MagickAllocateMemory(short *,MaxStackSize*sizeof(short));
149
suffix=MagickAllocateMemory(unsigned char *,MaxStackSize);
150
pixel_stack=MagickAllocateMemory(unsigned char *,MaxStackSize+1);
151
if ((packet == (unsigned char *) NULL) ||
152
(prefix == (short *) NULL) ||
153
(suffix == (unsigned char *) NULL) ||
154
(pixel_stack == (unsigned char *) NULL))
156
MagickFreeMemory(pixel_stack);
157
MagickFreeMemory(suffix);
158
MagickFreeMemory(prefix);
159
MagickFreeMemory(packet);
160
ThrowBinaryException(ResourceLimitError,MemoryAllocationFailed,
164
Initialize GIF data stream decoder.
166
clear=1 << data_size;
167
end_of_information=clear+1;
170
code_size=data_size+1;
171
code_mask=(1 << code_size)-1;
172
for (code=0; code < clear; code++)
175
suffix[code]=(unsigned char) code;
178
Decode GIF pixel stream.
187
top_stack=pixel_stack;
188
for (y=0; y < (long) image->rows; y++)
190
q=SetImagePixels(image,0,offset,image->columns,1);
191
if (q == (PixelPacket *) NULL)
196
indexes=GetIndexes(image);
197
for (x=0; x < (long) image->columns; )
199
if (top_stack == pixel_stack)
201
if (bits < code_size)
204
Load bytes until there is enough bits for a code.
209
Read a new data block.
211
count=ReadBlobBlock(image,packet);
216
datum+=(unsigned long) (*c) << bits;
225
code=(long) (datum & code_mask);
231
if (code > available)
236
if (code == end_of_information)
243
code_size=data_size+1;
244
code_mask=(1 << code_size)-1;
249
if (old_code == NullCode)
251
*top_stack++=suffix[code];
253
first=(unsigned char) code;
257
if (code >= available)
262
while (code >= clear)
264
if ((top_stack-pixel_stack) >= MaxStackSize)
269
*top_stack++=suffix[code];
272
if (status == MagickFail)
276
Add a new string to the string table,
278
if (available >= MaxStackSize)
284
prefix[available]=(short) old_code;
285
suffix[available]=first;
287
if (((available & code_mask) == 0) && (available < MaxStackSize))
290
code_mask+=available;
295
Pop a pixel off the pixel stack.
299
VerifyColormapIndex(image,index);
301
*q=image->colormap[index];
303
(index == opacity ? TransparentOpacity : OpaqueOpacity);
307
if (image->interlace == NoInterlace)
316
if (offset >= (long) image->rows)
326
if (offset >= (long) image->rows)
336
if (offset >= (long) image->rows)
349
if (!SyncImagePixels(image))
354
if (x < (long) image->columns)
359
if (image->previous == (Image *) NULL)
360
if (QuantumTick(y,image->rows))
361
if (!MagickMonitor(LoadImageText,y,image->rows,&image->exception))
367
MagickFreeMemory(pixel_stack);
368
MagickFreeMemory(suffix);
369
MagickFreeMemory(prefix);
370
MagickFreeMemory(packet);
371
if ((status == MagickFail) || (y < (long) image->rows))
372
ThrowBinaryException(CorruptImageError,CorruptImage,image->filename);
377
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381
% E n c o d e I m a g e %
385
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387
% Method EncodeImage compresses an image via GIF-coding.
389
% The format of the EncodeImage method is:
391
% MagickPassFail EncodeImage(const ImageInfo *image_info,Image *image,
392
% const unsigned int data_size)
394
% A description of each parameter follows:
396
% o status: Method EncodeImage returns MagickPass if all the pixels are
397
% compressed without error, otherwise MagickFail.
399
% o image_info: Specifies a pointer to a ImageInfo structure.
401
% o image: The address of a structure of type Image.
403
% o data_size: The number of bits in the compressed packet.
407
#define MaxCode(number_bits) ((1 << (number_bits))-1)
408
#define MaxHashTable 5003
409
#define MaxGIFBits 12
411
# define MaxGIFTable (1 << MaxGIFBits)
413
# define MaxGIFTable max_code
415
#define GIFOutputCode(code) \
421
datum|=((long) code << bits); \
428
Add a character to current packet. \
430
packet[byte_count++]=(unsigned char) (datum & 0xff); \
431
if (byte_count >= 254) \
433
(void) WriteBlobByte(image,byte_count); \
434
(void) WriteBlob(image,byte_count,(char *) packet); \
440
if (free_code > max_code) \
443
if (number_bits == MaxGIFBits) \
444
max_code=MaxGIFTable; \
446
max_code=MaxCode(number_bits); \
449
static MagickPassFail EncodeImage(const ImageInfo *image_info,Image *image,
450
const unsigned int data_size)
469
register const PixelPacket
481
end_of_information_code,
494
Allocate encoder tables.
496
assert(image != (Image *) NULL);
497
packet=MagickAllocateMemory(unsigned char *,256);
498
hash_code=MagickAllocateMemory(short *,MaxHashTable*sizeof(short));
499
hash_prefix=MagickAllocateMemory(short *,MaxHashTable*sizeof(short));
500
hash_suffix=MagickAllocateMemory(unsigned char *,MaxHashTable);
501
if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) ||
502
(hash_prefix == (short *) NULL) ||
503
(hash_suffix == (unsigned char *) NULL))
505
MagickFreeMemory(packet);
506
MagickFreeMemory(hash_code);
507
MagickFreeMemory(hash_prefix);
508
MagickFreeMemory(hash_suffix);
512
Initialize GIF encoder.
514
number_bits=data_size;
515
max_code=MaxCode(number_bits);
516
clear_code=((short) 1 << (data_size-1));
517
end_of_information_code=clear_code+1;
518
free_code=clear_code+2;
522
for (i=0; i < MaxHashTable; i++)
524
GIFOutputCode(clear_code);
531
for (y=0; y < (long) image->rows; y++)
533
p=AcquireImagePixels(image,0,offset,image->columns,1,&image->exception);
534
if (p == (const PixelPacket *) NULL)
536
indexes=GetIndexes(image);
538
waiting_code=(*indexes);
539
for (x=(y == 0) ? 1 : 0; x < (long) image->columns; x++)
544
index=indexes[x] & 0xff;
546
k=(int) ((int) index << (MaxGIFBits-8))+waiting_code;
547
if (k >= MaxHashTable)
552
if ((image_info->compression != NoCompression) && (hash_code[k] > 0))
554
if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index))
556
waiting_code=hash_code[k];
560
displacement=MaxHashTable-k;
566
if (hash_code[k] == 0)
568
if ((hash_prefix[k] == waiting_code) && (hash_suffix[k] == index))
570
waiting_code=hash_code[k];
575
if (next_pixel == True)
579
GIFOutputCode(waiting_code);
580
if (free_code < MaxGIFTable)
582
hash_code[k]=free_code++;
583
hash_prefix[k]=waiting_code;
584
hash_suffix[k]=(unsigned char) index;
589
Fill the hash table with empty entries.
591
for (k=0; k < MaxHashTable; k++)
594
Reset compressor and issue a clear code.
596
free_code=clear_code+2;
597
GIFOutputCode(clear_code);
598
number_bits=data_size;
599
max_code=MaxCode(number_bits);
603
if (image_info->interlace == NoInterlace)
612
if (offset >= (long) image->rows)
622
if (offset >= (long) image->rows)
632
if (offset >= (long) image->rows)
645
if (image->previous == (Image *) NULL)
646
if (QuantumTick(y,image->rows))
647
if (!MagickMonitor(SaveImageText,y,image->rows,&image->exception))
651
Flush out the buffered code.
653
GIFOutputCode(waiting_code);
654
GIFOutputCode(end_of_information_code);
658
Add a character to current packet.
660
packet[byte_count++]=(unsigned char) (datum & 0xff);
661
if (byte_count >= 254)
663
(void) WriteBlobByte(image,byte_count);
664
(void) WriteBlob(image,byte_count,(char *) packet);
669
Flush accumulated data.
673
(void) WriteBlobByte(image,byte_count);
674
(void) WriteBlob(image,byte_count,(char *) packet);
679
MagickFreeMemory(hash_suffix);
680
MagickFreeMemory(hash_prefix);
681
MagickFreeMemory(hash_code);
682
MagickFreeMemory(packet);
687
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
695
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
697
% Method IsGIF returns MagickTrue if the image format type, identified by
698
% the magick string, is GIF.
700
% The format of the IsGIF method is:
702
% MagickBool IsGIF(const unsigned char *magick,const size_t length)
704
% A description of each parameter follows:
706
% o status: Method IsGIF returns True if the image format type is GIF.
708
% o magick: This string is generally the first few bytes of an image file
711
% o length: Specifies the length of the magick string.
715
static MagickBool IsGIF(const unsigned char *magick,const size_t length)
719
if (LocaleNCompare((char *) magick,"GIF8",4) == 0)
725
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
729
+ R e a d B l o b B l o c k %
733
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735
% Method ReadBlobBlock reads data from the image file and returns it. The
736
% amount of data is determined by first reading a count byte. The number
737
% or bytes read is returned.
739
% The format of the ReadBlobBlock method is:
741
% size_t ReadBlobBlock(Image *image,unsigned char *data)
743
% A description of each parameter follows:
745
% o count: Method ReadBlobBlock returns the number of bytes read.
747
% o image: The image.
749
% o data: Specifies an area to place the information requested from
754
static size_t ReadBlobBlock(Image *image,unsigned char *data)
762
assert(image != (Image *) NULL);
763
assert(image->signature == MagickSignature);
764
assert(data != (unsigned char *) NULL);
765
count=ReadBlob(image,1,&block_count);
768
return(ReadBlob(image,(size_t) block_count,data));
772
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776
% R e a d G I F I m a g e %
780
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
782
% Method ReadGIFImage reads a Compuserve Graphics image file and returns it.
783
% It allocates the memory necessary for the new Image structure and returns a
784
% pointer to the new image.
786
% The format of the ReadGIFImage method is:
788
% Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
790
% A description of each parameter follows:
792
% o image: Method ReadGIFImage returns a pointer to the image after
793
% reading. A null image is returned if there is a memory shortage or
796
% o image_info: Specifies a pointer to a ImageInfo structure.
798
% o exception: return any errors or warnings in this structure.
802
#define BitSet(byte,bit) (((byte) & (bit)) == (bit))
803
#define LSBFirstOrder(x,y) (((y) << 8) | (x))
804
static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
821
register unsigned char
832
header[MaxTextExtent],
845
assert(image_info != (const ImageInfo *) NULL);
846
assert(image_info->signature == MagickSignature);
847
assert(exception != (ExceptionInfo *) NULL);
848
assert(exception->signature == MagickSignature);
849
image=AllocateImage(image_info);
850
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
851
if (status == MagickFail)
852
ThrowReaderException(FileOpenError,UnableToOpenFile,image);
854
Determine if this is a GIF file.
856
count=ReadBlob(image,6,(char *) magick);
857
if ((count == 0) || ((LocaleNCompare((char *) magick,"GIF87",5) != 0) &&
858
(LocaleNCompare((char *) magick,"GIF89",5) != 0)))
859
ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
861
global_colormap=(unsigned char *) NULL;
862
page.width=ReadBlobLSBShort(image);
863
page.height=ReadBlobLSBShort(image);
864
flag=ReadBlobByte(image);
865
background=ReadBlobByte(image);
866
c=ReadBlobByte(image); /* reserved */
867
global_colors=1 << ((flag & 0x07)+1);
868
global_colormap=MagickAllocateMemory(unsigned char *,3*Max(global_colors,256));
869
if (global_colormap == (unsigned char *) NULL)
870
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
871
if (BitSet(flag,0x80))
872
(void) ReadBlob(image,3*global_colors,(char *) global_colormap);
880
count=ReadBlob(image,1,(char *) &c);
884
break; /* terminator */
890
count=ReadBlob(image,1,(char *) &c);
892
MagickFreeMemory(global_colormap);
893
ThrowReaderException(CorruptImageError,UnableToReadExtensionBlock,
901
Read Graphics Control extension.
903
while (ReadBlobBlock(image,header) != 0);
904
dispose=header[0] >> 2;
905
delay=(header[2] << 8) | header[1];
906
if ((header[0] & 0x01) == 1)
916
Read Comment extension.
918
comments=AllocateString((char *) NULL);
921
count=ReadBlobBlock(image,header);
925
(void) ConcatenateString(&comments,(const char *) header);
927
(void) SetImageAttribute(image,"comment",comments);
928
MagickFreeMemory(comments);
937
Read Netscape Loop extension.
940
if (ReadBlobBlock(image,header) != 0)
941
loop=!LocaleNCompare((char *) header,"NETSCAPE2.0",11);
942
while (ReadBlobBlock(image,header) != 0)
944
iterations=(header[2] << 8) | header[1];
949
while (ReadBlobBlock(image,header) != 0);
956
if (image_count != 0)
959
Allocate next image structure.
961
AllocateNextImage(image_info,image);
962
if (image->next == (Image *) NULL)
964
DestroyImageList(image);
965
MagickFreeMemory(global_colormap);
966
return((Image *) NULL);
968
image=SyncNextImageInList(image);
969
if (!MagickMonitor(LoadImagesText,TellBlob(image),GetBlobSize(image),exception))
974
Read image attributes.
976
image->storage_class=PseudoClass;
977
image->compression=LZWCompression;
978
page.x=ReadBlobLSBShort(image);
979
page.y=ReadBlobLSBShort(image);
980
image->columns=ReadBlobLSBShort(image);
981
image->rows=ReadBlobLSBShort(image);
983
flag=ReadBlobByte(image);
984
image->interlace=BitSet(flag,0x40) ? PlaneInterlace : NoInterlace;
985
image->colors=!BitSet(flag,0x80) ? global_colors : 0x01U << ((flag & 0x07)+1);
986
if (opacity >= (long) image->colors)
987
image->colors=opacity+1;
988
image->page.width=page.width;
989
image->page.height=page.height;
990
image->page.y=page.y;
991
image->page.x=page.x;
993
image->dispose=(DisposeType) dispose;
994
image->iterations=iterations;
995
image->matte=opacity >= 0;
999
if ((image->columns == 0) || (image->rows == 0)) {
1000
MagickFreeMemory(global_colormap);
1001
ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
1004
Inititialize colormap.
1006
if (!AllocateImageColormap(image,image->colors)) {
1007
MagickFreeMemory(global_colormap);
1008
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1010
if (!BitSet(flag,0x80))
1013
Use global colormap.
1016
for (i=0; i < (long) image->colors; i++)
1018
image->colormap[i].red=ScaleCharToQuantum(*p++);
1019
image->colormap[i].green=ScaleCharToQuantum(*p++);
1020
image->colormap[i].blue=ScaleCharToQuantum(*p++);
1022
image->background_color=
1023
image->colormap[Min(background,image->colors-1)];
1031
Read local colormap.
1033
colormap=MagickAllocateMemory(unsigned char *,3*image->colors);
1034
if (colormap == (unsigned char *) NULL)
1036
MagickFreeMemory(global_colormap);
1037
ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
1040
(void) ReadBlob(image,3*image->colors,(char *) colormap);
1042
for (i=0; i < (long) image->colors; i++)
1044
image->colormap[i].red=ScaleCharToQuantum(*p++);
1045
image->colormap[i].green=ScaleCharToQuantum(*p++);
1046
image->colormap[i].blue=ScaleCharToQuantum(*p++);
1048
MagickFreeMemory(colormap);
1050
if (image_info->ping && (image_info->subrange != 0))
1051
if (image->scene >= (image_info->subimage+image_info->subrange-1))
1056
status=DecodeImage(image,opacity);
1057
if (!image_info->ping && (status == False)) {
1058
MagickFreeMemory(global_colormap);
1059
ThrowReaderException(CorruptImageError,CorruptImage,image);
1061
if (image_info->subrange != 0)
1062
if (image->scene >= (image_info->subimage+image_info->subrange-1))
1065
MagickFreeMemory(global_colormap);
1066
if ((image->columns == 0) || (image->rows == 0))
1067
ThrowReaderException(CorruptImageError,NegativeOrZeroImageSize,image);
1068
while (image->previous != (Image *) NULL)
1069
image=image->previous;
1075
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079
% R e g i s t e r G I F I m a g e %
1083
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1085
% Method RegisterGIFImage adds attributes for the GIF image format to
1086
% the list of supported formats. The attributes include the image format
1087
% tag, a method to read and/or write the format, whether the format
1088
% supports the saving of more than one frame to the same file or blob,
1089
% whether the format supports native in-memory I/O, and a brief
1090
% description of the format.
1092
% The format of the RegisterGIFImage method is:
1094
% RegisterGIFImage(void)
1097
ModuleExport void RegisterGIFImage(void)
1102
entry=SetMagickInfo("GIF");
1103
entry->decoder=(DecoderHandler) ReadGIFImage;
1104
entry->encoder=(EncoderHandler) WriteGIFImage;
1105
entry->magick=(MagickHandler) IsGIF;
1106
entry->description=AcquireString("CompuServe graphics interchange format");
1107
#if !defined(HasLZW)
1108
entry->version=AcquireString("LZW disabled");
1110
entry->module=AcquireString("GIF");
1111
(void) RegisterMagickInfo(entry);
1112
entry=SetMagickInfo("GIF87");
1113
entry->decoder=(DecoderHandler) ReadGIFImage;
1114
entry->encoder=(EncoderHandler) WriteGIFImage;
1115
entry->magick=(MagickHandler) IsGIF;
1116
entry->adjoin=False;
1117
entry->description=AcquireString("CompuServe graphics interchange format");
1118
entry->version=AcquireString("version 87a");
1119
entry->module=AcquireString("GIF");
1120
(void) RegisterMagickInfo(entry);
1124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128
% U n r e g i s t e r G I F I m a g e %
1132
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1134
% Method UnregisterGIFImage removes format registrations made by the
1135
% GIF module from the list of supported formats.
1137
% The format of the UnregisterGIFImage method is:
1139
% UnregisterGIFImage(void)
1142
ModuleExport void UnregisterGIFImage(void)
1144
(void) UnregisterMagickInfo("GIF");
1145
(void) UnregisterMagickInfo("GIF87");
1149
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1153
% W r i t e G I F I m a g e %
1157
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159
% Method WriteGIFImage writes an image to a file in the Compuserve Graphics
1162
% The format of the WriteGIFImage method is:
1164
% MagickPassFail WriteGIFImage(const ImageInfo *image_info,Image *image)
1166
% A description of each parameter follows.
1168
% o status: Method WriteGIFImage return MagickPass if the image is written.
1169
% MagickFail is returned is there is a memory shortage or if the image file
1172
% o image_info: Specifies a pointer to a ImageInfo structure.
1174
% o image: A pointer to an Image structure.
1178
static MagickPassFail WriteGIFImage(const ImageInfo *image_info,Image *image)
1195
register IndexPacket
1198
register const PixelPacket
1207
register unsigned char
1227
Open output image file.
1229
assert(image_info != (const ImageInfo *) NULL);
1230
assert(image_info->signature == MagickSignature);
1231
assert(image != (Image *) NULL);
1232
assert(image->signature == MagickSignature);
1233
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1234
if (status == MagickFail)
1235
ThrowWriterException(FileOpenError,UnableToOpenFile,image);
1237
Determine image bounding box.
1239
page.width=image->columns;
1240
page.height=image->rows;
1243
for (next_image=image; next_image != (Image *) NULL; )
1245
page.x=next_image->page.x;
1246
page.y=next_image->page.y;
1247
if ((next_image->columns+page.x) > page.width)
1248
page.width=next_image->columns+page.x;
1249
if ((next_image->rows+page.y) > page.height)
1250
page.height=next_image->rows+page.y;
1251
next_image=next_image->next;
1256
global_colormap=MagickAllocateMemory(unsigned char *,768);
1257
colormap=MagickAllocateMemory(unsigned char *,768);
1258
if ((global_colormap == (unsigned char *) NULL) ||
1259
(colormap == (unsigned char *) NULL))
1260
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
1261
for (i=0; i < 768; i++)
1266
if ((GetImageAttribute(image,"comment") == (ImageAttribute *) NULL) &&
1267
!image_info->adjoin && !image->matte)
1268
(void) WriteBlob(image,6,"GIF87a");
1270
if (LocaleCompare(image_info->magick,"GIF87") == 0)
1271
(void) WriteBlob(image,6,"GIF87a");
1273
(void) WriteBlob(image,6,"GIF89a");
1274
page.x=image->page.x;
1275
page.y=image->page.y;
1276
if ((image->page.width != 0) && (image->page.height != 0))
1278
(void) WriteBlobLSBShort(image,page.width);
1279
(void) WriteBlobLSBShort(image,page.height);
1281
Write images to file.
1283
interlace=image_info->interlace;
1284
if (image_info->adjoin && (image->next != (Image *) NULL))
1285
interlace=NoInterlace;
1290
(void) TransformColorspace(image,RGBColorspace);
1291
if ((image->storage_class == DirectClass) || (image->colors > 256))
1294
GIF requires that the image is colormapped.
1296
GetQuantizeInfo(&quantize_info);
1297
quantize_info.dither=image_info->dither;
1298
quantize_info.number_colors=image->matte ? 255 : 256;
1299
(void) QuantizeImage(&quantize_info,image);
1303
Set transparent pixel.
1305
opacity=(long) image->colors++;
1306
MagickReallocMemory(image->colormap,
1307
image->colors*sizeof(PixelPacket));
1308
if (image->colormap == (PixelPacket *) NULL)
1310
MagickFreeMemory(global_colormap);
1311
MagickFreeMemory(colormap);
1312
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image)
1314
image->colormap[opacity]=image->background_color;
1315
for (y=0; y < (long) image->rows; y++)
1317
p=AcquireImagePixels(image,0,y,image->columns,1,
1319
if (p == (const PixelPacket *) NULL)
1321
indexes=GetIndexes(image);
1322
for (x=0; x < (long) image->columns; x++)
1324
if (p->opacity == TransparentOpacity)
1325
indexes[x]=(IndexPacket) opacity;
1328
if (!SyncImagePixels(image))
1337
Identify transparent pixel index.
1339
for (y=0; y < (long) image->rows; y++)
1341
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1342
if (p == (const PixelPacket *) NULL)
1344
indexes=GetIndexes(image);
1345
for (x=0; x < (long) image->columns; x++)
1347
if (p->opacity == TransparentOpacity)
1349
opacity=(long) indexes[x];
1354
if (x < (long) image->columns)
1358
if (image->colormap == (PixelPacket *) NULL)
1360
for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++)
1361
if ((1UL << bits_per_pixel) >= image->colors)
1364
for (i=0; i < (long) image->colors; i++)
1366
*q++=ScaleQuantumToChar(image->colormap[i].red);
1367
*q++=ScaleQuantumToChar(image->colormap[i].green);
1368
*q++=ScaleQuantumToChar(image->colormap[i].blue);
1370
for ( ; i < (1L << bits_per_pixel); i++)
1376
if ((image->previous == (Image *) NULL) || !image_info->adjoin)
1379
Write global colormap.
1382
c|=(8-1) << 4; /* color resolution */
1383
c|=(bits_per_pixel-1); /* size of global colormap */
1384
(void) WriteBlobByte(image,c);
1385
for (p=image->colormap, j=0; j < Max(image->colors-1,1); j++, p++)
1386
if (ColorMatch(&image->background_color,p))
1388
(void) WriteBlobByte(image,(long) j); /* background color */
1389
(void) WriteBlobByte(image,0x0); /* reserved */
1390
(void) WriteBlob(image,3*(1 << bits_per_pixel),(char *) colormap);
1391
for (j=0; j < 768; j++)
1392
global_colormap[j]=colormap[j];
1394
if (LocaleCompare(image_info->magick,"GIF87") != 0)
1397
Write Graphics Control extension.
1399
(void) WriteBlobByte(image,0x21);
1400
(void) WriteBlobByte(image,0xf9);
1401
(void) WriteBlobByte(image,0x04);
1402
c=(unsigned char) ((int) image->dispose << 2);
1405
(void) WriteBlobByte(image,c);
1406
(void) WriteBlobLSBShort(image,image->delay);
1407
(void) WriteBlobByte(image,opacity >= 0 ? opacity : 0);
1408
(void) WriteBlobByte(image,0x00);
1409
if (GetImageAttribute(image,"comment") != (ImageAttribute *) NULL)
1411
const ImageAttribute
1421
Write Comment extension.
1423
(void) WriteBlobByte(image,0x21);
1424
(void) WriteBlobByte(image,0xfe);
1425
attribute=GetImageAttribute(image,"comment");
1427
while (strlen(p) != 0)
1429
count=Min(strlen(p),255);
1430
(void) WriteBlobByte(image,(long) count);
1431
for (i=0; i < (long) count; i++)
1432
(void) WriteBlobByte(image,*p++);
1434
(void) WriteBlobByte(image,0x0);
1436
if ((image->previous == (Image *) NULL) &&
1437
(image->next != (Image *) NULL) && (image->iterations != 1))
1440
Write Netscape Loop extension.
1442
(void) WriteBlobByte(image,0x21);
1443
(void) WriteBlobByte(image,0xff);
1444
(void) WriteBlobByte(image,0x0b);
1445
(void) WriteBlob(image,11,"NETSCAPE2.0");
1446
(void) WriteBlobByte(image,0x03);
1447
(void) WriteBlobByte(image,0x01);
1448
(void) WriteBlobLSBShort(image,image->iterations);
1449
(void) WriteBlobByte(image,0x00);
1452
(void) WriteBlobByte(image,','); /* image separator */
1454
Write the image header.
1456
page.x=image->page.x;
1457
page.y=image->page.y;
1458
if ((image->page.width != 0) && (image->page.height != 0))
1460
(void) WriteBlobLSBShort(image,page.x);
1461
(void) WriteBlobLSBShort(image,page.y);
1462
(void) WriteBlobLSBShort(image,image->columns);
1463
(void) WriteBlobLSBShort(image,image->rows);
1465
if (interlace != NoInterlace)
1466
c|=0x40; /* pixel data is interlaced */
1467
for (j=0; j < (3*image->colors); j++)
1468
if (colormap[j] != global_colormap[j])
1470
if (j == (3*image->colors))
1471
(void) WriteBlobByte(image,c);
1475
c|=(bits_per_pixel-1); /* size of local colormap */
1476
(void) WriteBlobByte(image,c);
1477
(void) WriteBlob(image,3*(1 << bits_per_pixel),(char *) colormap);
1480
Write the image data.
1482
c=Max(bits_per_pixel,2);
1483
(void) WriteBlobByte(image,c);
1484
status=EncodeImage(image_info,image,Max(bits_per_pixel,2)+1);
1485
if (status == MagickFail)
1487
MagickFreeMemory(global_colormap);
1488
MagickFreeMemory(colormap);
1489
ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image)
1491
(void) WriteBlobByte(image,0x0);
1492
if (image->next == (Image *) NULL)
1494
image=SyncNextImageInList(image);
1495
status=MagickMonitor(SaveImagesText,scene++,GetImageListLength(image),
1497
if (status == MagickFail)
1499
} while (image_info->adjoin);
1500
(void) WriteBlobByte(image,';'); /* terminator */
1501
MagickFreeMemory(global_colormap);
1502
MagickFreeMemory(colormap);
1503
if (image_info->adjoin)
1504
while (image->previous != (Image *) NULL)
1505
image=image->previous;