1 /*===========================================================================*/
2 /* GifTools - GIF encoder / decoder */
3 /* Copyright (C) 2005 Jarek Tuszynski */
4 /* Distributed under GNU General Public License version 3 */
5 /*===========================================================================*/
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h> // memset, memcpy
10 #include "GifTools.h"
11 typedef unsigned char uchar;
12
13 #ifndef USING_R // if not using R language than define following calls:
14 #define print printf
15 #define Calloc(n, T) new T[n];
Free(void * p)16 inline void Free(void* p) { delete []p; }
17 #endif
18
19 //#define STANDALONE_TEST
20 #ifdef STANDALONE_TEST
Error(char * message)21 inline void Error(char *message) { fprintf(stderr, "\nError: %s.\n", message); exit(1); }
22 #endif //STANDALONE_TEST
23
24 //=======================================================================
25 // Encoding Algorithm adapted from code by Christoph Hohmann
26 // found at http://members.aol.com/rf21exe/gif.htm.
27 // Which was adapted from code by Michael A, Mayer
28 // found at http://www.danbbs.dk/%7Edino/whirlgif/gifcode.html
29 // Parts of Decoding Algorithm were adapted from code by David Koblas.
30 // It had the following notice:
31 // "Copyright 1990 - 1994, David Koblas. (koblas@netcom.com)
32 // Permission to use, copy, modify, and distribute this software and its
33 // documentation for any purpose and without fee is hereby granted, provided
34 // that the above copyright notice appear in all copies and that both that
35 // copyright notice and this permission notice appear in supporting
36 // documentation. This software is provided "as is" without express or
37 // implied warranty."
38 //=======================================================================
39
bitGet(int num,int bit)40 inline int bitGet (int num, int bit) { return ((num & (1<<bit)) !=0 ); }
41
42 //==============================================================
43 // bit-packer class
44 //==============================================================
45
GetDataBlock(FILE * fp,uchar * buffer)46 int GetDataBlock(FILE *fp, uchar *buffer)
47 {
48 int BlockSize = fgetc(fp);
49 if (BlockSize==EOF) return -1;
50 if (BlockSize== 0 ) return 0;
51 if (!fread(buffer, BlockSize, 1, fp)) return -1;
52 return BlockSize;
53 }
54
55
56 //=======================================================================
57 // Packs & unpacks a sequence of variable length codes into a buffer. Every
58 // time 255 bytes have been completed, they are written to a binary file as
59 // a data block of 256 bytes (where the first byte is the 'bytecount' of the
60 // rest and therefore equals 255). Any remaining bits are moved to the
61 // buffer start to become part of the following block. After submitting
62 // the last code via submit(), the user must call WriteFlush() to write
63 // a terminal, possibly shorter, data block.
64 //=======================================================================
65 class BitPacker {
66 public:
67
BitPacker()68 BitPacker()
69 { // Constructor
70 binfile = NULL;
71 need = 8;
72 pos = buffer;
73 *pos = 0;
74 bytesdone = 0;
75 BlockSize = 255;
76 curbit = (2+BlockSize)<<3;
77 }
78
BytesDone()79 int BytesDone() { return bytesdone; }
GetFile(FILE * bf)80 void GetFile(FILE *bf) { binfile = bf; }
81
82 //-------------------------------------------------------------------------
83
SubmitCode(short code,short nBits)84 void SubmitCode(short code, short nBits)
85 // Packs an incoming 'code' of 'nBits' bits [1,12] to the buffer. As soon
86 // as 255 bytes are full, they are written to 'binfile' as a data block
87 // end cleared from 'buffer'.
88 {
89 // 'pos' points to a partially empty byte and
90 // 'need' [1..8] tells how many bits will still fit in there.
91 // Since the bytes are filled bottom up (least significant bits first),
92 // the 'need' vacant bits are the most significant ones.
93 if (nBits<0 || nBits>12) Error("BitPacker::SubmitCode");
94 short mask;
95 while (nBits >= need) {
96 mask = (1<<need)-1; // 'mask'= all zeroes followed by 'need' ones
97 *pos += static_cast<uchar>((mask&code) << (8-need)); // the 'need' lowest bits of 'code' fill the current byte at its upper end
98 nBits -= need; // update the length of 'code'
99 code >>= need; // remove the written bits from code
100 *(++pos)=0; // byte is now full, goto next byte & init it
101 need=8; // current byte can take 8 bits
102 } // Now we have nBits < need.
103 // (remainder of) code is written to the nBits rightmost free bits of
104 // the current byte. The current byte can still take 'need' bits, and
105 // we have 'need'>0. The bits will be filled upon future calls.
106 if(nBits>0) {
107 mask = (1<<nBits)-1; // 'mask'= all zeroes followed by 'need' ones
108 *pos += static_cast<uchar>((mask&code)<<(8-need));
109 need -= nBits;
110 }
111 // As soon as 255 bytes are full, they are written to 'binfile' as a
112 // data block and removed from 'buffer'.
113 if(pos-buffer >= 255) { // pos pointing to buffer[255] or beyond
114 fputc(255,binfile); // write the "bytecount-byte"
115 fwrite(buffer,255,1,binfile); // write buffer[0..254] to file
116 buffer[0] = buffer[255]; // rotate the following bytes, which may still
117 buffer[1] = buffer[256]; // contain data, to the beginning of buffer,
118 pos -= 255; // point pos to the position for new input
119 bytesdone += 256;
120 }
121 } // BitPacker::SubmitCode
122
123 //-------------------------------------------------------------------------
124
WriteFlush()125 void WriteFlush()
126 // Writes any data contained in 'buffer' to the file as one data block of
127 // 1<= length<=255.
128 {
129 // if the current byte is partially filled, leave it alone
130 if(need<8) pos++; // close any partially filled terminal byte
131 int BlockSize = static_cast<int>(pos-buffer); // # remaining bytes
132 if(BlockSize>0) { // buffer is empty
133 fputc(BlockSize, binfile);
134 fwrite(buffer, BlockSize, 1, binfile);
135 bytesdone += BlockSize+1;
136 }
137 } // BitPacker::WriteFlush
138
139 //-------------------------------------------------------------------------
140
GetCode(short nBits)141 short GetCode(short nBits)
142 // Extract nBits [1:32] integer from the buffer.
143 // Read next data block if needed.
144 {
145 short i, j, code, lastbit;
146 // if more bits is needed than we have stored in the buffer
147 lastbit = (2+BlockSize)<<3; // (BlockSize<<3 == BlockSize*8) - byte to bit conversion
148 while ( (curbit+nBits) >= lastbit ) { // If () should have been enough but used while() just in case
149 buffer[0] = buffer[BlockSize ];
150 buffer[1] = buffer[BlockSize+1];
151 curbit -= BlockSize<<3;
152 BlockSize = GetDataBlock(binfile, &buffer[2]);
153 lastbit = (2+BlockSize)<<3; // (BlockSize<<3 == BlockSize*8) - byte to bit conversion
154 bytesdone += BlockSize+1; // keep track of number of bytes read
155 }
156 // read next set of nBits from the buffer and store it into ret
157 code = 0;
158 i = curbit;
159 for (j=0; j<nBits; j++, i++)
160 code |= bitGet(buffer[i>>3] , i&7) << j;
161 curbit += nBits; // we read nBits of data from buffer
162 return code;
163 }
164
165 //-------------------------------------------------------------------------
166
ReadFlush()167 int ReadFlush()
168 {
169 short count;
170 while ((count = GetDataBlock(binfile, buffer)) > 0);
171 return count;
172 }
173
174 private:
175 FILE *binfile;
176 uchar buffer[260]; // holds the total buffer of 256 + some extra
177 uchar *pos; // sliding pointer into buffer
178 uchar need; // [1..8] tells how many bits will still fit in current byte
179 int bytesdone; // total number of bytes processed during the object's lifetime
180 int curbit, BlockSize;
181 }; // class bitpacker
182
183
184 //==============================================================
185 // Gif-compression de compression functions
186 //==============================================================
187
188 //===========================================================================
189 // Contains the string-table, generates compression codes and writes them to a
190 // binary file, formatted in data blocks of maximum length 255 with
191 // additional bytecount header.
192 // Encodes the pixel data and writes the "raster data"-section of the GIF
193 // file, consisting of the "code size" byte followed by the counter-headed
194 // data blocks, including the terminating zero block.
195 // bf must be an opened binary file to which the preceding parts
196 // of the GIF format have been written
197 // data is an array of bytes containing one pixel each and sorted
198 // left to right, top to bottom. The first pixel is in data[0]
199 // nPixel Number of pixels in the image
200 // nBit Number of bits per pixel, where 2^nBit is the size of the GIF's
201 // color tables. Allowed are 1..8. Used to determine 'nbits' and
202 // the number of root codes. Max(data) HAS to be < 2^nBits
203 // returns: The total number of bytes that have been written.
204 //-------------------------------------------------------------------------
EncodeLZW(FILE * bf,const uchar * data,int nPixel,short nBits)205 int EncodeLZW(FILE *bf, const uchar *data, int nPixel, short nBits)
206 {
207 BitPacker bp; // object that does the packing and writing of the compression codes
208 int iPixel; // pixel counter
209 uchar pixel; // next pixel value to be encoded
210 short axon[4096], next[4096]; // arrays making up the string-table
211 uchar pix[4096]; // dito
212 short freecode; // next code to be added to the string-table
213 short i, depth, cc, eoi, up, down, outlet;
214
215 if (nPixel<0) Error("EncodeLZW: nPixel can not be negative");
216 if (nBits<1 || nBits>8) Error(" EncodeLZW: nBit has to be between 1 and 8");
217
218 // The following parameters will remain unchanged through the run
219 depth = (nBits<2 ? 2 : nBits); // number of bits per data item (=pixel). Remains unchanged.
220 cc = 1<<depth; // 'cc' or 'clear-code' Signals the clearing of the string-table.
221 eoi = cc+1; // 'end-of-information'-code must be the last item of the code stream
222 // initialize pixel reader
223 nBits = depth+1; // current length of compression codes in bits [2, 12] (changes during encoding process)
224 iPixel = 0; // pixel #1 is next to be processed (iPixel will be pixel counter)
225 pixel = data[iPixel]; // get pixel #1
226 // alocate and initialize memory
227 bp.GetFile(bf); // object packs the code and renders it to the binary file 'bf'
228 for(i=0; i<cc; i++) pix[i] = static_cast<uchar>(i); // Initialize the string-table's root nodes
229
230 // Write what the GIF specification calls the "code size". Allowed are [2..8].
231 // This is the number of bits required to represent the pixel values.
232 fputc(depth,bf); // provide data-depth to the decoder
233 freecode = 4096; // this will cause string-table flush first time around
234 while(iPixel<nPixel) { // continue untill all the pixels are processed
235 if(freecode==(1<<nBits)) // if the latest code added to the string-table exceeds 'nbits' bits:
236 nBits++; // increase size of compression codes by 1 bit
237 freecode++; // freecode is only changed in this loop
238 if(freecode>=4096) { // free code is 2^12 the largest allowed
239 // Flush the string-table by removing the outlets of all root nodes. Everything is set to initial state.
240 memset(axon, 0, 4096*sizeof(short)); // avoid string-table overflow
241 bp.SubmitCode(cc,nBits); // tell the decoding software to flush its string-table
242 nBits = depth+1; // reset nBits
243 freecode = cc+2; // reset freecode
244 }
245 // Writes the next code to the codestream and adds one entry to the string-table.
246 outlet=pixel; // start with the root node for 'pixel'
247 // Follow the string-table and the data stream to the end of the
248 // longest string that has a code
249 do {
250 up = outlet;
251 iPixel++; // advance pixel counter (the only place it is advanced)
252 if(iPixel >= nPixel) break; // end of data stream ? Terminate
253 pixel = data[iPixel]; // get the value of the next pixel
254 // Checks if the chain starting from headnode's axon (axon[up]) contains a node for
255 // 'pixel'. Returns that node's address (=outlet), or 0 if there is no such node.
256 // 0 cannot be the root node 0, since root nodes occur in no chain.
257 outlet = axon[up];
258 while(outlet && pix[outlet]!=pixel) outlet=next[outlet];
259 } while(outlet);
260
261 // Submit 'up' which is the code of the longest string
262 bp.SubmitCode(up,nBits);
263 if(iPixel >= nPixel) break; // end of data stream ? Terminate
264
265 // Extend the string by appending 'pixel':
266 // Create a successor node for 'pixel' whose code is 'freecode'
267 pix [freecode]=pixel;
268 axon[freecode]=next[freecode]=0;
269 // Link it to the end of the chain emanating from axon[up].
270 // Don't link it to the start: it would slow down performance.
271 down=axon[up];
272 if(!down) axon[up]=freecode;
273 else {
274 while(next[down]) down=next[down];
275 next[down]=freecode;
276 }
277 } // while()
278
279 // Wrap up the file
280 bp.SubmitCode(eoi,nBits); // submit 'eoi' as the last item of the code stream
281 bp.WriteFlush(); // write remaining codes including this 'eoi' to the binary file
282 fputc(0,bf); // write an empty data block to signal the end of "raster data" section in the file
283 return 2 + bp.BytesDone();
284 } // EncodeLZW
285
286
287 //-------------------------------------------------------------------------
288 // Reads the "raster data"-section of the GIF file and decodes the pixel
289 // data. Most work is done by GifDecomposer class and this function mostly
290 // handles interlace row irdering
291 // bf must be an opened binary file to which the preceding parts
292 // of the GIF format have been written
293 // data is an array of bytes containing one pixel each and sorted
294 // left to right, top to bottom.
295 // nPixels Number of pixels in the image
296 // returns: The total number of bytes that have been written.
297 //-------------------------------------------------------------------------
DecodeLZW(FILE * fp,uchar * data,int nPixel)298 int DecodeLZW(FILE *fp, uchar *data, int nPixel)
299 {
300 BitPacker bp; // object that does the packing and writing of the
301 short cc, eoi, freecode, nBits, depth, nStack, code, incode, firstcode, oldcode;
302 short pix[4096], next[4096];
303 uchar stack[4096];
304 int iPixel, ret;
305
306 freecode=nBits=firstcode=oldcode=0; // unnecesary line used to prevent warnings in gcc
307 depth = fgetc(fp); // number of bits per data item (=pixel). Remains unchanged.
308 if (depth==EOF) return -1;
309 bp.GetFile(fp); // object packs the code and renders it to the binary file 'bf'
310 cc = 1<<depth; // 'cc' or 'clear-code' Signals the clearing of the string-table.
311 eoi = cc+1; // 'end-of-information'-code must be the last item of the code stream
312
313 code = cc; // this will force the code to flush & initialize the string-table first
314 for(iPixel=0; iPixel<nPixel; ) { // read until all pixels were read
315 if (iPixel) code=bp.GetCode(nBits);
316 if (code == -1) return 0; // error
317 if (code == eoi) break; // 'end-of-information' - last item of the code stream
318 if (code == cc) { // Flush the string-table. Everything is (re)set to initial state.
319 memset(next, 0, 4096*sizeof(short));
320 memset(pix , 0, 4096*sizeof(short));
321 for (int i=0; i<cc; i++) pix[i] = i;
322 nBits = depth+1;
323 freecode = cc+2;
324 do { firstcode = bp.GetCode(nBits); } while (firstcode==cc); // keep on flushing until a non cc entry
325 oldcode = firstcode;
326 data[iPixel++] = static_cast<uchar>(firstcode);
327 } else { // the regular case
328 nStack = 0; // (re)initialize the stack
329 incode = code; // store a copy of the code - it will be needed
330 if (code >= freecode) {
331 stack[nStack++] = static_cast<uchar>(firstcode);
332 code = oldcode;
333 }
334 while (code >= cc) { // read string for code from string-table
335 if (nStack>=4096) return 0; // error
336 stack[nStack++] = static_cast<uchar>(pix[code]);
337 code = next[code];
338 }
339 firstcode = pix[code];
340 data[iPixel++] = static_cast<uchar>(pix[code]);
341 while (nStack && iPixel<nPixel)
342 data[iPixel++] = stack[--nStack]; // if there is data on the stack return it
343 if (freecode<4096) { // free code is smaller than 2^12 the largest allowed
344 next[freecode] = oldcode;// add to string-table
345 pix [freecode] = firstcode;
346 freecode++;
347 if(freecode==(1<<nBits)) // if the latest code added to the string-table exceeds 'nbits' bits:
348 nBits++; // increase size of compression codes by 1 bit
349 }
350 oldcode = incode;
351 }
352 }
353 if (bp.ReadFlush()==0) ret = 1+bp.BytesDone(); // 'end-of-information' - last item of the code stream
354 else ret = 0;
355 return ret;
356 }
357
358
359 //==============================================================
360 // Gif Writer
361 //==============================================================
362
getint(uchar * buffer)363 inline int getint(uchar *buffer) { return (buffer[1]<<8) | buffer[0]; }
fputw(int w,FILE * fp)364 inline void fputw(int w, FILE *fp)
365 { // Write out a word to the GIF file
366 fputc( w & 0xff, fp );
367 fputc( (w>>8) & 0xff, fp );
368 }
369
370 //------------------------------------------
371
372
imwriteGif(const char * filename,const uchar * data,int nRow,int nCol,int nBand,int nColor,const int * ColorMap,bool interlace,int transparent,int DalayTime,char * comment)373 int imwriteGif(const char* filename, const uchar* data, int nRow, int nCol, int nBand, int nColor,
374 const int *ColorMap, bool interlace, int transparent, int DalayTime, char* comment)
375 {
376 int B, i, rgb, imMax, filesize=0, Bands, band, n, m;
377 int BitsPerPixel=0, ColorMapSize, Width, Height, nPixel;
378 char fname[256], sig[16], *q;
379 const uchar *p=data;
380
381 strcpy(fname,filename);
382 i = static_cast<int>(strlen(fname));
383 if (fname[i-4]=='.') strcpy(strrchr(fname,'.'),".gif");
384 Width = nCol;
385 Height = nRow;
386 Bands = nBand;
387 nPixel = Width*Height;
388 imMax = data[0];
389 n = nPixel*nBand;
390 for(i=0; i<n; i++, p++) if(imMax<*p) imMax=*p;
391 nColor=(nColor>256 ? 256 : nColor); // is a power of two between 2 and 256 compute its exponent BitsPerPixel (between 1 and 8)
392 if (!nColor) nColor = imMax+1;
393 if (imMax>nColor)
394 Error("ImWriteGif: Higher pixel values than size of color table");
395 for(i=1; i<nColor; i*=2) BitsPerPixel++;
396 if (BitsPerPixel==0) BitsPerPixel=1;
397
398 FILE *fp = fopen(fname,"wb");
399 if (fp==0) return -1;
400
401 //====================================
402 // GIF Signature and Screen Descriptor
403 //====================================
404 if (transparent>=0 || comment || Bands>1) strcpy(sig,"GIF89a"); else strcpy(sig,"GIF87a");
405 fwrite( sig, 1, 6, fp ); // Write the Magic header
406 fputw( Width , fp ); // Bit 1&2 : Logical Screen Width
407 fputw( Height, fp ); // Bit 3&4 : Logical Screen Height
408 B = 0xf0 | (0x7&(BitsPerPixel-1)); // write BitsPerPixel-1 to the three least significant bits of byte 5
409 fputc( B, fp ); // Bit 5: global color table (yes), color resolution, sort flag (no) size of global color table
410 fputc( 0, fp ); // Bit 6: Write out the Background color index
411 fputc( 0, fp ); // Bit 7: Byte of 0's (no aspect ratio info)
412
413 //====================================
414 // Global Color Map
415 //====================================
416 ColorMapSize = 1 << BitsPerPixel;
417 if (ColorMap) {
418 for( i=0; i<nColor; i++ ) { // Write out the Global Colour Map
419 rgb = ColorMap[i];
420 fputc( (rgb >> 16) & 0xff, fp );
421 fputc( (rgb >> 8) & 0xff, fp );
422 fputc( rgb & 0xff, fp );
423 }
424 } else { // default gray-scale ramp
425 for( i=0; i<nColor; i++ ) { // Write out the Global Colour Map
426 rgb = ((i*256)/nColor) & 0xff;
427 fputc( rgb, fp );
428 fputc( rgb, fp );
429 fputc( rgb, fp );
430 }
431 }
432 for( i=nColor; i<ColorMapSize; i++ ) { fputc(0,fp); fputc(0,fp); fputc(0,fp); }
433
434 //====================================
435 // Extentions (optional)
436 //====================================
437 n = (comment ? static_cast<int>(strlen(comment)) : 0);
438 if (n>0) {
439 fputc( 0x21, fp ); // GIF Extention Block introducer
440 fputc( 0xfe, fp ); // "Comment Extension"
441 for (q=comment; n>0; n-=255) {
442 m = n<255 ? n : 255;
443 fputc(m, fp );
444 fwrite(q, 1, m, fp );
445 q += m;
446 filesize += m+1;
447 }
448 fputc( 0, fp ); // extention Block Terminator
449 filesize += 3;
450 }
451 if (Bands>1) {
452 fputc( 0x21, fp ); // GIF Extention Block introducer
453 fputc( 0xff, fp ); // byte 2: 255 (hex 0xFF) Application Extension Label
454 fputc( 11, fp ); // byte 3: 11 (hex (0x0B) Length of Application Block
455 fwrite("NETSCAPE2.0", 1, 11, fp ); // bytes 4 to 14: 11 bis of first sub-block
456 fputc( 3, fp ); // byte 15: 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow)
457 fputc( 1, fp ); // byte 16: 1-means next number 2 bytes have iteration counter; 2-means next 4 bytes haveamount of memory needed
458 fputw( 0, fp ); // byte 17&18: 0 to 65535, an unsigned integer. # of iterations the loop should be executed.
459 fputc( 0, fp ); // extention Block Terminator
460 filesize += 19;
461 }
462
463
464 filesize += 6 + 7 + 3*ColorMapSize;
465 for (band=0; band<Bands; band++) {
466 if ( transparent >= 0 || Bands>1 ) {
467 fputc( 0x21, fp ); // GIF Extention Block introducer "!"
468 fputc( 0xf9, fp ); // "Graphic Control Extension"
469 fputc( 4, fp ); // block is of size 4
470 B = (Bands>1 ? 2 : 0) << 2; // Disposal Method
471 B |= (0) << 1; // User Input flag: is user input needed?
472 B |= (transparent >= 0 ? 1 : 0); // Transparency flag
473 fputc( B, fp ); // "transparency color follows" flag
474 fputw( DalayTime, fp ); // delay time in # of hundredths (1/100) of a second delay between frames
475 fputc( static_cast<uchar>(transparent), fp );
476 fputc( 0, fp ); // extention Block Terminator
477 filesize += 8;
478 }
479
480 //====================================
481 // Image Descriptor
482 //====================================
483 fputc( 0x2c , fp ); // Byte 1 : Write an Image Separator ","
484 fputw( 0 , fp ); // Byte 2&3: Write the Image left offset
485 fputw( 0 , fp ); // Byte 4&5: Write the Image top offset
486 fputw( Width , fp ); // Byte 6&7: Write the Image width
487 fputw( Height, fp ); // Byte 8&9: Write the Image height
488 fputc( interlace ? 0x40 : 0x00,fp); // Byte 10 : contains the interlaced flag
489 filesize += 10;
490
491 //====================================
492 // Raster Data (LZW encrypted)
493 //====================================
494 p = data+band*nPixel;
495 if(interlace) { // rearrange rows to do interlace
496 int i, row=0;
497 uchar* tmp = new uchar[Width*Height];
498 for (i=0; i<Height; i+=8) memcpy(tmp+Width*(row++), p+Width*i, Width);
499 for (i=4; i<Height; i+=8) memcpy(tmp+Width*(row++), p+Width*i, Width);
500 for (i=2; i<Height; i+=4) memcpy(tmp+Width*(row++), p+Width*i, Width);
501 for (i=1; i<Height; i+=2) memcpy(tmp+Width*(row++), p+Width*i, Width);
502 filesize += EncodeLZW(fp, tmp, nPixel, BitsPerPixel);
503 delete []tmp;
504 } else filesize += EncodeLZW(fp, p, nPixel, BitsPerPixel);
505 }
506
507 fputc(0x3b, fp ); // Write the GIF file terminator ";"
508 fclose(fp);
509 return filesize+1;
510 }
511
512 //==============================================================
513 // Gif Reader
514 // Limitations:
515 // - single colormap (global or local)
516 // - all bands will have same dimentions
517 //==============================================================
518
ReadColorMap(FILE * fp,uchar byte,int ColorMap[256],int skip=0)519 int ReadColorMap(FILE *fp, uchar byte, int ColorMap[256], int skip=0)
520 {
521 int i, nColor, ok=1;
522 uchar buf[16];
523 nColor = 2<<(byte&0x07);
524 if ((byte&0x80)==0x80) {
525 if (skip) {
526 char buffer[3*255];
527 if (!fread(buffer, 3*nColor, 1, fp)) return 0;
528 } else {
529 for (i=0; i<nColor; i++) {
530 if (!fread(buf, 3, 1, fp)) return 0;
531 ColorMap[i] = (buf[0]<<16) | (buf[1]<<8) | buf[2];
532 }
533 while(i<256) ColorMap[i++] = -1;
534 }
535 ok = 2;
536 }
537 return ok;
538 }
539
540 //------------------------------------------
541
append(uchar * trg,uchar * src,int nPixel,int nBand)542 uchar* append(uchar *trg, uchar *src, int nPixel, int nBand )
543 {
544 uchar* data = Calloc(nPixel*(nBand+1), uchar);
545 int n = nPixel*nBand*sizeof(uchar);
546 memcpy(data , trg, n);
547 memcpy(data+n, src, nPixel*sizeof(uchar));
548 Free(trg);
549 Free(src);
550 return data;
551 }
552
553 //------------------------------------------
554
imreadGif(const char * filename,int nImage,bool verbose,uchar ** data,int & nRow,int & nCol,int & nBand,int ColorMap[255],int & Transparent,char ** Comment)555 int imreadGif(const char* filename, int nImage, bool verbose,
556 uchar** data, int &nRow, int &nCol, int &nBand,
557 int ColorMap[255], int &Transparent, char** Comment)
558 {
559 bool interlace;
560 uchar buffer[256], *cube=0, *image=0;
561 int Width, Height, i, c, iImage, ret, DelayTime, stats, done, n, m, nColMap=0, filesize=0;
562 char version[7], fname[256], *p, *comment=0;
563
564 *data=NULL;
565 *Comment=NULL;
566 Width=Height=nRow=nCol=nBand=0;
567 ret=Transparent=-1;
568 strcpy(fname,filename);
569 i = static_cast<int>( strlen(fname));
570 if (fname[i-4]=='.') strcpy(strrchr(fname,'.'),".gif");
571 FILE *fp = fopen(fname,"rb");
572 if (fp==0) return -1;
573
574 //====================================================
575 // GIF Signature, Screen Descriptor & Global Color Map
576 //====================================================
577 if (!fread(version, 6, 1, fp)) return -2; // Read Header
578 version[6] = '\0';
579 if ((strcmp(version, "GIF87a") != 0) && (strcmp(version, "GIF89a") != 0)) return -2;
580 if (!fread(buffer, 7, 1, fp)) return -3; // Read Screen Descriptor
581 if(verbose) print("GIF image header\n");
582 i = ReadColorMap(fp, buffer[4], ColorMap); // Read Global Colormap
583 if (i==0) return -3;
584 if (i==2) nColMap++;
585 if(verbose) {
586 if(i==2) print("Global colormap with %i colors \n", 2<<(buffer[4]&0x07));
587 else print("No global colormap provided\n");
588 }
589 filesize += 6 + 7 + 3*256;
590
591 //====================================================
592 // Raster Data of encoded images and Extention Blocks
593 //====================================================
594 iImage = stats = done = 0;
595 while(!stats && !done) {
596 c = fgetc(fp);
597 switch(c) {
598 case EOF: stats=3; break; // unexpected EOF
599
600 case 0x3b: // GIF terminator ";"
601 done =1;
602 if(verbose) print("GIF Terminator\n");
603 break;
604
605 case 0x21: // GIF Extention Block introducer
606 c = fgetc(fp);
607 switch (c) {
608 case EOF : stats=3; break; // unexpected EOF
609 case 0xf9: // "Graphic Control Extension"
610 n = GetDataBlock(fp, buffer); // block is of size 4
611 if (n==4) { // block has to be of size 4
612 DelayTime = getint(buffer+1);
613 if ((buffer[0] & 0x1) != 0) Transparent = buffer[3];
614 if(verbose)
615 print("Graphic Control Extension (delay=%i transparent=%i)\n",
616 DelayTime, Transparent);
617 }
618 while (GetDataBlock(fp, buffer) != 0); // look for block terminator
619 break;
620 case 0xfe: // "Comment Extension"
621 m = (comment ? static_cast<int>(strlen(comment)) : 0);
622 while ((n=GetDataBlock(fp, buffer)) != 0) { // look for block terminator
623 p = Calloc(m+n+1,char);
624 if(m>0) { // if there was a previous comment than whey will be concatinated
625 memcpy(p,comment,m);
626 free(comment);
627 }
628 comment = p;
629 strncpy(comment+m, (char*) buffer, n);
630 m+=n;
631 comment[m]=0;
632 }
633 if(verbose) print("Comment Extension\n");
634 break;
635 case 0xff: // "Software Specific Extension" most likelly NETSCAPE2.0
636 while (GetDataBlock(fp, buffer) != 0); // look for block terminator
637 if(verbose) print("Animation Extension\n");
638 break;
639 case 0x01: // "Plain Text Extension"
640 while (GetDataBlock(fp, buffer) != 0); // look for block terminator
641 if(verbose) print("Plain Text Extension (ignored)\n");
642 break;
643 default: // Any other type of Extension
644 while (GetDataBlock(fp, buffer) != 0); // look for block terminator
645 if(verbose) print("Unknown Extension %i\n", c);
646 break;
647 }
648 break;
649
650 case 0x2c: // Image separator found
651 //====================================
652 // Image Descriptor
653 //====================================
654 if (!fread(buffer, 9, 1, fp)) {stats=3; break;} // unexpected EOF
655 Width = getint(buffer+4); // Byte 6&7: Read the Image width
656 Height = getint(buffer+6); // Byte 8&9: Read the Image height
657 interlace = ((buffer[8]&0x40)==0x40);
658 if(verbose) print("Image [%i x %i]: ", Height, Width);
659 if (!nImage && nBand>0 && (nRow!=Height || nCol!=Width)) {stats=5; break;}
660
661 //=============================================
662 // Local Color Map & Raster Data (LZW encrypted)
663 //=============================================
664 i = ReadColorMap(fp, buffer[8], ColorMap, nColMap*nImage); // Read local Colormap
665 if (i==0) {stats=3; break;} // EOF found during reading local colormap
666 if (i==2) nColMap++;
667 if(image) Free(image);
668 image = Calloc(Height*Width, uchar);
669 ret = DecodeLZW(fp, image, Height*Width);
670 // if (ret==0) {stats=4; break;} // syntax error
671 if(interlace) {
672 int i, row=0;
673 uchar* to = image;
674 uchar* from = new uchar[Width*Height];
675 memcpy(from, to, Width*Height);
676 for (i=0; i<Height; i+=8) memcpy(to+Width*i, from+Width*(row++), Width);
677 for (i=4; i<Height; i+=8) memcpy(to+Width*i, from+Width*(row++), Width);
678 for (i=2; i<Height; i+=4) memcpy(to+Width*i, from+Width*(row++), Width);
679 for (i=1; i<Height; i+=2) memcpy(to+Width*i, from+Width*(row++), Width);
680 delete []from;
681 }
682 if (!nImage) { // save all bands
683 if (!nBand) cube = image; // first image
684 else cube = append(cube, image, Height*Width, nBand);
685 nBand++;
686 } else { // replace each image with new one
687 if(cube) Free(cube);
688 cube = image;
689 nBand = 1;
690 }
691 image = 0;
692 nRow = Height;
693 nCol = Width;
694 if (ret==0) {stats=4; break;} // DecodeLZW exit without finding file terminator
695 else filesize += ret+10;
696 if (++iImage==nImage) done=1;
697 if(verbose) print("%i bytes \n", ret);
698 if(verbose && i==2) print("Local colormap with %i colors \n", 2<<(buffer[4]&0x07));
699 break;
700
701 default:
702 if(verbose) print("Unexpected character %c (%i)\n", c, c);
703 stats=4;
704 break;
705 }
706 } // end while
707 if(verbose) print("\n");
708 *Comment = comment;
709 *data = cube;
710 nRow = Height;
711 nCol = Width;
712 if (nImage==0 && nColMap>1) stats += 6;
713 if (stats) filesize = -stats; // if no image than save error #
714 return filesize;
715 }
716
717
718 //==============================================================
719 // Section below is used in interface with Matrix Library
720 //==============================================================
721 #ifdef MATRIX_INTERFACE
722
imwriteGif(const bMatrix & im,const char * filename,const iMatrix ColorMap,bool interlace,int transparent,int delayTime,char * comment)723 template <> int imwriteGif<uchar>(const bMatrix &im, const char* filename, const iMatrix ColorMap,
724 bool interlace, int transparent, int delayTime, char* comment)
725 {
726 int ret = imwriteGif(filename, im->d(), im->rows(), im->cols(), im->bands(),
727 ColorMap->len(), ColorMap->d(), interlace, transparent, delayTime, comment);
728 if (ret<0) Error("write.gif: cannot open the output GIF file");
729 return ret;
730 }
731
imreadGif(bMatrix & im,const char * filename,iMatrix & ColorMap,int imageNumber)732 int imreadGif(bMatrix &im, const char* filename, iMatrix &ColorMap, int imageNumber)
733 {
734 int nRow, nCol, nBand, transparent, stats, success, nPixel;
735 char *comment=0;
736 uchar* data=0;
737
738 ColorMap->init(256);
739 // initialize data
740 nRow=nCol=nBand=transparent=0;
741 comment = NULL;
742 success = imreadGif(filename, imageNumber, false, &data, nRow, nCol,
743 nBand, ColorMap->d(), transparent, &comment);
744 nPixel = nRow*nCol*nBand;
745 if(comment) Free(comment);
746 stats = -success;
747
748 if (stats>=6) {
749 print("write.gif: file '", filename,
750 "' contains multiple color-maps. Use 'frame' > 0.");
751 stats = stats-6;
752 }
753 if (nPixel==0) {
754 switch (stats) {
755 case 1: Error("write.gif: cannot open the input GIF file");
756 case 2: Error("write.gif: input file is not a GIF file");
757 case 3: Error("write.gif: unexpected end of input GIF file");
758 case 4: Error("write.gif: syntax error in input GIF file");
759 }
760 } else {
761 switch (stats) { // warnings
762 case 3: print("write.gif: unexpected end of input GIF file: ", filename);
763 case 4: print("write.gif: syntax error in input GIF file: ", filename);
764 case 5: print("write.gif: file '", filename,
765 "' contains multiple images (frames) of uneven length. Use 'imageNumber' > 0." );
766 }
767 }
768 im->moveto(data, nRow*nCol*nBand);
769 im->resize(nBand, nRow, nCol);
770 return success;
771 }
772
773 #endif
774
775
776 //==============================================================
777 // Section below is used in standalone test application
778 //==============================================================
779 #ifdef STANDALONE_TEST
780
main()781 int main()
782 {
783 bool interlace;
784 int nRow, nCol, nBand, ColorMap[256], transparent, *Data=0, DelayTime, nImage, succes, n;
785 char *Comment=0, str[256];
786 uchar *data=0;
787
788 interlace = 0;
789 DelayTime = 0;
790 nImage = 0;
791 succes = imreadGif ("bats.gif", nImage, (bool) 1, &data, nRow, nCol, nBand, ColorMap, transparent, &Comment);
792 printf("Image read = [%i x %i x %i]: %i\n",nRow, nCol, nBand, succes);
793 if (1) {
794 n = nRow*nCol;
795 strcpy(str, "hello world");
796 succes = imwriteGif("tmp.gif", data, nRow, nCol, nBand, 256, ColorMap, interlace, transparent, DelayTime, str);
797 printf("Image written = [%i x %i x %i]: %i\n",nRow, nCol, nBand, succes);
798 }
799 printf("Press any key\n");
800 getchar();
801 return 0;
802 }
803
804 #endif
805
806
807
808