Powered by Pair ImageMagick logo
Image Magick
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Globals | Related Pages

ImageMagick-6.1.1/coders/gif.c

Go to the documentation of this file.
00001 /* 00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00003 % % 00004 % % 00005 % % 00006 % GGGG IIIII FFFFF % 00007 % G I F % 00008 % G GG I FFF % 00009 % G G I F % 00010 % GGG IIIII F % 00011 % % 00012 % % 00013 % Read/Write Compuserv Graphics Interchange Format. % 00014 % % 00015 % Software Design % 00016 % John Cristy % 00017 % July 1992 % 00018 % % 00019 % % 00020 % Copyright 1999-2004 ImageMagick Studio LLC, a non-profit organization % 00021 % dedicated to making software imaging solutions freely available. % 00022 % % 00023 % You may not use this file except in compliance with the License. You may % 00024 % obtain a copy of the License at % 00025 % % 00026 % http://www.imagemagick.org/www/Copyright.html % 00027 % % 00028 % Unless required by applicable law or agreed to in writing, software % 00029 % distributed under the License is distributed on an "AS IS" BASIS, % 00030 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 00031 % See the License for the specific language governing permissions and % 00032 % limitations under the License. % 00033 % % 00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00035 % 00036 % 00037 */ 00038 00039 /* 00040 Include declarations. 00041 */ 00042 #include "magick/studio.h" 00043 #include "magick/attribute.h" 00044 #include "magick/blob.h" 00045 #include "magick/blob_private.h" 00046 #include "magick/color.h" 00047 #include "magick/color_private.h" 00048 #include "magick/colorspace.h" 00049 #include "magick/error.h" 00050 #include "magick/error_private.h" 00051 #include "magick/image.h" 00052 #include "magick/image_private.h" 00053 #include "magick/list.h" 00054 #include "magick/magick.h" 00055 #include "magick/memory_.h" 00056 #include "magick/monitor.h" 00057 #include "magick/quantize.h" 00058 #include "magick/static.h" 00059 #include "magick/string_.h" 00060 00061 /* 00062 Forward declarations. 00063 */ 00064 static ssize_t 00065 ReadBlobBlock(Image *,unsigned char *); 00066 00067 static MagickBooleanType 00068 WriteGIFImage(const ImageInfo *,Image *); 00069 00070 /* 00071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00072 % % 00073 % % 00074 % % 00075 % D e c o d e I m a g e % 00076 % % 00077 % % 00078 % % 00079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00080 % 00081 % DecodeImage uncompresses an image via GIF-coding. 00082 % 00083 % The format of the DecodeImage method is: 00084 % 00085 % MagickBooleanType DecodeImage(Image *image,const long opacity) 00086 % 00087 % A description of each parameter follows: 00088 % 00089 % o image: The address of a structure of type Image. 00090 % 00091 % o opacity: The colormap index associated with the transparent 00092 % color. 00093 % 00094 % 00095 */ 00096 static MagickBooleanType DecodeImage(Image *image,const Quantum opacity) 00097 { 00098 #define MaxStackSize 4096 00099 #define NullCode (~0UL) 00100 00101 IndexPacket 00102 index; 00103 00104 long 00105 offset, 00106 y; 00107 00108 MagickBooleanType 00109 status; 00110 00111 register IndexPacket 00112 *indexes; 00113 00114 register long 00115 x; 00116 00117 register PixelPacket 00118 *q; 00119 00120 register unsigned char 00121 *c; 00122 00123 register unsigned long 00124 datum; 00125 00126 short 00127 *prefix; 00128 00129 ssize_t 00130 count; 00131 00132 unsigned char 00133 *packet, 00134 *pixel_stack, 00135 *suffix, 00136 *top_stack; 00137 00138 unsigned long 00139 available, 00140 bits, 00141 clear, 00142 code, 00143 code_mask, 00144 code_size, 00145 data_size, 00146 first, 00147 end_of_information, 00148 in_code, 00149 old_code, 00150 pass; 00151 00152 /* 00153 Allocate decoder tables. 00154 */ 00155 assert(image != (Image *) NULL); 00156 assert(image->signature == MagickSignature); 00157 if (image->debug != MagickFalse) 00158 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 00159 packet=(unsigned char *) AcquireMagickMemory(256); 00160 prefix=(short *) AcquireMagickMemory(MaxStackSize*sizeof(*prefix)); 00161 suffix=(unsigned char *) AcquireMagickMemory(MaxStackSize); 00162 pixel_stack=(unsigned char *) AcquireMagickMemory(MaxStackSize+1); 00163 if ((packet == (unsigned char *) NULL) || 00164 (prefix == (short *) NULL) || 00165 (suffix == (unsigned char *) NULL) || 00166 (pixel_stack == (unsigned char *) NULL)) 00167 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 00168 image->filename); 00169 /* 00170 Initialize GIF data stream decoder. 00171 */ 00172 data_size=(unsigned long) ReadBlobByte(image); 00173 if (data_size > 8) 00174 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename); 00175 clear=1UL << data_size; 00176 end_of_information=clear+1; 00177 available=clear+2; 00178 old_code=NullCode; 00179 code_size=data_size+1; 00180 code_mask=(1 << code_size)-1; 00181 for (code=0; code < clear; code++) 00182 { 00183 prefix[code]=0; 00184 suffix[code]=(unsigned char) code; 00185 } 00186 /* 00187 Decode GIF pixel stream. 00188 */ 00189 datum=0; 00190 bits=0; 00191 c=0; 00192 count=0; 00193 first=0; 00194 offset=0; 00195 pass=0; 00196 top_stack=pixel_stack; 00197 for (y=0; y < (long) image->rows; y++) 00198 { 00199 q=SetImagePixels(image,0,offset,image->columns,1); 00200 if (q == (PixelPacket *) NULL) 00201 break; 00202 indexes=GetIndexes(image); 00203 for (x=0; x < (long) image->columns; ) 00204 { 00205 if (top_stack == pixel_stack) 00206 { 00207 if (bits < code_size) 00208 { 00209 /* 00210 Load bytes until there is enough bits for a code. 00211 */ 00212 if (count == 0) 00213 { 00214 /* 00215 Read a new data block. 00216 */ 00217 count=ReadBlobBlock(image,packet); 00218 if (count == 0) 00219 break; 00220 c=packet; 00221 } 00222 datum+=(unsigned long) (*c) << bits; 00223 bits+=8; 00224 c++; 00225 count--; 00226 continue; 00227 } 00228 /* 00229 Get the next code. 00230 */ 00231 code=datum & code_mask; 00232 datum>>=code_size; 00233 bits-=code_size; 00234 /* 00235 Interpret the code 00236 */ 00237 if ((code > available) || (code == end_of_information)) 00238 break; 00239 if (code == clear) 00240 { 00241 /* 00242 Reset decoder. 00243 */ 00244 code_size=data_size+1; 00245 code_mask=(1 << code_size)-1; 00246 available=clear+2; 00247 old_code=NullCode; 00248 continue; 00249 } 00250 if (old_code == NullCode) 00251 { 00252 *top_stack++=suffix[code]; 00253 old_code=code; 00254 first=code; 00255 continue; 00256 } 00257 in_code=code; 00258 if (code >= available) 00259 { 00260 *top_stack++=(unsigned char) first; 00261 code=old_code; 00262 } 00263 while (code >= clear) 00264 { 00265 if ((top_stack-pixel_stack) >= MaxStackSize) 00266 break; 00267 *top_stack++=suffix[code]; 00268 code=(unsigned long) prefix[code]; 00269 } 00270 first=(unsigned long) suffix[code]; 00271 /* 00272 Add a new string to the string table, 00273 */ 00274 if ((top_stack-pixel_stack) >= MaxStackSize) 00275 break; 00276 if (available >= MaxStackSize) 00277 break; 00278 *top_stack++=(unsigned char) first; 00279 prefix[available]=(short) old_code; 00280 suffix[available]=(unsigned char) first; 00281 available++; 00282 if (((available & code_mask) == 0) && (available < MaxStackSize)) 00283 { 00284 code_size++; 00285 code_mask+=available; 00286 } 00287 old_code=in_code; 00288 } 00289 /* 00290 Pop a pixel off the pixel stack. 00291 */ 00292 top_stack--; 00293 index=ConstrainColormapIndex(image,*top_stack); 00294 indexes[x]=index; 00295 *q=image->colormap[index]; 00296 q->opacity=(Quantum) 00297 (index == opacity ? TransparentOpacity : OpaqueOpacity); 00298 x++; 00299 q++; 00300 } 00301 if (image->interlace == NoInterlace) 00302 offset++; 00303 else 00304 switch (pass) 00305 { 00306 case 0: 00307 default: 00308 { 00309 offset+=8; 00310 if (offset >= (long) image->rows) 00311 { 00312 pass++; 00313 offset=4; 00314 } 00315 break; 00316 } 00317 case 1: 00318 { 00319 offset+=8; 00320 if (offset >= (long) image->rows) 00321 { 00322 pass++; 00323 offset=2; 00324 } 00325 break; 00326 } 00327 case 2: 00328 { 00329 offset+=4; 00330 if (offset >= (long) image->rows) 00331 { 00332 pass++; 00333 offset=1; 00334 } 00335 break; 00336 } 00337 case 3: 00338 { 00339 offset+=2; 00340 break; 00341 } 00342 } 00343 if (SyncImagePixels(image) == MagickFalse) 00344 break; 00345 if (x < (long) image->columns) 00346 break; 00347 if (image->previous == (Image *) NULL) 00348 if ((image->progress_monitor != (MagickProgressMonitor) NULL) && 00349 (QuantumTick(y,image->rows) != MagickFalse)) 00350 { 00351 status=image->progress_monitor(LoadImageTag,y,image->rows, 00352 image->client_data); 00353 if (status == MagickFalse) 00354 break; 00355 } 00356 } 00357 pixel_stack=(unsigned char *) RelinquishMagickMemory(pixel_stack); 00358 suffix=(unsigned char *) RelinquishMagickMemory(suffix); 00359 prefix=(short *) RelinquishMagickMemory(prefix); 00360 packet=(unsigned char *) RelinquishMagickMemory(packet); 00361 if (y < (long) image->rows) 00362 ThrowBinaryException(CorruptImageError,"CorruptImage",image->filename); 00363 return(MagickTrue); 00364 } 00365 00366 /* 00367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00368 % % 00369 % % 00370 % % 00371 % E n c o d e I m a g e % 00372 % % 00373 % % 00374 % % 00375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00376 % 00377 % EncodeImage compresses an image via GIF-coding. 00378 % 00379 % The format of the EncodeImage method is: 00380 % 00381 % MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image, 00382 % const unsigned long data_size) 00383 % 00384 % A description of each parameter follows: 00385 % 00386 % o image_info: The image info. 00387 % 00388 % o image: The address of a structure of type Image. 00389 % 00390 % o data_size: The number of bits in the compressed packet. 00391 % 00392 % 00393 */ 00394 static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image, 00395 const unsigned long data_size) 00396 { 00397 #define MaxCode(number_bits) ((1UL << (number_bits))-1) 00398 #define MaxHashTable 5003 00399 #define MaxGIFBits 12UL 00400 #define MaxGIFTable (1UL << MaxGIFBits) 00401 #define GIFOutputCode(code) \ 00402 { \ 00403 /* \ 00404 Emit a code. \ 00405 */ \ 00406 if (bits > 0) \ 00407 datum|=(code) << bits; \ 00408 else \ 00409 datum=code; \ 00410 bits+=number_bits; \ 00411 while (bits >= 8) \ 00412 { \ 00413 /* \ 00414 Add a character to current packet. \ 00415 */ \ 00416 packet[length++]=(unsigned char) (datum & 0xff); \ 00417 if (length >= 254) \ 00418 { \ 00419 (void) WriteBlobByte(image,(unsigned char) length); \ 00420 (void) WriteBlob(image,length,packet); \ 00421 length=0; \ 00422 } \ 00423 datum>>=8; \ 00424 bits-=8; \ 00425 } \ 00426 if (free_code > max_code) \ 00427 { \ 00428 number_bits++; \ 00429 if (number_bits == MaxGIFBits) \ 00430 max_code=MaxGIFTable; \ 00431 else \ 00432 max_code=MaxCode(number_bits); \ 00433 } \ 00434 } 00435 00436 IndexPacket 00437 index; 00438 00439 long 00440 displacement, 00441 offset, 00442 k, 00443 y; 00444 00445 MagickBooleanType 00446 status; 00447 00448 register const PixelPacket 00449 *p; 00450 00451 register IndexPacket 00452 *indexes; 00453 00454 register long 00455 i, 00456 x; 00457 00458 size_t 00459 length; 00460 00461 short 00462 *hash_code, 00463 *hash_prefix, 00464 waiting_code; 00465 00466 unsigned char 00467 *packet, 00468 *hash_suffix; 00469 00470 unsigned long 00471 bits, 00472 clear_code, 00473 datum, 00474 end_of_information_code, 00475 free_code, 00476 max_code, 00477 next_pixel, 00478 number_bits, 00479 pass; 00480 00481 /* 00482 Allocate encoder tables. 00483 */ 00484 assert(image != (Image *) NULL); 00485 packet=(unsigned char *) AcquireMagickMemory(256); 00486 hash_code=(short *) AcquireMagickMemory(MaxHashTable*sizeof(*hash_code)); 00487 hash_prefix=(short *) AcquireMagickMemory(MaxHashTable*sizeof(*hash_prefix)); 00488 hash_suffix=(unsigned char *) AcquireMagickMemory(MaxHashTable); 00489 if ((packet == (unsigned char *) NULL) || (hash_code == (short *) NULL) || 00490 (hash_prefix == (short *) NULL) || 00491 (hash_suffix == (unsigned char *) NULL)) 00492 return(MagickFalse); 00493 /* 00494 Initialize GIF encoder. 00495 */ 00496 number_bits=data_size; 00497 max_code=MaxCode(number_bits); 00498 clear_code=((short) 1 << (data_size-1)); 00499 end_of_information_code=clear_code+1; 00500 free_code=clear_code+2; 00501 length=0; 00502 datum=0; 00503 bits=0; 00504 for (i=0; i < MaxHashTable; i++) 00505 hash_code[i]=0; 00506 GIFOutputCode(clear_code); 00507 /* 00508 Encode pixels. 00509 */ 00510 offset=0; 00511 pass=0; 00512 waiting_code=0; 00513 for (y=0; y < (long) image->rows; y++) 00514 { 00515 p=AcquireImagePixels(image,0,offset,image->columns,1,&image->exception); 00516 if (p == (const PixelPacket *) NULL) 00517 break; 00518 indexes=GetIndexes(image); 00519 if (y == 0) 00520 waiting_code=(short) (*indexes); 00521 for (x=(y == 0) ? 1 : 0; x < (long) image->columns; x++) 00522 { 00523 /* 00524 Probe hash table. 00525 */ 00526 index=indexes[x] & 0xff; 00527 p++; 00528 k=(int) (index << (MaxGIFBits-8))+waiting_code; 00529 if (k >= MaxHashTable) 00530 k-=MaxHashTable; 00531 next_pixel=MagickFalse; 00532 displacement=1; 00533 if (hash_code[k] > 0) 00534 { 00535 if ((hash_prefix[k] == waiting_code) && 00536 (hash_suffix[k] == (unsigned char) index)) 00537 { 00538 waiting_code=hash_code[k]; 00539 continue; 00540 } 00541 if (k != 0) 00542 displacement=MaxHashTable-k; 00543 for ( ; ; ) 00544 { 00545 k-=displacement; 00546 if (k < 0) 00547 k+=MaxHashTable; 00548 if (hash_code[k] == 0) 00549 break; 00550 if ((hash_prefix[k] == waiting_code) && 00551 (hash_suffix[k] == (unsigned char) index)) 00552 { 00553 waiting_code=hash_code[k]; 00554 next_pixel=MagickTrue; 00555 break; 00556 } 00557 } 00558 if (next_pixel == MagickTrue) 00559 continue; 00560 } 00561 GIFOutputCode((unsigned long) waiting_code); 00562 if (free_code < MaxGIFTable) 00563 { 00564 hash_code[k]=(short) free_code++; 00565 hash_prefix[k]=waiting_code; 00566 hash_suffix[k]=(unsigned char) index; 00567 } 00568 else 00569 { 00570 /* 00571 Fill the hash table with empty entries. 00572 */ 00573 for (k=0; k < MaxHashTable; k++) 00574 hash_code[k]=0; 00575 /* 00576 Reset compressor and issue a clear code. 00577 */ 00578 free_code=clear_code+2; 00579 GIFOutputCode(clear_code); 00580 number_bits=data_size; 00581 max_code=MaxCode(number_bits); 00582 } 00583 waiting_code=(short) index; 00584 } 00585 if (image_info->interlace == NoInterlace) 00586 offset++; 00587 else 00588 switch (pass) 00589 { 00590 case 0: 00591 default: 00592 { 00593 offset+=8; 00594 if (offset >= (long) image->rows) 00595 { 00596 pass++; 00597 offset=4; 00598 } 00599 break; 00600 } 00601 case 1: 00602 { 00603 offset+=8; 00604 if (offset >= (long) image->rows) 00605 { 00606 pass++; 00607 offset=2; 00608 } 00609 break; 00610 } 00611 case 2: 00612 { 00613 offset+=4; 00614 if (offset >= (long) image->rows) 00615 { 00616 pass++; 00617 offset=1; 00618 } 00619 break; 00620 } 00621 case 3: 00622 { 00623 offset+=2; 00624 break; 00625 } 00626 } 00627 if (image->previous == (Image *) NULL) 00628 if ((image->progress_monitor != (MagickProgressMonitor) NULL) && 00629 (QuantumTick(y,image->rows) != MagickFalse)) 00630 { 00631 status=image->progress_monitor(SaveImageTag,y,image->rows, 00632 image->client_data); 00633 if (status == MagickFalse) 00634 break; 00635 } 00636 } 00637 /* 00638 Flush out the buffered code. 00639 */ 00640 GIFOutputCode((unsigned long) waiting_code); 00641 GIFOutputCode(end_of_information_code); 00642 if (bits > 0) 00643 { 00644 /* 00645 Add a character to current packet. 00646 */ 00647 packet[length++]=(unsigned char) (datum & 0xff); 00648 if (length >= 254) 00649 { 00650 (void) WriteBlobByte(image,(unsigned char) length); 00651 (void) WriteBlob(image,length,packet); 00652 length=0; 00653 } 00654 } 00655 /* 00656 Flush accumulated data. 00657 */ 00658 if (length > 0) 00659 { 00660 (void) WriteBlobByte(image,(unsigned char) length); 00661 (void) WriteBlob(image,length,packet); 00662 } 00663 /* 00664 Free encoder memory. 00665 */ 00666 hash_suffix=(unsigned char *) RelinquishMagickMemory(hash_suffix); 00667 hash_prefix=(short *) RelinquishMagickMemory(hash_prefix); 00668 hash_code=(short *) RelinquishMagickMemory(hash_code); 00669 packet=(unsigned char *) RelinquishMagickMemory(packet); 00670 return(MagickTrue); 00671 } 00672 00673 /* 00674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00675 % % 00676 % % 00677 % % 00678 % I s G I F % 00679 % % 00680 % % 00681 % % 00682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00683 % 00684 % IsGIF() returns MagickTrue if the image format type, identified by the 00685 % magick string, is GIF. 00686 % 00687 % The format of the IsGIF method is: 00688 % 00689 % MagickBooleanType IsGIF(const unsigned char *magick,const size_t length) 00690 % 00691 % A description of each parameter follows: 00692 % 00693 % o magick: This string is generally the first few bytes of an image file 00694 % or blob. 00695 % 00696 % o length: Specifies the length of the magick string. 00697 % 00698 % 00699 */ 00700 static MagickBooleanType IsGIF(const unsigned char *magick,const size_t length) 00701 { 00702 if (length < 4) 00703 return(MagickFalse); 00704 if (LocaleNCompare((char *) magick,"GIF8",4) == 0) 00705 return(MagickTrue); 00706 return(MagickFalse); 00707 } 00708 00709 /* 00710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00711 % % 00712 % % 00713 % % 00714 + R e a d B l o b B l o c k % 00715 % % 00716 % % 00717 % % 00718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00719 % 00720 % ReadBlobBlock() reads data from the image file and returns it. The 00721 % amount of data is determined by first reading a count byte. The number 00722 % or bytes read is returned. 00723 % 00724 % The format of the ReadBlobBlock method is: 00725 % 00726 % size_t ReadBlobBlock(Image *image,unsigned char *data) 00727 % 00728 % A description of each parameter follows: 00729 % 00730 % o image: The image. 00731 % 00732 % o data: Specifies an area to place the information requested from 00733 % the file. 00734 % 00735 % 00736 */ 00737 static ssize_t ReadBlobBlock(Image *image,unsigned char *data) 00738 { 00739 ssize_t 00740 count; 00741 00742 unsigned char 00743 block_count; 00744 00745 assert(image != (Image *) NULL); 00746 assert(image->signature == MagickSignature); 00747 assert(data != (unsigned char *) NULL); 00748 count=ReadBlob(image,1,&block_count); 00749 if (count == 0) 00750 return(0); 00751 return(ReadBlob(image,(size_t) block_count,data)); 00752 } 00753 00754 /* 00755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00756 % % 00757 % % 00758 % % 00759 % R e a d G I F I m a g e % 00760 % % 00761 % % 00762 % % 00763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 00764 % 00765 % ReadGIFImage() reads a Compuserve Graphics image file and returns it. 00766 % It allocates the memory necessary for the new Image structure and returns a 00767 % pointer to the new image. 00768 % 00769 % The format of the ReadGIFImage method is: 00770 % 00771 % Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception) 00772 % 00773 % A description of each parameter follows: 00774 % 00775 % o image_info: The image info. 00776 % 00777 % o exception: return any errors or warnings in this structure. 00778 % 00779 % 00780 */ 00781 static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception) 00782 { 00783 #define BitSet(byte,bit) (((byte) & (bit)) == (bit)) 00784 #define LSBFirstOrder(x,y) (((y) << 8) | (x)) 00785 00786 Image 00787 *image; 00788 00789 long 00790 opacity; 00791 00792 MagickBooleanType 00793 status; 00794 00795 RectangleInfo 00796 page; 00797 00798 register long 00799 i; 00800 00801 register unsigned char 00802 *p; 00803 00804 ssize_t 00805 count; 00806 00807 unsigned char 00808 background, 00809 c, 00810 flag, 00811 *global_colormap, 00812 header[MaxTextExtent], 00813 magick[12]; 00814 00815 unsigned long 00816 delay, 00817 dispose, 00818 global_colors, 00819 image_count, 00820 iterations; 00821 00822 /* 00823 Open image file. 00824 */ 00825 assert(image_info != (const ImageInfo *) NULL); 00826 assert(image_info->signature == MagickSignature); 00827 if (image_info->debug != MagickFalse) 00828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image_info->filename); 00829 assert(exception != (ExceptionInfo *) NULL); 00830 assert(exception->signature == MagickSignature); 00831 image=AllocateImage(image_info); 00832 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 00833 if (status == MagickFalse) 00834 { 00835 DestroyImageList(image); 00836 return((Image *) NULL); 00837 } 00838 /* 00839 Determine if this is a GIF file. 00840 */ 00841 count=ReadBlob(image,6,magick); 00842 if ((count == 0) || ((LocaleNCompare((char *) magick,"GIF87",5) != 0) && 00843 (LocaleNCompare((char *) magick,"GIF89",5) != 0))) 00844 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 00845 global_colors=0; 00846 global_colormap=(unsigned char *) NULL; 00847 page.width=ReadBlobLSBShort(image); 00848 page.height=ReadBlobLSBShort(image); 00849 flag=(unsigned char) ReadBlobByte(image); 00850 background=(unsigned char) ReadBlobByte(image); 00851 c=(unsigned char) ReadBlobByte(image); /* reserved */ 00852 global_colors=1 << (((unsigned long) flag & 0x07)+1); 00853 global_colormap=(unsigned char *) 00854 AcquireMagickMemory((size_t) (3*Max(global_colors,256))); 00855 if (global_colormap == (unsigned char *) NULL) 00856 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 00857 if (BitSet((int) flag,0x80) != 0) 00858 (void) ReadBlob(image,(size_t) (3*global_colors),global_colormap); 00859 delay=0; 00860 dispose=0; 00861 iterations=1; 00862 opacity=(-1); 00863 image_count=0; 00864 for ( ; ; ) 00865 { 00866 count=ReadBlob(image,1,&c); 00867 if (count == 0) 00868 break; 00869 if (c == (unsigned char) ';') 00870 break; /* terminator */ 00871 if (c == (unsigned char) '!') 00872 { 00873 /* 00874 GIF Extension block. 00875 */ 00876 count=ReadBlob(image,1,&c); 00877 if (count == 0) 00878 ThrowReaderException(CorruptImageError,"UnableToReadExtensionBlock"); 00879 switch (c) 00880 { 00881 case 0xf9: 00882 { 00883 /* 00884 Read graphics control extension. 00885 */ 00886 while (ReadBlobBlock(image,header) != 0); 00887 dispose=(unsigned long) (header[0] >> 2); 00888 delay=(unsigned long) ((header[2] << 8) | header[1]); 00889 if ((int) (header[0] & 0x01) == 0x01) 00890 opacity=(long) header[3]; 00891 break; 00892 } 00893 case 0xfe: 00894 { 00895 char 00896 *comments; 00897 00898 /* 00899 Read comment extension. 00900 */ 00901 comments=AcquireString((char *) NULL); 00902 for ( ; ; ) 00903 { 00904 count=(ssize_t) ReadBlobBlock(image,header); 00905 if (count == 0) 00906 break; 00907 header[count]='\0'; 00908 (void) ConcatenateString(&comments,(const char *) header); 00909 } 00910 (void) SetImageAttribute(image,"Comment",comments); 00911 comments=(char *) RelinquishMagickMemory(comments); 00912 break; 00913 } 00914 case 0xff: 00915 { 00916 MagickBooleanType 00917 loop; 00918 00919 /* 00920 Read Netscape Loop extension. 00921 */ 00922 loop=MagickFalse; 00923 if (ReadBlobBlock(image,header) != 0) 00924 loop=(MagickBooleanType) 00925 (LocaleNCompare((char *) header,"NETSCAPE2.0",11) == 0); 00926 while (ReadBlobBlock(image,header) != 0) 00927 if (loop != MagickFalse) 00928 iterations=(unsigned long) ((header[2] << 8) | header[1]); 00929 break; 00930 } 00931 default: 00932 { 00933 while (ReadBlobBlock(image,header) != 0); 00934 break; 00935 } 00936 } 00937 } 00938 if (c != (unsigned char) ',') 00939 continue; 00940 if (image_count != 0) 00941 { 00942 /* 00943 Allocate next image structure. 00944 */ 00945 AllocateNextImage(image_info,image); 00946 if (image->next == (Image *) NULL) 00947 { 00948 DestroyImageList(image); 00949 global_colormap=(unsigned char *) 00950 RelinquishMagickMemory(global_colormap); 00951 return((Image *) NULL); 00952 } 00953 image=SyncNextImageInList(image); 00954 if (image->progress_monitor != (MagickProgressMonitor) NULL) 00955 { 00956 status=image->progress_monitor(LoadImagesTag,TellBlob(image), 00957 GetBlobSize(image),image->client_data); 00958 if (status == MagickFalse) 00959 break; 00960 } 00961 } 00962 image_count++; 00963 /* 00964 Read image attributes. 00965 */ 00966 image->storage_class=PseudoClass; 00967 image->compression=LZWCompression; 00968 page.x=(long) ReadBlobLSBShort(image); 00969 page.y=(long) ReadBlobLSBShort(image); 00970 image->columns=ReadBlobLSBShort(image); 00971 image->rows=ReadBlobLSBShort(image); 00972 image->depth=8; 00973 flag=(unsigned char) ReadBlobByte(image); 00974 image->interlace=BitSet((int) flag,0x40) != 0 ? PlaneInterlace : 00975 NoInterlace; 00976 image->colors=BitSet((int) flag,0x80) == 0 ? global_colors : 00977 1UL << ((unsigned long) (flag & 0x07)+1); 00978 if (opacity >= (long) image->colors) 00979 image->colors=(unsigned long) opacity+1; 00980 image->page.width=page.width; 00981 image->page.height=page.height; 00982 image->page.y=page.y; 00983 image->page.x=page.x; 00984 image->delay=delay; 00985 image->dispose=(DisposeType) dispose; 00986 image->iterations=iterations; 00987 image->matte=(MagickBooleanType) (opacity >= 0); 00988 delay=0; 00989 dispose=0; 00990 iterations=1; 00991 if ((image->columns == 0) || (image->rows == 0)) 00992 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 00993 /* 00994 Inititialize colormap. 00995 */ 00996 if (AllocateImageColormap(image,image->colors) == MagickFalse) 00997 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 00998 if (BitSet((int) flag,0x80) == 0) 00999 { 01000 /* 01001 Use global colormap. 01002 */ 01003 p=global_colormap; 01004 for (i=0; i < (long) image->colors; i++) 01005 { 01006 image->colormap[i].red=ScaleCharToQuantum(*p++); 01007 image->colormap[i].green=ScaleCharToQuantum(*p++); 01008 image->colormap[i].blue=ScaleCharToQuantum(*p++); 01009 } 01010 image->background_color= 01011 image->colormap[Min((unsigned long) background,image->colors-1)]; 01012 } 01013 else 01014 { 01015 unsigned char 01016 *colormap; 01017 01018 /* 01019 Read local colormap. 01020 */ 01021 colormap=(unsigned char *) 01022 AcquireMagickMemory((size_t) (3*image->colors)); 01023 if (colormap == (unsigned char *) NULL) 01024 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 01025 (void) ReadBlob(image,(size_t) (3*image->colors),colormap); 01026 p=colormap; 01027 for (i=0; i < (long) image->colors; i++) 01028 { 01029 image->colormap[i].red=ScaleCharToQuantum(*p++); 01030 image->colormap[i].green=ScaleCharToQuantum(*p++); 01031 image->colormap[i].blue=ScaleCharToQuantum(*p++); 01032 } 01033 colormap=(unsigned char *) RelinquishMagickMemory(colormap); 01034 } 01035 if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0)) 01036 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 01037 break; 01038 /* 01039 Decode image. 01040 */ 01041 status=DecodeImage(image,(Quantum) opacity); 01042 if ((image_info->ping == MagickFalse) && (status == MagickFalse)) 01043 { 01044 global_colormap=(unsigned char *) 01045 RelinquishMagickMemory(global_colormap); 01046 ThrowReaderException(CorruptImageError,"CorruptImage"); 01047 } 01048 if (image_info->number_scenes != 0) 01049 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 01050 break; 01051 opacity=(-1); 01052 } 01053 global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap); 01054 if ((image->columns == 0) || (image->rows == 0)) 01055 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 01056 CloseBlob(image); 01057 return(GetFirstImageInList(image)); 01058 } 01059 01060 /* 01061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01062 % % 01063 % % 01064 % % 01065 % R e g i s t e r G I F I m a g e % 01066 % % 01067 % % 01068 % % 01069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01070 % 01071 % RegisterGIFImage() adds attributes for the GIF image format to 01072 % the list of supported formats. The attributes include the image format 01073 % tag, a method to read and/or write the format, whether the format 01074 % supports the saving of more than one frame to the same file or blob, 01075 % whether the format supports native in-memory I/O, and a brief 01076 % description of the format. 01077 % 01078 % The format of the RegisterGIFImage method is: 01079 % 01080 % RegisterGIFImage(void) 01081 % 01082 */ 01083 ModuleExport void RegisterGIFImage(void) 01084 { 01085 MagickInfo 01086 *entry; 01087 01088 entry=SetMagickInfo("GIF"); 01089 entry->decoder=(DecoderHandler *) ReadGIFImage; 01090 entry->encoder=(EncoderHandler *) WriteGIFImage; 01091 entry->magick=(MagickHandler *) IsGIF; 01092 entry->description=AcquireString("CompuServe graphics interchange format"); 01093 entry->module=AcquireString("GIF"); 01094 (void) RegisterMagickInfo(entry); 01095 entry=SetMagickInfo("GIF87"); 01096 entry->decoder=(DecoderHandler *) ReadGIFImage; 01097 entry->encoder=(EncoderHandler *) WriteGIFImage; 01098 entry->magick=(MagickHandler *) IsGIF; 01099 entry->adjoin=MagickFalse; 01100 entry->description=AcquireString("CompuServe graphics interchange format"); 01101 entry->version=AcquireString("version 87a"); 01102 entry->module=AcquireString("GIF"); 01103 (void) RegisterMagickInfo(entry); 01104 } 01105 01106 /* 01107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01108 % % 01109 % % 01110 % % 01111 % U n r e g i s t e r G I F I m a g e % 01112 % % 01113 % % 01114 % % 01115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01116 % 01117 % UnregisterGIFImage() removes format registrations made by the 01118 % GIF module from the list of supported formats. 01119 % 01120 % The format of the UnregisterGIFImage method is: 01121 % 01122 % UnregisterGIFImage(void) 01123 % 01124 */ 01125 ModuleExport void UnregisterGIFImage(void) 01126 { 01127 (void) UnregisterMagickInfo("GIF"); 01128 (void) UnregisterMagickInfo("GIF87"); 01129 } 01130 01131 /* 01132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01133 % % 01134 % % 01135 % % 01136 % W r i t e G I F I m a g e % 01137 % % 01138 % % 01139 % % 01140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 01141 % 01142 % WriteGIFImage() writes an image to a file in the Compuserve Graphics 01143 % image format. 01144 % 01145 % The format of the WriteGIFImage method is: 01146 % 01147 % MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image) 01148 % 01149 % A description of each parameter follows. 01150 % 01151 % o image_info: The image info. 01152 % 01153 % o image: The image. 01154 % 01155 % 01156 */ 01157 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image) 01158 { 01159 Image 01160 *next_image; 01161 01162 int 01163 c; 01164 01165 long 01166 j, 01167 opacity, 01168 y; 01169 01170 ImageInfo 01171 *write_info; 01172 01173 InterlaceType 01174 interlace; 01175 01176 MagickBooleanType 01177 status; 01178 01179 MagickOffsetType 01180 scene; 01181 01182 QuantizeInfo 01183 quantize_info; 01184 01185 RectangleInfo 01186 page; 01187 01188 register IndexPacket 01189 *indexes; 01190 01191 register const PixelPacket 01192 *p; 01193 01194 register long 01195 x; 01196 01197 register long 01198 i; 01199 01200 register unsigned char 01201 *q; 01202 01203 size_t 01204 length; 01205 01206 unsigned char 01207 *colormap, 01208 *global_colormap; 01209 01210 unsigned long 01211 bits_per_pixel; 01212 01213 /* 01214 Open output image file. 01215 */ 01216 assert(image_info != (const ImageInfo *) NULL); 01217 assert(image_info->signature == MagickSignature); 01218 assert(image != (Image *) NULL); 01219 assert(image->signature == MagickSignature); 01220 if (image->debug != MagickFalse) 01221 (void) LogMagickEvent(TraceEvent,GetMagickModule(),image->filename); 01222 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); 01223 if (status == MagickFalse) 01224 return(status); 01225 /* 01226 Determine image bounding box. 01227 */ 01228 page.width=image->columns; 01229 page.height=image->rows; 01230 page.x=0; 01231 page.y=0; 01232 for (next_image=image; next_image != (Image *) NULL; ) 01233 { 01234 page.x=next_image->page.x; 01235 page.y=next_image->page.y; 01236 if ((next_image->columns+page.x) > page.width) 01237 page.width=next_image->columns+page.x; 01238 if ((next_image->rows+page.y) > page.height) 01239 page.height=next_image->rows+page.y; 01240 next_image=next_image->next; 01241 } 01242 /* 01243 Allocate colormap. 01244 */ 01245 global_colormap=(unsigned char *) AcquireMagickMemory(768); 01246 colormap=(unsigned char *) AcquireMagickMemory(768); 01247 if ((global_colormap == (unsigned char *) NULL) || 01248 (colormap == (unsigned char *) NULL)) 01249 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 01250 for (i=0; i < 768; i++) 01251 colormap[i]=(unsigned char) 0; 01252 /* 01253 Write GIF header. 01254 */ 01255 write_info=CloneImageInfo(image_info); 01256 if (LocaleCompare(write_info->magick,"GIF87") != 0) 01257 (void) WriteBlob(image,6,(unsigned char *) "GIF89a"); 01258 else 01259 { 01260 (void) WriteBlob(image,6,(unsigned char *) "GIF87a"); 01261 write_info->adjoin=MagickFalse; 01262 } 01263 page.x=image->page.x; 01264 page.y=image->page.y; 01265 if ((image->page.width != 0) && (image->page.height != 0)) 01266 page=image->page; 01267 (void) WriteBlobLSBShort(image,(unsigned short) page.width); 01268 (void) WriteBlobLSBShort(image,(unsigned short) page.height); 01269 /* 01270 Write images to file. 01271 */ 01272 interlace=write_info->interlace; 01273 if ((write_info->adjoin != MagickFalse) && (image->next != (Image *) NULL)) 01274 interlace=NoInterlace; 01275 scene=0; 01276 do 01277 { 01278 opacity=(-1); 01279 (void) SetImageColorspace(image,RGBColorspace); 01280 if ((image->storage_class == DirectClass) || (image->colors > 256)) 01281 { 01282 /* 01283 GIF requires that the image is colormapped. 01284 */ 01285 GetQuantizeInfo(&quantize_info); 01286 quantize_info.dither= 01287 IsPaletteImage(image,&image->exception) == MagickFalse; 01288 if ((LocaleCompare(write_info->magick,"GIF87") == 0) || 01289 (image->matte == MagickFalse)) 01290 (void) QuantizeImage(&quantize_info,image); 01291 else 01292 { 01293 /* 01294 Set transparent pixel. 01295 */ 01296 quantize_info.number_colors=255; 01297 (void) QuantizeImage(&quantize_info,image); 01298 opacity=(long) image->colors++; 01299 image->colormap=(PixelPacket *) ResizeMagickMemory(image->colormap, 01300 (size_t) image->colors*sizeof(*image->colormap)); 01301 if (image->colormap == (PixelPacket *) NULL) 01302 { 01303 global_colormap=(unsigned char *) 01304 RelinquishMagickMemory(global_colormap); 01305 colormap=(unsigned char *) RelinquishMagickMemory(colormap); 01306 write_info=DestroyImageInfo(write_info); 01307 ThrowWriterException(ResourceLimitError, 01308 "MemoryAllocationFailed"); 01309 } 01310 image->colormap[opacity]=image->background_color; 01311 for (y=0; y < (long) image->rows; y++) 01312 { 01313 p=AcquireImagePixels(image,0,y,image->columns,1, 01314 &image->exception); 01315 if (p == (const PixelPacket *) NULL) 01316 break; 01317 indexes=GetIndexes(image); 01318 for (x=0; x < (long) image->columns; x++) 01319 { 01320 if ((double) p->opacity >= (MaxRGB-image->fuzz)) 01321 indexes[x]=(IndexPacket) opacity; 01322 p++; 01323 } 01324 if (SyncImagePixels(image) == MagickFalse) 01325 break; 01326 } 01327 } 01328 } 01329 else 01330 if ((LocaleCompare(write_info->magick,"GIF87") != 0) && 01331 (image->matte != MagickFalse)) 01332 { 01333 /* 01334 Identify transparent pixel index. 01335 */ 01336 for (y=0; y < (long) image->rows; y++) 01337 { 01338 p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); 01339 if (p == (const PixelPacket *) NULL) 01340 break; 01341 indexes=GetIndexes(image); 01342 for (x=0; x < (long) image->columns; x++) 01343 { 01344 if ((double) p->opacity >= (MaxRGB-image->fuzz)) 01345 { 01346 opacity=(long) indexes[x]; 01347 break; 01348 } 01349 p++; 01350 } 01351 if (x < (long) image->columns) 01352 break; 01353 } 01354 } 01355 if (image->colormap == (PixelPacket *) NULL) 01356 break; 01357 for (bits_per_pixel=1; bits_per_pixel < 8; bits_per_pixel++) 01358 if ((1UL << bits_per_pixel) >= image->colors) 01359 break; 01360 q=colormap; 01361 for (i=0; i < (long) image->colors; i++) 01362 { 01363 *q++=ScaleQuantumToChar(image->colormap[i].red); 01364 *q++=ScaleQuantumToChar(image->colormap[i].green); 01365 *q++=ScaleQuantumToChar(image->colormap[i].blue); 01366 } 01367 for ( ; i < (long) (1UL << bits_per_pixel); i++) 01368 { 01369 *q++=(unsigned char) 0x0; 01370 *q++=(unsigned char) 0x0; 01371 *q++=(unsigned char) 0x0; 01372 } 01373 if ((image->previous == (Image *) NULL) || 01374 (write_info->adjoin == MagickFalse)) 01375 { 01376 /* 01377 Write global colormap. 01378 */ 01379 c=0x80; 01380 c|=(8-1) << 4; /* color resolution */ 01381 c|=(bits_per_pixel-1); /* size of global colormap */ 01382 (void) WriteBlobByte(image,(unsigned char) c); 01383 for (j=0; j < (long) Max(image->colors-1,1); j++) 01384 if (ColorMatch(&image->background_color,image->colormap+j)) 01385 break; 01386 (void) WriteBlobByte(image,(unsigned char) j); /* background color */ 01387 (void) WriteBlobByte(image,(unsigned char) 0x00); /* reserved */ 01388 length=(size_t) (3*(1 << bits_per_pixel)); 01389 (void) WriteBlob(image,length,colormap); 01390 for (j=0; j < 768; j++) 01391 global_colormap[j]=colormap[j]; 01392 } 01393 if (LocaleCompare(write_info->magick,"GIF87") != 0) 01394 { 01395 /* 01396 Write graphics control extension. 01397 */ 01398 (void) WriteBlobByte(image,(unsigned char) 0x21); 01399 (void) WriteBlobByte(image,(unsigned char) 0xf9); 01400 (void) WriteBlobByte(image,(unsigned char) 0x04); 01401 c=image->dispose << 2; 01402 if (opacity >= 0) 01403 c|=0x01; 01404 (void) WriteBlobByte(image,(unsigned char) c); 01405 (void) WriteBlobLSBShort(image,(unsigned short) image->delay); 01406 (void) WriteBlobByte(image,(unsigned char) 01407 (opacity >= 0 ? opacity : 0)); 01408 (void) WriteBlobByte(image,(unsigned char) 0x00); 01409 if ((LocaleCompare(write_info->magick,"GIF87") != 0) && 01410 (GetImageAttribute(image,"Comment") != (ImageAttribute *) NULL)) 01411 { 01412 const ImageAttribute 01413 *attribute; 01414 01415 register char 01416 *p; 01417 01418 size_t 01419 count; 01420 01421 /* 01422 Write Comment extension. 01423 */ 01424 (void) WriteBlobByte(image,(unsigned char) 0x21); 01425 (void) WriteBlobByte(image,(unsigned char) 0xfe); 01426 attribute=GetImageAttribute(image,"Comment"); 01427 p=attribute->value; 01428 while (strlen(p) != 0) 01429 { 01430 count=Min(strlen(p),255); 01431 (void) WriteBlobByte(image,(unsigned char) count); 01432 for (i=0; i < (long) count; i++) 01433 (void) WriteBlobByte(image,(unsigned char) *p++); 01434 } 01435 (void) WriteBlobByte(image,(unsigned char) 0x00); 01436 } 01437 if ((image->previous == (Image *) NULL) && 01438 (image->next != (Image *) NULL) && (image->iterations != 1)) 01439 { 01440 /* 01441 Write Netscape Loop extension. 01442 */ 01443 (void) WriteBlobByte(image,(unsigned char) 0x21); 01444 (void) WriteBlobByte(image,(unsigned char) 0xff); 01445 (void) WriteBlobByte(image,(unsigned char) 0x0b); 01446 (void) WriteBlob(image,11,(unsigned char *) "NETSCAPE2.0"); 01447 (void) WriteBlobByte(image,(unsigned char) 0x03); 01448 (void) WriteBlobByte(image,(unsigned char) 0x01); 01449 (void) WriteBlobLSBShort(image,(unsigned short) image->iterations); 01450 (void) WriteBlobByte(image,(unsigned char) 0x00); 01451 } 01452 } 01453 (void) WriteBlobByte(image,','); /* image separator */ 01454 /* 01455 Write the image header. 01456 */ 01457 page.x=image->page.x; 01458 page.y=image->page.y; 01459 if ((image->page.width != 0) && (image->page.height != 0)) 01460 page=image->page; 01461 (void) WriteBlobLSBShort(image,(unsigned short) (page.x < 0 ? 0 : page.x)); 01462 (void) WriteBlobLSBShort(image,(unsigned short) (page.y < 0 ? 0 : page.y)); 01463 (void) WriteBlobLSBShort(image,(unsigned short) image->columns); 01464 (void) WriteBlobLSBShort(image,(unsigned short) image->rows); 01465 c=0x00; 01466 if (interlace != NoInterlace) 01467 c|=0x40; /* pixel data is interlaced */ 01468 for (j=0; j < (long) (3*image->colors); j++) 01469 if (colormap[j] != global_colormap[j]) 01470 break; 01471 if (j == (long) (3*image->colors)) 01472 (void) WriteBlobByte(image,(unsigned char) c); 01473 else 01474 { 01475 c|=0x80; 01476 c|=(bits_per_pixel-1); /* size of local colormap */ 01477 (void) WriteBlobByte(image,(unsigned char) c); 01478 length=(size_t) (3*(1UL << bits_per_pixel)); 01479 (void) WriteBlob(image,length,colormap); 01480 } 01481 /* 01482 Write the image data. 01483 */ 01484 c=(int) Max(bits_per_pixel,2); 01485 (void) WriteBlobByte(image,(unsigned char) c); 01486 status=EncodeImage(write_info,image,Max(bits_per_pixel,2)+1); 01487 if (status == MagickFalse) 01488 { 01489 global_colormap=(unsigned char *) 01490 RelinquishMagickMemory(global_colormap); 01491 colormap=(unsigned char *) RelinquishMagickMemory(colormap); 01492 write_info=DestroyImageInfo(write_info); 01493 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 01494 } 01495 (void) WriteBlobByte(image,(unsigned char) 0x00); 01496 if (image->next == (Image *) NULL) 01497 break; 01498 image=SyncNextImageInList(image); 01499 if (image->progress_monitor != (MagickProgressMonitor) NULL) 01500 { 01501 status=image->progress_monitor(SaveImagesTag,scene, 01502 GetImageListLength(image),image->client_data); 01503 if (status == MagickFalse) 01504 break; 01505 } 01506 scene++; 01507 } while (write_info->adjoin != MagickFalse); 01508 (void) WriteBlobByte(image,';'); /* terminator */ 01509 global_colormap=(unsigned char *) RelinquishMagickMemory(global_colormap); 01510 colormap=(unsigned char *) RelinquishMagickMemory(colormap); 01511 write_info=DestroyImageInfo(write_info); 01512 CloseBlob(image); 01513 return(MagickTrue); 01514 }

Generated on Mon Oct 25 13:40:36 2004 for ImageMagick by doxygen 1.3.7
ImageMagick Copyright © 2004, ImageMagick Studio LLC