]> Creatis software - clitk.git/blob - utilities/CxImage/ximagif.cpp
cosmetic
[clitk.git] / utilities / CxImage / ximagif.cpp
1 /*
2  * File:        ximagif.cpp
3  * Purpose:     Platform Independent GIF Image Class Loader and Writer
4  * 07/Aug/2001 Davide Pizzolato - www.xdp.it
5  * CxImage version 6.0.0 02/Feb/2008
6  */
7
8 #include "ximagif.h"
9
10 #if CXIMAGE_SUPPORT_GIF
11
12 #include "ximaiter.h"
13
14 #if defined (_WIN32_WCE)
15         #define assert(s)
16 #else
17         #include <assert.h>
18 #endif
19
20 ////////////////////////////////////////////////////////////////////////////////
21 #if CXIMAGE_SUPPORT_DECODE
22 ////////////////////////////////////////////////////////////////////////////////
23 bool CxImageGIF::Decode(CxFile *fp)
24 {
25         /* AD - for transparency */
26         struct_dscgif dscgif;
27         struct_image image;
28         struct_TabCol TabCol;
29
30         if (fp == NULL) return false;
31
32         fp->Read(&dscgif,/*sizeof(dscgif)*/13,1);
33         //if (strncmp(dscgif.header,"GIF8",3)!=0) {
34         if (strncmp(dscgif.header,"GIF8",4)!=0) return FALSE;
35
36         // Avoid Byte order problem with Mac <AMSN>
37         dscgif.scrheight = ntohs(dscgif.scrheight);
38         dscgif.scrwidth = ntohs(dscgif.scrwidth);
39
40         if (info.nEscape == -1) {
41                 // Return output dimensions only
42                 head.biWidth = dscgif.scrwidth;
43                 head.biHeight = dscgif.scrheight;
44                 info.dwType = CXIMAGE_FORMAT_GIF;
45                 return true;
46         }
47
48         /* AD - for interlace */
49         TabCol.sogct = (short)(1 << ((dscgif.pflds & 0x07)+1));
50         TabCol.colres = (short)(((dscgif.pflds & 0x70) >> 4) + 1);
51
52         // assume that the image is a truecolor-gif if
53         // 1) no global color map found
54         // 2) (image.w, image.h) of the 1st image != (dscgif.scrwidth, dscgif.scrheight)
55         long bTrueColor=0;
56         CxImage* imaRGB=NULL;
57
58         // Global colour map?
59         if (dscgif.pflds & 0x80)
60                 fp->Read(TabCol.paleta,sizeof(struct rgb_color)*TabCol.sogct,1);
61         else 
62                 bTrueColor++;   //first chance for a truecolor gif
63
64         long first_transparent_index = 0;
65
66         int iImage = 0;
67         info.nNumFrames=get_num_frames(fp,&TabCol,&dscgif);
68
69         if ((info.nFrame<0)||(info.nFrame>=info.nNumFrames)) return false;
70
71         //it cannot be a true color GIF with only one frame
72         if (info.nNumFrames == 1)
73                 bTrueColor=0;
74
75         char ch;
76         bool bPreviousWasNull = true;
77         int  prevdispmeth = 0;
78         CxImage *previousFrame = NULL;
79
80         for (BOOL bContinue = TRUE; bContinue; )
81         {
82                 if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}
83
84                 if (info.nEscape > 0) return false; // <vho> - cancel decoding
85                 if (bPreviousWasNull || ch==0)
86                 {
87                         switch (ch)
88                         {
89                         case '!': // extension
90                                 {
91                                 bContinue = DecodeExtension(fp);
92                                 break;
93                                 }
94                         case ',': // image
95                                 {
96                                 assert(sizeof(image) == 9);
97                                 fp->Read(&image,sizeof(image),1);
98                                 //avoid byte order problems with Solaris <candan> <AMSN>
99                                 image.l = ntohs(image.l);
100                                 image.t = ntohs(image.t);
101                                 image.w = ntohs(image.w);
102                                 image.h = ntohs(image.h);
103
104                                 if (((image.l + image.w) > dscgif.scrwidth)||((image.t + image.h) > dscgif.scrheight))
105                                         break;
106
107                                 // check if it could be a truecolor gif
108                                 if ((iImage==0) && (image.w != dscgif.scrwidth) && (image.h != dscgif.scrheight))
109                                         bTrueColor++;
110
111                                 rgb_color  locpal[256];                         //Local Palette 
112                                 rgb_color* pcurpal = TabCol.paleta;     //Current Palette 
113                                 short palcount = TabCol.sogct;          //Current Palette color count  
114
115                                 // Local colour map?
116                                 if (image.pf & 0x80) {
117                                         palcount = (short)(1 << ((image.pf & 0x07) +1));
118                                         assert(3 == sizeof(struct rgb_color));
119                                         fp->Read(locpal,sizeof(struct rgb_color)*palcount,1);
120                                         pcurpal = locpal;
121                                 }
122
123                                 int bpp; //<DP> select the correct bit per pixel value
124                                 if              (palcount <= 2)  bpp = 1;
125                                 else if (palcount <= 16) bpp = 4;
126                                 else                                     bpp = 8;
127
128                                 CxImageGIF backimage;
129                                 backimage.CopyInfo(*this);
130                                 if (iImage==0){
131                                         //first frame: build image background
132                                         backimage.Create(dscgif.scrwidth, dscgif.scrheight, bpp, CXIMAGE_FORMAT_GIF);
133                                         first_transparent_index = info.nBkgndIndex;
134                                         backimage.Clear((BYTE)gifgce.transpcolindex);
135                                         previousFrame = new CxImage(backimage);
136                                         previousFrame->SetRetreiveAllFrames(false);
137                                 } else {
138                                 //generic frame: handle disposal method from previous one
139                                 /*Values :  0 -   No disposal specified. The decoder is
140                                                                   not required to take any action.
141                                                         1 -   Do not dispose. The graphic is to be left
142                                                                   in place.
143                                                         2 -   Restore to background color. The area used by the
144                                                                   graphic must be restored to the background color.
145                                                         3 -   Restore to previous. The decoder is required to
146                                                                   restore the area overwritten by the graphic with
147                                                                   what was there prior to rendering the graphic.
148                                 */
149                                 /*      backimage.Copy(*this);
150                                         if (prevdispmeth==2){
151                                                 backimage.Clear((BYTE)first_transparent_index);
152                                         }*/
153                                         if (prevdispmeth==2){
154                                                 backimage.Copy(*this,false,false,false);
155                                                 backimage.Clear((BYTE)first_transparent_index);
156                                         } else if (prevdispmeth==3) {
157                                                 backimage.Copy(*this,false,false,false);
158                                                 backimage.Create(previousFrame->GetWidth(),
159                                                         previousFrame->GetHeight(),
160                                                         previousFrame->GetBpp(),CXIMAGE_FORMAT_GIF);
161                                                 memcpy(backimage.GetDIB(),previousFrame->GetDIB(),
162                                                         backimage.GetSize());
163                                                 backimage.AlphaSet(*previousFrame);
164                                         } else {
165                                                 backimage.Copy(*this);
166                                         }
167                                 }
168
169                                 //active frame
170                                 Create(image.w, image.h, bpp, CXIMAGE_FORMAT_GIF);
171
172                                 if ((image.pf & 0x80) || (dscgif.pflds & 0x80)) {
173                                         unsigned char r[256], g[256], b[256];
174                                         int i, has_white = 0;
175
176                                         for (i=0; i < palcount; i++) {
177                                                 r[i] = pcurpal[i].r;
178                                                 g[i] = pcurpal[i].g;
179                                                 b[i] = pcurpal[i].b;
180                                                 if (RGB(r[i],g[i],b[i]) == 0xFFFFFF) has_white = 1;
181                                         }
182
183                                         // Force transparency colour white...
184                                         //if (0) if (info.nBkgndIndex >= 0)
185                                         //      r[info.nBkgndIndex] = g[info.nBkgndIndex] = b[info.nBkgndIndex] = 255;
186                                         // Fill in with white // AD
187                                         if (info.nBkgndIndex >= 0) {
188                                                 while (i < 256) {
189                                                         has_white = 1;
190                                                         r[i] = g[i] = b[i] = 255;
191                                                         i++;
192                                                 }
193                                         }
194
195                                         // Force last colour to white...   // AD
196                                         //if ((info.nBkgndIndex >= 0) && !has_white) {
197                                         //      r[255] = g[255] = b[255] = 255;
198                                         //}
199
200                                         SetPalette((info.nBkgndIndex >= 0 ? 256 : palcount), r, g, b);
201                                 }
202
203                                 CImageIterator* iter = new CImageIterator(this);
204                                 iter->Upset();
205                                 int badcode=0;
206                                 ibf = GIFBUFTAM+1;
207
208                                 interlaced = image.pf & 0x40;
209                                 iheight = image.h;
210                                 istep = 8;
211                                 iypos = 0;
212                                 ipass = 0;
213
214                                 long pos_start = fp->Tell();
215                                 //if (interlaced) log << "Interlaced" << endl;
216                                 decoder(fp, iter, image.w, badcode);
217                                 delete iter;
218
219                                 if (info.nEscape) return false; // <vho> - cancel decoding
220
221                                 if (bTrueColor<2 ){ //standard GIF: mix frame with background
222                                         backimage.GifMix(*this,image);
223                                         backimage.SetTransIndex(first_transparent_index);
224                                         backimage.SetPalette(GetPalette());
225                                         Transfer(backimage,false);
226                                 } else { //it's a truecolor gif!
227                                         //force full image decoding
228                                         info.nFrame=info.nNumFrames-1;
229                                         //build the RGB image
230                                         if (imaRGB==NULL) imaRGB = new CxImage(dscgif.scrwidth,dscgif.scrheight,24,CXIMAGE_FORMAT_GIF);
231                                         //copy the partial image into the full RGB image
232                                         for(long y=0;y<image.h;y++){
233                                                 for (long x=0;x<image.w;x++){
234                                                         imaRGB->SetPixelColor(x+image.l,dscgif.scrheight-1-image.t-y,GetPixelColor(x,image.h-y-1));
235                                                 }
236                                         }
237                                 }
238
239                                 prevdispmeth = (gifgce.flags >> 2) & 0x7;
240
241                                 //restore the correct position in the file for the next image
242                                 if (badcode){
243                                         seek_next_image(fp,pos_start);
244                                 } else {
245                                         fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);
246                                 }
247
248                                 if (info.bGetAllFrames && imaRGB == NULL) {
249                                         if (iImage == 0) {
250                                                 DestroyFrames();
251                                                 ppFrames = new CxImage*[info.nNumFrames];
252                                                 for(int frameIdx = 0; frameIdx < info.nNumFrames; frameIdx++){
253                                                         ppFrames[frameIdx] = NULL;
254                                                 }
255                                         }
256                                         ppFrames[iImage] = new CxImage(*this);
257                                         ppFrames[iImage]->SetRetreiveAllFrames(false);
258                                 }
259                                 if (prevdispmeth <= 1) {
260                                         delete previousFrame;
261                                         previousFrame = new CxImage(*this);
262                                         previousFrame->SetRetreiveAllFrames(false);
263                                 }
264
265                                 if (info.nFrame==iImage) bContinue=false; else iImage++;
266
267                                 break;
268                                 }
269                         case ';': //terminator
270                                 bContinue=false;
271                                 break;
272                         default:
273                                 bPreviousWasNull = (ch==0);
274                                 break;
275                         }
276                 }
277         }
278
279         if (bTrueColor>=2 && imaRGB){
280                 if (gifgce.flags & 0x1){
281                         imaRGB->SetTransColor(GetPaletteColor((BYTE)info.nBkgndIndex));
282                         imaRGB->SetTransIndex(0);
283                 }
284                 Transfer(*imaRGB);
285         }
286         delete imaRGB;
287
288         delete previousFrame;
289
290         return true;
291
292 }
293 ////////////////////////////////////////////////////////////////////////////////
294 bool CxImageGIF::DecodeExtension(CxFile *fp)
295 {
296         bool bContinue;
297         unsigned char count;
298         unsigned char fc;
299
300         bContinue = (1 == fp->Read(&fc, sizeof(fc), 1));
301         if (bContinue) {
302                 /* AD - for transparency */
303                 if (fc == 0xF9) {
304                         bContinue = (1 == fp->Read(&count, sizeof(count), 1));
305                         if (bContinue) {
306                                 assert(sizeof(gifgce) == 4);
307                                 bContinue = (count == fp->Read(&gifgce, 1, sizeof(gifgce)));
308                                 gifgce.delaytime = ntohs(gifgce.delaytime); // Avoid Byte order problem with Mac <AMSN>
309                                 if (bContinue) {
310                                         info.nBkgndIndex  = (gifgce.flags & 0x1) ? gifgce.transpcolindex : -1;
311                                         info.dwFrameDelay = gifgce.delaytime;
312                                         SetDisposalMethod((gifgce.flags >> 2) & 0x7);
313                 }       }       }
314
315                 if (fc == 0xFE) { //<DP> Comment block
316                         bContinue = (1 == fp->Read(&count, sizeof(count), 1));
317                         if (bContinue) {
318                                 bContinue = (1 == fp->Read(m_comment, count, 1));
319                                 m_comment[count]='\0';
320                 }       }
321
322                 if (fc == 0xFF) { //<DP> Application Extension block
323                         bContinue = (1 == fp->Read(&count, sizeof(count), 1));
324                         if (bContinue) {
325                                 bContinue = (count==11);
326                                 if (bContinue){
327                                         char AppID[11];
328                                         bContinue = (1 == fp->Read(AppID, count, 1));
329                                         if (bContinue) {
330                                                 bContinue = (1 == fp->Read(&count, sizeof(count), 1));
331                                                 if (bContinue) {
332                                                         BYTE* dati = (BYTE*)malloc(count);
333                                                         bContinue = (dati!=NULL);
334                                                         if (bContinue){
335                                                                 bContinue = (1 == fp->Read(dati, count, 1));
336                                                                 if (count>2){
337                                                                         m_loops = dati[1]+256*dati[2];
338                                                                 }
339                                                         }
340                                                         free(dati);
341                 }       }       }       }       }
342
343                 while (bContinue && fp->Read(&count, sizeof(count), 1) && count) {
344                         //log << "Skipping " << count << " bytes" << endl;
345                         fp->Seek(count, SEEK_CUR);
346                 }
347         }
348         return bContinue;
349
350 }
351 ////////////////////////////////////////////////////////////////////////////////
352 #endif //CXIMAGE_SUPPORT_DECODE
353 ////////////////////////////////////////////////////////////////////////////////
354
355 //   - This external (machine specific) function is expected to return
356 // either the next BYTE from the GIF file, or a negative error number.
357 int CxImageGIF::get_byte(CxFile* file)
358 {
359         if (ibf>=GIFBUFTAM){
360                 // FW 06/02/98 >>>
361                 ibfmax = (int)file->Read( buf , 1 , GIFBUFTAM) ;
362                 if( ibfmax < GIFBUFTAM ) buf[ ibfmax ] = 255 ;
363                 // FW 06/02/98 <<<
364                 ibf = 0;
365         }
366         if (ibf>=ibfmax) return -1; //<DP> avoid overflows
367         return buf[ibf++];
368 }
369 ////////////////////////////////////////////////////////////////////////////////
370 /*   - This function takes a full line of pixels (one BYTE per pixel) and
371  * displays them (or does whatever your program wants with them...).  It
372  * should return zero, or negative if an error or some other event occurs
373  * which would require aborting the decode process...  Note that the length
374  * passed will almost always be equal to the line length passed to the
375  * decoder function, with the sole exception occurring when an ending code
376  * occurs in an odd place in the GIF file...  In any case, linelen will be
377  * equal to the number of pixels passed...
378 */
379 int CxImageGIF::out_line(CImageIterator* iter, unsigned char *pixels, int linelen)
380 {
381         if (iter == NULL || pixels == NULL)
382                 return -1;
383
384         //<DP> for 1 & 4 bpp images, the pixels are compressed
385         if (head.biBitCount < 8){
386                 for(long x=0;x<head.biWidth;x++){
387                         BYTE pos;
388                         BYTE* iDst= pixels + (x*head.biBitCount >> 3);
389                         if (head.biBitCount==4){
390                                 pos = (BYTE)(4*(1-x%2));
391                                 *iDst &= ~(0x0F<<pos);
392                                 *iDst |= ((pixels[x] & 0x0F)<<pos);
393                         } else if (head.biBitCount==1){
394                                 pos = (BYTE)(7-x%8);
395                                 *iDst &= ~(0x01<<pos);
396                                 *iDst |= ((pixels[x] & 0x01)<<pos);
397                         }
398                 }
399         }
400
401         /* AD - for interlace */
402         if (interlaced) {
403                 iter->SetY(iheight-iypos-1);
404                 iter->SetRow(pixels, linelen);
405
406                 if ((iypos += istep) >= iheight) {
407                         do {
408                                 if (ipass++ > 0) istep /= 2;
409                                 iypos = istep / 2;
410                         }
411                         while (iypos > iheight);
412                 }
413                 return 0;
414         } else {
415                 if (iter->ItOK()) {
416                         iter->SetRow(pixels, linelen);
417                         (void)iter->PrevRow();
418                         return 0;
419                 } else {
420                         //       puts("chafeo");
421                         return -1;
422                 }
423         }
424 }
425 ////////////////////////////////////////////////////////////////////////////////
426 #if CXIMAGE_SUPPORT_ENCODE
427 ////////////////////////////////////////////////////////////////////////////////
428 // SaveFile - writes GIF87a gif file
429 // Randy Spann 6/15/97
430 // R.Spann@ConnRiver.net
431 bool CxImageGIF::Encode(CxFile * fp)
432 {
433         if (EncodeSafeCheck(fp)) return false;
434
435         if(head.biBitCount > 8) {
436                 //strcpy(info.szLastError,"GIF Images must be 8 bit or less");
437                 //return FALSE;
438                 return EncodeRGB(fp);
439         }
440
441         if ( GetNumFrames()>1 && ppFrames ) {
442                 return Encode(fp, ppFrames, GetNumFrames() );
443         }
444
445         EncodeHeader(fp);
446
447         EncodeExtension(fp);
448
449         EncodeComment(fp);
450
451         EncodeBody(fp);
452
453         fp->PutC(';'); // Write the GIF file terminator
454
455         return true; // done!
456 }
457 ////////////////////////////////////////////////////////////////////////////////
458 bool CxImageGIF::Encode(CxFile * fp, CxImage ** pImages, int pagecount, bool bLocalColorMap, bool bLocalDispMeth)
459 {
460   cx_try {
461         if (fp==NULL) cx_throw("invalid file pointer");
462         if (pImages==NULL || pagecount<=0 || pImages[0]==NULL) cx_throw("multipage GIF, no images!");
463
464         int i;
465         for (i=0; i<pagecount; i++){
466                 if (pImages[i]==NULL)
467                         cx_throw("Bad image pointer");
468                 if (!(pImages[i]->IsValid()))
469                         cx_throw("Empty image");
470                 if (pImages[i]->GetNumColors()==0)
471                         cx_throw("CxImageGIF::Encode cannot create animated GIFs with a true color frame. Use DecreaseBpp before");
472         }
473
474         CxImageGIF ghost;
475
476         //write the first image
477         ghost.Ghost(pImages[0]);
478         ghost.EncodeHeader(fp);
479
480         if (m_loops!=1){
481                 ghost.SetLoops(max(0,m_loops-1));
482                 ghost.EncodeLoopExtension(fp);
483         }
484
485         if (bLocalDispMeth) {
486                 ghost.EncodeExtension(fp);
487         } else {
488                 BYTE dm = ghost.GetDisposalMethod();
489                 ghost.SetDisposalMethod(GetDisposalMethod());
490                 ghost.EncodeExtension(fp);
491                 ghost.SetDisposalMethod(dm);
492         }
493
494         EncodeComment(fp);
495
496         ghost.EncodeBody(fp);
497
498         for (i=1; i<pagecount; i++){
499                 ghost.Ghost(pImages[i]);
500
501                 if (bLocalDispMeth) {
502                         ghost.EncodeExtension(fp);
503                 } else {
504                         BYTE dm = ghost.GetDisposalMethod();
505                         ghost.SetDisposalMethod(GetDisposalMethod());
506                         ghost.EncodeExtension(fp);
507                         ghost.SetDisposalMethod(dm);
508                 }
509
510                 ghost.EncodeBody(fp,bLocalColorMap);
511         }
512
513         fp->PutC(';'); // Write the GIF file terminator
514
515   } cx_catch {
516           if (strcmp(message,"")) strncpy(info.szLastError,message,255);
517           return false;
518   }
519         return true;
520 }
521 ////////////////////////////////////////////////////////////////////////////////
522 void CxImageGIF::EncodeHeader(CxFile *fp)
523 {
524         fp->Write("GIF89a",1,6);           //GIF Header
525
526         Putword(head.biWidth,fp);                          //Logical screen descriptor
527         Putword(head.biHeight,fp);
528
529         BYTE Flags;
530         if (head.biClrUsed==0){
531                 Flags=0x11;
532         } else {
533                 Flags = 0x80;
534                 Flags |=(head.biBitCount - 1) << 5;
535                 Flags |=(head.biBitCount - 1);
536         }
537
538         fp->PutC(Flags); //GIF "packed fields"
539         fp->PutC(0);     //GIF "BackGround"
540         fp->PutC(0);     //GIF "pixel aspect ratio"
541
542         if (head.biClrUsed!=0){
543                 RGBQUAD* pPal = GetPalette();
544                 for(DWORD i=0; i<head.biClrUsed; ++i) 
545                 {
546                         fp->PutC(pPal[i].rgbRed);
547                         fp->PutC(pPal[i].rgbGreen);
548                         fp->PutC(pPal[i].rgbBlue);
549                 }
550         }
551 }
552 ////////////////////////////////////////////////////////////////////////////////
553 void CxImageGIF::EncodeExtension(CxFile *fp)
554 {
555         // TRK BEGIN : transparency
556         fp->PutC('!');
557         fp->PutC(TRANSPARENCY_CODE);
558
559         gifgce.flags = 0;
560         gifgce.flags |= ((info.nBkgndIndex != -1) ? 1 : 0);
561         gifgce.flags |= ((GetDisposalMethod() & 0x7) << 2);
562         gifgce.delaytime = (WORD)info.dwFrameDelay;
563         gifgce.transpcolindex = (BYTE)info.nBkgndIndex;    
564
565         //Invert byte order in case we use a byte order arch, then set it back <AMSN>
566         gifgce.delaytime = ntohs(gifgce.delaytime);
567         fp->PutC(sizeof(gifgce));
568         fp->Write(&gifgce, sizeof(gifgce), 1);
569         gifgce.delaytime = ntohs(gifgce.delaytime);
570
571         fp->PutC(0);
572         // TRK END
573 }
574 ////////////////////////////////////////////////////////////////////////////////
575 void CxImageGIF::EncodeLoopExtension(CxFile *fp)
576 {
577         fp->PutC('!');          //byte  1  : 33 (hex 0x21) GIF Extension code
578         fp->PutC(255);          //byte  2  : 255 (hex 0xFF) Application Extension Label
579         fp->PutC(11);           //byte  3  : 11 (hex (0x0B) Length of Application Block (eleven bytes of data to follow)
580         fp->Write("NETSCAPE2.0",11,1);
581         fp->PutC(3);                    //byte 15  : 3 (hex 0x03) Length of Data Sub-Block (three bytes of data to follow)
582         fp->PutC(1);                    //byte 16  : 1 (hex 0x01)
583         Putword(m_loops,fp); //bytes 17 to 18 : 0 to 65535, an unsigned integer in lo-hi byte format. 
584                                                 //This indicate the number of iterations the loop should be executed.
585         fp->PutC(0);                    //bytes 19       : 0 (hex 0x00) a Data Sub-block Terminator. 
586 }
587 ////////////////////////////////////////////////////////////////////////////////
588 void CxImageGIF::EncodeBody(CxFile *fp, bool bLocalColorMap)
589 {
590         curx = 0;
591         cury = head.biHeight - 1;       //because we read the image bottom to top
592         CountDown = (long)head.biWidth * (long)head.biHeight;
593
594         fp->PutC(',');
595
596         Putword(info.xOffset,fp);
597         Putword(info.yOffset,fp);
598         Putword(head.biWidth,fp);
599         Putword(head.biHeight,fp);
600
601         BYTE Flags=0x00; //non-interlaced (0x40 = interlaced) (0x80 = LocalColorMap)
602         if (bLocalColorMap)     { Flags|=0x80; Flags|=head.biBitCount-1; }
603         fp->PutC(Flags);
604
605         if (bLocalColorMap){
606                 Flags|=0x87;
607                 RGBQUAD* pPal = GetPalette();
608                 for(DWORD i=0; i<head.biClrUsed; ++i) 
609                 {
610                         fp->PutC(pPal[i].rgbRed);
611                         fp->PutC(pPal[i].rgbGreen);
612                         fp->PutC(pPal[i].rgbBlue);
613                 }
614         }
615
616         int InitCodeSize = head.biBitCount <=1 ? 2 : head.biBitCount;
617          // Write out the initial code size
618         fp->PutC((BYTE)InitCodeSize);
619
620          // Go and actually compress the data
621         switch (GetCodecOption(CXIMAGE_FORMAT_GIF))
622         {
623         case 1: //uncompressed
624                 compressNONE(InitCodeSize+1, fp);
625                 break;
626         case 2: //RLE
627                 compressRLE(InitCodeSize+1, fp);
628                 break;
629         default: //LZW
630                 compressLZW(InitCodeSize+1, fp);
631         }
632
633          // Write out a Zero-length packet (to end the series)
634         fp->PutC(0);
635 }
636 ////////////////////////////////////////////////////////////////////////////////
637 void CxImageGIF::EncodeComment(CxFile *fp)
638 {
639         unsigned long n = (unsigned long) strlen(m_comment);
640         if (n>255) n=255;
641         if (n) {
642                 fp->PutC('!');  //extension code:
643                 fp->PutC(254);  //comment extension
644                 fp->PutC((BYTE)n);      //size of comment
645                 fp->Write(m_comment,n,1);
646                 fp->PutC(0);    //block terminator
647         }
648 }
649 ////////////////////////////////////////////////////////////////////////////////
650 bool CxImageGIF::EncodeRGB(CxFile *fp)
651 {
652         EncodeHeader(fp);
653
654 //      EncodeLoopExtension(fp);
655
656         EncodeComment(fp);
657
658         unsigned long w,h;
659         w=h=0;
660         const long cellw = 17;
661         const long cellh = 15;
662         CxImageGIF tmp;
663         for (long y=0;y<head.biHeight;y+=cellh){
664                 for (long x=0;x<head.biWidth;x+=cellw){
665                         if ((head.biWidth -x)<cellw) w=head.biWidth -x; else w=cellw;
666                         if ((head.biHeight-y)<cellh) h=head.biHeight-y; else h=cellh;
667
668                         if (w!=tmp.GetWidth() || h!=tmp.GetHeight()) tmp.Create(w,h,8);
669
670                         if (IsTransparent()){
671                                 tmp.SetTransIndex(0);
672                                 tmp.SetPaletteColor(0,GetTransColor());
673                         }
674
675                         BYTE i;
676                         for (unsigned long j=0;j<h;j++){
677                                 for (unsigned long k=0;k<w;k++){
678                                         i=(BYTE)(1+k+cellw*j);
679                                         tmp.SetPaletteColor(i,GetPixelColor(x+k,head.biHeight-y-h+j));
680                                         tmp.SetPixelIndex(k,j,tmp.GetNearestIndex(tmp.GetPaletteColor(i)));
681                                 }
682                         }
683
684                         tmp.SetOffset(x,y);
685                         tmp.EncodeExtension(fp);
686                         tmp.EncodeBody(fp,true);
687                 }
688         }
689
690         fp->PutC(';'); // Write the GIF file terminator
691
692         return true; // done!
693 }
694 ////////////////////////////////////////////////////////////////////////////////
695 #endif // CXIMAGE_SUPPORT_ENCODE
696 ////////////////////////////////////////////////////////////////////////////////
697 // Return the next pixel from the image
698 // <DP> fix for 1 & 4 bpp images
699 int CxImageGIF::GifNextPixel( )
700 {
701         if( CountDown == 0 ) return EOF;
702         --CountDown;
703         int r = GetPixelIndex(curx,cury);
704         // Bump the current X position
705         ++curx;
706         if( curx == head.biWidth ){
707                 curx = 0;
708                 cury--;              //bottom to top
709         }
710         return r;
711 }
712 ////////////////////////////////////////////////////////////////////////////////
713 void CxImageGIF::Putword(int w, CxFile *fp )
714 {
715         fp->PutC((BYTE)(w & 0xff));
716         fp->PutC((BYTE)((w >> 8) & 0xff));
717 }
718 ////////////////////////////////////////////////////////////////////////////////
719 void CxImageGIF::compressNONE( int init_bits, CxFile* outfile)
720 {
721         register long c;
722         register long ent;
723
724         // g_init_bits - initial number of bits
725         // g_outfile   - pointer to output file
726         g_init_bits = init_bits;
727         g_outfile = outfile;
728
729          // Set up the necessary values
730         cur_accum = cur_bits = clear_flg = 0;
731         maxcode = (short)MAXCODE(n_bits = g_init_bits);
732         code_int maxmaxcode = (code_int)1 << MAXBITSCODES;
733
734         ClearCode = (1 << (init_bits - 1));
735         EOFCode = ClearCode + 1;
736         free_ent = (short)(ClearCode + 2);
737
738         a_count=0;
739         ent = GifNextPixel( );
740
741         output( (code_int)ClearCode );
742
743         while ( ent != EOF ) {    
744                 c = GifNextPixel();
745
746                 output ( (code_int) ent );
747                 ent = c;
748                 if ( free_ent < maxmaxcode ) {  
749                         free_ent++;
750                 } else {
751                         free_ent=(short)(ClearCode+2);
752                         clear_flg=1;
753                         output((code_int)ClearCode);
754                 }
755         }
756          // Put out the final code.
757         output( (code_int) EOFCode );
758 }
759 ////////////////////////////////////////////////////////////////////////////////
760
761 /***************************************************************************
762  *
763  *  GIFCOMPR.C       -     LZW GIF Image compression routines
764  *
765  ***************************************************************************/
766
767 void CxImageGIF::compressLZW( int init_bits, CxFile* outfile)
768 {
769         register long fcode;
770         register long c;
771         register long ent;
772         register long hshift;
773         register long disp;
774         register long i;
775
776         // g_init_bits - initial number of bits
777         // g_outfile   - pointer to output file
778         g_init_bits = init_bits;
779         g_outfile = outfile;
780
781          // Set up the necessary values
782         cur_accum = cur_bits = clear_flg = 0;
783         maxcode = (short)MAXCODE(n_bits = g_init_bits);
784         code_int maxmaxcode = (code_int)1 << MAXBITSCODES;
785
786         ClearCode = (1 << (init_bits - 1));
787         EOFCode = ClearCode + 1;
788         free_ent = (short)(ClearCode + 2);
789
790         a_count=0;
791         ent = GifNextPixel( );
792
793         hshift = 0;
794         for ( fcode = (long) HSIZE;  fcode < 65536L; fcode *= 2L )      ++hshift;
795         hshift = 8 - hshift;                /* set hash code range bound */
796         cl_hash((long)HSIZE);        /* clear hash table */
797         output( (code_int)ClearCode );
798
799         while ( (c = GifNextPixel( )) != EOF ) {    
800
801                 fcode = (long) (((long) c << MAXBITSCODES) + ent);
802                 i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
803
804                 if ( HashTabOf (i) == fcode ) {
805                         ent = CodeTabOf (i);
806                         continue;
807                 } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
808                         goto nomatch;
809                 disp = HSIZE - i;           /* secondary hash (after G. Knott) */
810                 if ( i == 0 )   disp = 1;
811 probe:
812                 if ( (i -= disp) < 0 )  i += HSIZE;
813                 if ( HashTabOf (i) == fcode ) { ent = CodeTabOf (i); continue; }
814                 if ( (long)HashTabOf (i) > 0 )  goto probe;
815 nomatch:
816                 output ( (code_int) ent );
817                 ent = c;
818                 if ( free_ent < maxmaxcode ) {  
819                         CodeTabOf (i) = free_ent++; /* code -> hashtable */
820                         HashTabOf (i) = fcode;
821                 } else {
822                         cl_hash((long)HSIZE);
823                         free_ent=(short)(ClearCode+2);
824                         clear_flg=1;
825                         output((code_int)ClearCode);
826                 }
827         }
828          // Put out the final code.
829         output( (code_int)ent );
830         output( (code_int) EOFCode );
831 }
832 ////////////////////////////////////////////////////////////////////////////////
833
834 static const unsigned long code_mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
835                                                                   0x001F, 0x003F, 0x007F, 0x00FF,
836                                                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
837                                                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
838
839 ////////////////////////////////////////////////////////////////////////////////
840 void CxImageGIF::output( code_int  code)
841 {
842         cur_accum &= code_mask[ cur_bits ];
843
844         if( cur_bits > 0 )
845                 cur_accum |= ((long)code << cur_bits);
846         else
847                 cur_accum = code;
848
849         cur_bits += n_bits;
850
851         while( cur_bits >= 8 ) {
852                 char_out( (unsigned int)(cur_accum & 0xff) );
853                 cur_accum >>= 8;
854                 cur_bits -= 8;
855         }
856
857         /*
858          * If the next entry is going to be too big for the code size,
859          * then increase it, if possible.
860          */
861
862         if ( free_ent > maxcode || clear_flg ) {
863                 if( clear_flg ) {
864                         maxcode = (short)MAXCODE(n_bits = g_init_bits);
865                         clear_flg = 0;
866                 } else {
867                         ++n_bits;
868                         if ( n_bits == MAXBITSCODES )
869                                 maxcode = (code_int)1 << MAXBITSCODES; /* should NEVER generate this code */
870                         else
871                                 maxcode = (short)MAXCODE(n_bits);
872                 }
873         }
874         
875         if( code == EOFCode ) {
876                  // At EOF, write the rest of the buffer.
877                 while( cur_bits > 0 ) {
878                         char_out( (unsigned int)(cur_accum & 0xff) );
879                         cur_accum >>= 8;
880                         cur_bits -= 8;
881                 }
882         
883                 flush_char();
884                 g_outfile->Flush();
885
886                 if(g_outfile->Error()) strcpy(info.szLastError,"Write Error in GIF file");
887         }
888 }
889 ////////////////////////////////////////////////////////////////////////////////
890
891 void CxImageGIF::cl_hash(long hsize)
892
893 {
894         register long *htab_p = htab+hsize;
895
896         register long i;
897         register long m1 = -1L;
898
899         i = hsize - 16;
900
901         do {
902                 *(htab_p-16)=m1;
903                 *(htab_p-15)=m1;
904                 *(htab_p-14)=m1;
905                 *(htab_p-13)=m1;
906                 *(htab_p-12)=m1;
907                 *(htab_p-11)=m1;
908                 *(htab_p-10)=m1;
909                 *(htab_p-9)=m1;
910                 *(htab_p-8)=m1;
911                 *(htab_p-7)=m1;
912                 *(htab_p-6)=m1;
913                 *(htab_p-5)=m1;
914                 *(htab_p-4)=m1;
915                 *(htab_p-3)=m1;
916                 *(htab_p-2)=m1;
917                 *(htab_p-1)=m1;
918                 
919                 htab_p-=16;
920         } while ((i-=16) >=0);
921
922         for (i+=16;i>0;--i)
923                 *--htab_p=m1;
924 }
925
926 /*******************************************************************************
927 *   GIF specific
928 *******************************************************************************/
929
930 void CxImageGIF::char_out(int c)
931 {
932         accum[a_count++]=(char)c;
933         if (a_count >=254)
934                 flush_char();
935 }
936
937 void CxImageGIF::flush_char()
938 {
939         if (a_count > 0) {
940                 g_outfile->PutC((BYTE)a_count);
941                 g_outfile->Write(accum,1,a_count);
942                 a_count=0;
943         }
944 }
945
946 /*******************************************************************************
947 *   GIF decoder
948 *******************************************************************************/
949 /* DECODE.C - An LZW decoder for GIF
950  * Copyright (C) 1987, by Steven A. Bennett
951  * Copyright (C) 1994, C++ version by Alejandro Aguilar Sierra
952 *
953  * Permission is given by the author to freely redistribute and include
954  * this code in any program as long as this credit is given where due.
955  *
956  * In accordance with the above, I want to credit Steve Wilhite who wrote
957  * the code which this is heavily inspired by...
958  *
959  * GIF and 'Graphics Interchange Format' are trademarks (tm) of
960  * Compuserve, Incorporated, an H&R Block Company.
961  *
962  * Release Notes: This file contains a decoder routine for GIF images
963  * which is similar, structurally, to the original routine by Steve Wilhite.
964  * It is, however, somewhat noticably faster in most cases.
965  *
966  */
967
968 ////////////////////////////////////////////////////////////////////////////////
969
970 short CxImageGIF::init_exp(short size)
971 {
972         curr_size = (short)(size + 1);
973         top_slot = (short)(1 << curr_size);
974         clear = (short)(1 << size);
975         ending = (short)(clear + 1);
976         slot = newcodes = (short)(ending + 1);
977         navail_bytes = nbits_left = 0;
978
979         memset(stack,0,MAX_CODES + 1);
980         memset(prefix,0,MAX_CODES + 1);
981         memset(suffix,0,MAX_CODES + 1);
982         return(0);
983 }
984 ////////////////////////////////////////////////////////////////////////////////
985
986 /* get_next_code()
987  * - gets the next code from the GIF file.  Returns the code, or else
988  * a negative number in case of file errors...
989  */
990 short CxImageGIF::get_next_code(CxFile* file)
991 {
992         short i, x;
993         DWORD ret;
994
995         if (nbits_left == 0) {
996                 if (navail_bytes <= 0) {
997                         /* Out of bytes in current block, so read next block */
998                         pbytes = byte_buff;
999                         if ((navail_bytes = (short)get_byte(file)) < 0)
1000                                 return(navail_bytes);
1001                         else if (navail_bytes) {
1002                                 for (i = 0; i < navail_bytes; ++i) {
1003                                         if ((x = (short)get_byte(file)) < 0) return(x);
1004                                         byte_buff[i] = (BYTE)x;
1005                                 }
1006                         }
1007                 }
1008                 b1 = *pbytes++;
1009                 nbits_left = 8;
1010                 --navail_bytes;
1011         }
1012
1013         if (navail_bytes<0) return ending; // prevent deadlocks (thanks to Mike Melnikov)
1014
1015         ret = b1 >> (8 - nbits_left);
1016         while (curr_size > nbits_left){
1017                 if (navail_bytes <= 0){
1018                         /* Out of bytes in current block, so read next block*/
1019                         pbytes = byte_buff;
1020                         if ((navail_bytes = (short)get_byte(file)) < 0)
1021                                 return(navail_bytes);
1022                         else if (navail_bytes){
1023                                 for (i = 0; i < navail_bytes; ++i){
1024                                         if ((x = (short)get_byte(file)) < 0) return(x);
1025                                         byte_buff[i] = (BYTE)x;
1026                                 }
1027                         }
1028                 }
1029                 b1 = *pbytes++;
1030                 ret |= b1 << nbits_left;
1031                 nbits_left += 8;
1032                 --navail_bytes;
1033         }
1034         nbits_left = (short)(nbits_left-curr_size);
1035         ret &= code_mask[curr_size];
1036         return((short)(ret));
1037 }
1038 ////////////////////////////////////////////////////////////////////////////////
1039
1040 /* short decoder(linewidth)
1041  *    short linewidth;               * Pixels per line of image *
1042  *
1043  * - This function decodes an LZW image, according to the method used
1044  * in the GIF spec.  Every *linewidth* "characters" (ie. pixels) decoded
1045  * will generate a call to out_line(), which is a user specific function
1046  * to display a line of pixels.  The function gets it's codes from
1047  * get_next_code() which is responsible for reading blocks of data and
1048  * seperating them into the proper size codes.  Finally, get_byte() is
1049  * the global routine to read the next BYTE from the GIF file.
1050  *
1051  * It is generally a good idea to have linewidth correspond to the actual
1052  * width of a line (as specified in the Image header) to make your own
1053  * code a bit simpler, but it isn't absolutely necessary.
1054  *
1055  * Returns: 0 if successful, else negative.  (See ERRS.H)
1056  *
1057  */
1058 /* bad_code_count is incremented each time an out of range code is read.
1059  * When this value is non-zero after a decode, your GIF file is probably
1060  * corrupt in some way...
1061  */
1062 short CxImageGIF::decoder(CxFile* file, CImageIterator* iter, short linewidth, int &bad_code_count)
1063 {
1064         register BYTE *sp, *bufptr;
1065         BYTE *buf;
1066         register short code, fc, oc, bufcnt;
1067         short c, size, ret;
1068
1069         /* Initialize for decoding a new image... */
1070         bad_code_count = 0;
1071         if ((size = (short)get_byte(file)) < 0) return(size);
1072         if (size < 2 || 9 < size)                               return(BAD_CODE_SIZE);
1073         // out_line = outline;
1074         init_exp(size);
1075         //printf("L %d %x\n",linewidth,size);
1076
1077         /* Initialize in case they forgot to put in a clear code.
1078          * (This shouldn't happen, but we'll try and decode it anyway...)
1079          */
1080         oc = fc = 0;
1081
1082    /* Allocate space for the decode buffer */
1083         if ((buf = new BYTE[linewidth + 1]) == NULL) return(OUT_OF_MEMORY);
1084
1085    /* Set up the stack pointer and decode buffer pointer */
1086         sp = stack;
1087         bufptr = buf;
1088         bufcnt = linewidth;
1089
1090    /* This is the main loop.  For each code we get we pass through the
1091         * linked list of prefix codes, pushing the corresponding "character" for
1092         * each code onto the stack.  When the list reaches a single "character"
1093         * we push that on the stack too, and then start unstacking each
1094     * character for output in the correct order.  Special handling is
1095         * included for the clear code, and the whole thing ends when we get
1096     * an ending code.
1097     */
1098         while ((c = get_next_code(file)) != ending) {
1099                 /* If we had a file error, return without completing the decode*/
1100                 if (c < 0){
1101                         delete [] buf;
1102                         return(0);
1103                 }
1104                 /* If the code is a clear code, reinitialize all necessary items.*/
1105                 if (c == clear){
1106                         curr_size = (short)(size + 1);
1107                         slot = newcodes;
1108                         top_slot = (short)(1 << curr_size);
1109
1110                         /* Continue reading codes until we get a non-clear code
1111                         * (Another unlikely, but possible case...)
1112                         */
1113                         while ((c = get_next_code(file)) == clear);
1114
1115                         /* If we get an ending code immediately after a clear code
1116                         * (Yet another unlikely case), then break out of the loop.
1117                         */
1118                         if (c == ending) break;
1119
1120                         /* Finally, if the code is beyond the range of already set codes,
1121                         * (This one had better NOT happen...  I have no idea what will
1122                         * result from this, but I doubt it will look good...) then set it
1123                         * to color zero.
1124                         */
1125                         if (c >= slot) c = 0;
1126                         oc = fc = c;
1127
1128                         /* And let us not forget to put the char into the buffer... And
1129                         * if, on the off chance, we were exactly one pixel from the end
1130                         * of the line, we have to send the buffer to the out_line()
1131                         * routine...
1132                         */
1133                         *bufptr++ = (BYTE)c;
1134                         if (--bufcnt == 0) {
1135                                 if (iter) {
1136                                         if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {
1137                                                 delete [] buf;
1138                                                 return(ret);
1139                                         }
1140                                 }
1141                                 bufptr = buf;
1142                                 bufcnt = linewidth;
1143             }
1144                 } else {
1145                         /* In this case, it's not a clear code or an ending code, so
1146                         * it must be a code code...  So we can now decode the code into
1147                         * a stack of character codes. (Clear as mud, right?)
1148                         */
1149                         code = c;
1150
1151                         /* Here we go again with one of those off chances...  If, on the
1152                         * off chance, the code we got is beyond the range of those already
1153                         * set up (Another thing which had better NOT happen...) we trick
1154                         * the decoder into thinking it actually got the last code read.
1155                         * (Hmmn... I'm not sure why this works...  But it does...)
1156                         */
1157                         if (code >= slot && sp<(stack+MAX_CODES-1)) {
1158                                 if (code > slot)
1159                                         ++bad_code_count;
1160                                 code = oc;
1161                                 *sp++ = (BYTE)fc;
1162             }
1163
1164                         /* Here we scan back along the linked list of prefixes, pushing
1165                         * helpless characters (ie. suffixes) onto the stack as we do so.
1166                         */
1167                         while (code >= newcodes && sp<(stack+MAX_CODES-1)) {
1168                                 *sp++ = suffix[code];
1169                                 code = prefix[code];
1170             }
1171
1172                         /* Push the last character on the stack, and set up the new
1173                         * prefix and suffix, and if the required slot number is greater
1174                         * than that allowed by the current bit size, increase the bit
1175                         * size.  (NOTE - If we are all full, we *don't* save the new
1176                         * suffix and prefix...  I'm not certain if this is correct...
1177                         * it might be more proper to overwrite the last code...
1178                         */
1179                         *sp++ = (BYTE)code;
1180                         if (slot < top_slot){
1181                                 suffix[slot] = (BYTE)(fc = (BYTE)code);
1182                                 prefix[slot++] = oc;
1183                                 oc = c;
1184             }
1185                         if (slot >= top_slot){
1186                                 if (curr_size < 12) {
1187                                         top_slot <<= 1;
1188                                         ++curr_size;
1189                                 }
1190                         }
1191
1192                         /* Now that we've pushed the decoded string (in reverse order)
1193                         * onto the stack, lets pop it off and put it into our decode
1194                         * buffer...  And when the decode buffer is full, write another
1195                         * line...
1196                         */
1197                         while (sp > stack) {
1198                                 *bufptr++ = *(--sp);
1199                                 if (--bufcnt == 0) {
1200                                         if (iter) {
1201                                                 if ((ret = (short)out_line(iter, buf, linewidth)) < 0) {
1202                                                         delete [] buf;
1203                                                         return(ret);
1204                                                 }
1205                                         }
1206                                         bufptr = buf;
1207                                         bufcnt = linewidth;
1208                                 }
1209                         }
1210                 }
1211         }
1212         ret = 0;
1213         if (bufcnt != linewidth && iter)
1214                 ret = (short)out_line(iter, buf, (linewidth - bufcnt));
1215         delete [] buf;
1216         return(ret);
1217 }
1218 ////////////////////////////////////////////////////////////////////////////////
1219 int CxImageGIF::get_num_frames(CxFile *fp,struct_TabCol* TabColSrc,struct_dscgif* dscgif)
1220 {
1221         struct_image image;
1222
1223         long pos=fp->Tell();
1224         int nframes=0;
1225
1226         struct_TabCol TempTabCol;
1227         memcpy(&TempTabCol,TabColSrc,sizeof(struct_TabCol));
1228
1229         char ch;
1230         bool bPreviousWasNull = true;
1231
1232         for (BOOL bContinue = TRUE; bContinue; )
1233         {
1234                 if (fp->Read(&ch, sizeof(ch), 1) != 1) {break;}
1235
1236                 if (bPreviousWasNull || ch==0)
1237                 {
1238                         switch (ch)
1239                         {
1240                         case '!': // extension
1241                                 {
1242                                 DecodeExtension(fp);
1243                                 break;
1244                                 }
1245                         case ',': // image
1246                                 {
1247
1248                                 assert(sizeof(image) == 9);
1249                                 //log << "Image header" << endl;
1250                                 fp->Read(&image,sizeof(image),1);
1251
1252                                 //avoid byte order problems with Solaris <candan> <AMSN>
1253                                 image.l = ntohs(image.l);
1254                                 image.t = ntohs(image.t);
1255                                 image.w = ntohs(image.w);
1256                                 image.h = ntohs(image.h);
1257
1258                                 // in case of images with empty screen descriptor, give a last chance
1259                                 if (dscgif->scrwidth==0 && dscgif->scrheight==0){
1260                                         dscgif->scrwidth = image.w;
1261                                         dscgif->scrheight = image.h;
1262                                 }
1263
1264                                 if (((image.l + image.w) > dscgif->scrwidth)||((image.t + image.h) > dscgif->scrheight))
1265                                         break;
1266
1267                                 nframes++;
1268
1269                                 // Local colour map?
1270                                 if (image.pf & 0x80) {
1271                                         TempTabCol.sogct = (short)(1 << ((image.pf & 0x07) +1));
1272                                         assert(3 == sizeof(struct rgb_color));
1273                                         fp->Read(TempTabCol.paleta,sizeof(struct rgb_color)*TempTabCol.sogct,1);
1274                                         //log << "Local colour map" << endl;
1275                                 }
1276
1277                                 int badcode=0;
1278                                 ibf = GIFBUFTAM+1;
1279
1280                                 interlaced = image.pf & 0x40;
1281                                 iheight = image.h;
1282                                 istep = 8;
1283                                 iypos = 0;
1284                                 ipass = 0;
1285
1286                                 long pos_start = fp->Tell();
1287
1288                                 //if (interlaced) log << "Interlaced" << endl;
1289                                 decoder(fp, 0, image.w, badcode);
1290
1291                                 if (badcode){
1292                                         seek_next_image(fp,pos_start);
1293                                 } else {
1294                                         fp->Seek(-(ibfmax - ibf - 1), SEEK_CUR);
1295                                 }
1296                 
1297                                 break;
1298                                 }
1299                         case ';': //terminator
1300                                 bContinue=false;
1301                                 break;
1302                         default:
1303                                 bPreviousWasNull = (ch==0);
1304                                 break;
1305                         }
1306                 }
1307         }
1308
1309         fp->Seek(pos,SEEK_SET);
1310         return nframes;
1311 }
1312 ////////////////////////////////////////////////////////////////////////////////
1313 long CxImageGIF::seek_next_image(CxFile* fp, long position)
1314 {
1315         fp->Seek(position, SEEK_SET);
1316         char ch1,ch2;
1317         ch1=ch2=0;
1318         while(fp->Read(&ch2,sizeof(char),1)>0){
1319                 if (ch1 == 0 && ch2 == ','){
1320                         fp->Seek(-1,SEEK_CUR);
1321                         return fp->Tell();
1322                 } else {
1323                         ch1 = ch2;
1324                 }
1325         }
1326         return -1;
1327 }
1328 ////////////////////////////////////////////////////////////////////////////////
1329 void CxImageGIF::SetLoops(int loops)
1330 {       m_loops=loops; }
1331 ////////////////////////////////////////////////////////////////////////////////
1332 long CxImageGIF::GetLoops()
1333 {       return m_loops; }
1334 ////////////////////////////////////////////////////////////////////////////////
1335 void CxImageGIF::SetComment(const char* sz_comment_in)
1336 {       if (sz_comment_in) strncpy(m_comment,sz_comment_in,255); }
1337 ////////////////////////////////////////////////////////////////////////////////
1338 void CxImageGIF::GetComment(char* sz_comment_out)
1339 {       if (sz_comment_out) strncpy(sz_comment_out,m_comment,255); }
1340 ////////////////////////////////////////////////////////////////////////////////
1341 void CxImageGIF::GifMix(CxImage & imgsrc2, struct_image & imgdesc)
1342 {
1343         long ymin = max(0,(long)(GetHeight()-imgdesc.t - imgdesc.h));
1344         long ymax = GetHeight()-imgdesc.t;
1345         long xmin = imgdesc.l;
1346         long xmax = min(GetWidth(), (DWORD)(imgdesc.l + imgdesc.w));
1347
1348         long ibg2= imgsrc2.GetTransIndex();
1349     BYTE i2;
1350
1351         for(long y = ymin; y < ymax; y++){
1352                 for(long x = xmin; x < xmax; x++){
1353                         i2 = imgsrc2.GetPixelIndex(x-xmin,y-ymin);
1354                         if(i2!=ibg2) SetPixelIndex(x,y,i2);
1355                 }
1356         }
1357 }
1358 ////////////////////////////////////////////////////////////////////////////////
1359 /*-----------------------------------------------------------------------
1360  *
1361  * miGIF Compression - mouse and ivo's GIF-compatible compression
1362  *
1363  *          -run length encoding compression routines-
1364  *
1365  * Copyright (C) 1998 Hutchison Avenue Software Corporation
1366  *               http://www.hasc.com
1367  *               info@hasc.com
1368  *
1369  * Permission to use, copy, modify, and distribute this software and its
1370  * documentation for any purpose and without fee is hereby granted, provided
1371  * that the above copyright notice appear in all copies and that both that
1372  * copyright notice and this permission notice appear in supporting
1373  * documentation.  This software is provided "AS IS." The Hutchison Avenue 
1374  * Software Corporation disclaims all warranties, either express or implied, 
1375  * including but not limited to implied warranties of merchantability and 
1376  * fitness for a particular purpose, with respect to this code and accompanying
1377  * documentation. 
1378  * 
1379  * The miGIF compression routines do not, strictly speaking, generate files 
1380  * conforming to the GIF spec, since the image data is not LZW-compressed 
1381  * (this is the point: in order to avoid transgression of the Unisys patent 
1382  * on the LZW algorithm.)  However, miGIF generates data streams that any 
1383  * reasonably sane LZW decompresser will decompress to what we want.
1384  *
1385  * miGIF compression uses run length encoding. It compresses horizontal runs 
1386  * of pixels of the same color. This type of compression gives good results
1387  * on images with many runs, for example images with lines, text and solid 
1388  * shapes on a solid-colored background. It gives little or no compression 
1389  * on images with few runs, for example digital or scanned photos.
1390  *
1391  *                               der Mouse
1392  *                      mouse@rodents.montreal.qc.ca
1393  *            7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B
1394  *
1395  *                             ivo@hasc.com
1396  *
1397  * The Graphics Interchange Format(c) is the Copyright property of
1398  * CompuServe Incorporated.  GIF(sm) is a Service Mark property of
1399  * CompuServe Incorporated.
1400  *
1401  */
1402 ////////////////////////////////////////////////////////////////////////////////
1403 void CxImageGIF::rle_clear(struct_RLE* rle)
1404 {
1405         rle->out_bits = rle->out_bits_init;
1406         rle->out_bump = rle->out_bump_init;
1407         rle->out_clear = rle->out_clear_init;
1408         rle->out_count = 0;
1409         rle->rl_table_max = 0;
1410         rle->just_cleared = 1;
1411 }
1412 ////////////////////////////////////////////////////////////////////////////////
1413 void CxImageGIF::rle_flush(struct_RLE* rle)
1414 {
1415         if (rle->rl_count == 1){
1416                 rle_output_plain(rle->rl_pixel,rle);
1417                 rle->rl_count = 0;
1418                 return;
1419         }
1420         if (rle->just_cleared){
1421                 rle_flush_fromclear(rle->rl_count,rle);
1422         } else if ((rle->rl_table_max < 2) || (rle->rl_table_pixel != rle->rl_pixel)) {
1423                 rle_flush_clearorrep(rle->rl_count,rle);
1424         } else {
1425                 rle_flush_withtable(rle->rl_count,rle);
1426         }
1427         rle->rl_count = 0;
1428 }
1429 ////////////////////////////////////////////////////////////////////////////////
1430 void CxImageGIF::rle_output_plain(int c,struct_RLE* rle)
1431 {
1432         rle->just_cleared = 0;
1433         rle_output(c,rle);
1434         rle->out_count++;
1435         if (rle->out_count >= rle->out_bump){
1436                 rle->out_bits ++;
1437                 rle->out_bump += 1 << (rle->out_bits - 1);
1438         }
1439         if (rle->out_count >= rle->out_clear){
1440                 rle_output(rle->code_clear,rle);
1441                 rle_clear(rle);
1442         }
1443 }
1444 ////////////////////////////////////////////////////////////////////////////////
1445 void CxImageGIF::rle_flush_fromclear(int count,struct_RLE* rle)
1446 {
1447         int n;
1448
1449         rle->out_clear = rle->max_ocodes;
1450         rle->rl_table_pixel = rle->rl_pixel;
1451         n = 1;
1452         while (count > 0){
1453                 if (n == 1){
1454                         rle->rl_table_max = 1;
1455                         rle_output_plain(rle->rl_pixel,rle);
1456                         count --;
1457                 } else if (count >= n){
1458                         rle->rl_table_max = n;
1459                         rle_output_plain(rle->rl_basecode+n-2,rle);
1460                         count -= n;
1461                 } else if (count == 1){
1462                         rle->rl_table_max ++;
1463                         rle_output_plain(rle->rl_pixel,rle);
1464                         count = 0;
1465                 } else {
1466                         rle->rl_table_max ++;
1467                         rle_output_plain(rle->rl_basecode+count-2,rle);
1468                         count = 0;
1469                 }
1470                 if (rle->out_count == 0) n = 1; else n ++;
1471         }
1472         rle_reset_out_clear(rle);
1473 }
1474 ////////////////////////////////////////////////////////////////////////////////
1475 void CxImageGIF::rle_reset_out_clear(struct_RLE* rle)
1476 {
1477         rle->out_clear = rle->out_clear_init;
1478         if (rle->out_count >= rle->out_clear){
1479                 rle_output(rle->code_clear,rle);
1480                 rle_clear(rle);
1481         }
1482 }
1483 ////////////////////////////////////////////////////////////////////////////////
1484 void CxImageGIF::rle_flush_withtable(int count, struct_RLE* rle)
1485 {
1486         int repmax;
1487         int repleft;
1488         int leftover;
1489
1490         repmax = count / rle->rl_table_max;
1491         leftover = count % rle->rl_table_max;
1492         repleft = (leftover ? 1 : 0);
1493         if (rle->out_count+repmax+repleft > rle->max_ocodes){
1494                 repmax = rle->max_ocodes - rle->out_count;
1495                 leftover = count - (repmax * rle->rl_table_max);
1496                 repleft = 1 + rle_compute_triangle_count(leftover,rle->max_ocodes);
1497         }
1498         if (1+rle_compute_triangle_count(count,rle->max_ocodes) < (unsigned int)(repmax+repleft)){
1499                 rle_output(rle->code_clear,rle);
1500                 rle_clear(rle);
1501                 rle_flush_fromclear(count,rle);
1502                 return;
1503         }
1504         rle->out_clear = rle->max_ocodes;
1505         for (;repmax>0;repmax--) rle_output_plain(rle->rl_basecode+rle->rl_table_max-2,rle);
1506         if (leftover){
1507                 if (rle->just_cleared){
1508                         rle_flush_fromclear(leftover,rle);
1509                 } else if (leftover == 1){
1510                         rle_output_plain(rle->rl_pixel,rle);
1511                 } else {
1512                         rle_output_plain(rle->rl_basecode+leftover-2,rle);
1513                 }
1514         }
1515         rle_reset_out_clear(rle);
1516 }
1517 ////////////////////////////////////////////////////////////////////////////////
1518 unsigned int CxImageGIF::rle_compute_triangle_count(unsigned int count, unsigned int nrepcodes)
1519 {
1520         unsigned int perrep;
1521         unsigned int cost;
1522
1523         cost = 0;
1524         perrep = (nrepcodes * (nrepcodes+1)) / 2;
1525         while (count >= perrep){
1526                 cost += nrepcodes;
1527                 count -= perrep;
1528         }
1529         if (count > 0){
1530                 unsigned int n;
1531                 n = rle_isqrt(count);
1532                 while ((n*(n+1)) >= 2*count) n --;
1533                 while ((n*(n+1)) < 2*count) n ++;
1534                 cost += n;
1535         }
1536         return(cost);
1537 }
1538 ////////////////////////////////////////////////////////////////////////////////
1539 unsigned int CxImageGIF::rle_isqrt(unsigned int x)
1540 {
1541         unsigned int r;
1542         unsigned int v;
1543
1544         if (x < 2) return(x);
1545         for (v=x,r=1;v;v>>=2,r<<=1) ;
1546         for( ;; )
1547         {
1548                 v = ((x / r) + r) / 2;
1549                 if ((v == r) || (v == r+1)) return(r);
1550                 r = v;
1551         }
1552 }
1553 ////////////////////////////////////////////////////////////////////////////////
1554 void CxImageGIF::rle_flush_clearorrep(int count, struct_RLE* rle)
1555 {
1556         int withclr;
1557         withclr = 1 + rle_compute_triangle_count(count,rle->max_ocodes);
1558         if (withclr < count) {
1559                 rle_output(rle->code_clear,rle);
1560                 rle_clear(rle);
1561                 rle_flush_fromclear(count,rle);
1562         } else {
1563                 for (;count>0;count--) rle_output_plain(rle->rl_pixel,rle);
1564         }
1565 }
1566 ////////////////////////////////////////////////////////////////////////////////
1567 void CxImageGIF::rle_write_block(struct_RLE* rle)
1568 {
1569         g_outfile->PutC((BYTE)rle->oblen);
1570         g_outfile->Write(rle->oblock,1,rle->oblen);
1571         rle->oblen = 0;
1572 }
1573 ////////////////////////////////////////////////////////////////////////////////
1574 void CxImageGIF::rle_block_out(unsigned char c, struct_RLE* rle)
1575 {
1576         rle->oblock[rle->oblen++] = c;
1577         if (rle->oblen >= 255) rle_write_block(rle);
1578 }
1579 ////////////////////////////////////////////////////////////////////////////////
1580 void CxImageGIF::rle_block_flush(struct_RLE* rle)
1581 {
1582         if (rle->oblen > 0) rle_write_block(rle);
1583 }
1584 ////////////////////////////////////////////////////////////////////////////////
1585 void CxImageGIF::rle_output(int val, struct_RLE* rle)
1586 {
1587         rle->obuf |= val << rle->obits;
1588         rle->obits += rle->out_bits;
1589         while (rle->obits >= 8){
1590                 rle_block_out((unsigned char)(rle->obuf&0xff),rle);
1591                 rle->obuf >>= 8;
1592                 rle->obits -= 8;
1593         }
1594 }
1595 ////////////////////////////////////////////////////////////////////////////////
1596 void CxImageGIF::rle_output_flush(struct_RLE* rle)
1597 {
1598          if (rle->obits > 0) rle_block_out((unsigned char)(rle->obuf),rle);
1599          rle_block_flush(rle);
1600 }
1601 ////////////////////////////////////////////////////////////////////////////////
1602 void CxImageGIF::compressRLE( int init_bits, CxFile* outfile)
1603 {
1604         g_init_bits = init_bits;
1605         g_outfile = outfile;
1606
1607         struct_RLE rle;
1608         rle.code_clear = 1 << (init_bits - 1);
1609         rle.code_eof = rle.code_clear + 1;
1610         rle.rl_basecode = rle.code_eof + 1;
1611         rle.out_bump_init = (1 << (init_bits - 1)) - 1;
1612         rle.out_clear_init = (init_bits <= 3) ? 9 : (rle.out_bump_init-1);
1613         rle.out_bits_init = init_bits;
1614         rle.max_ocodes = (1 << MAXBITSCODES) - ((1 << (rle.out_bits_init - 1)) + 3);
1615         rle.rl_count = 0;
1616         rle_clear(&rle);
1617         rle.obuf = 0;
1618         rle.obits = 0;
1619         rle.oblen = 0;
1620
1621         rle_output(rle.code_clear,&rle);
1622
1623         int c;
1624         for( ;; )
1625         {
1626                 c = GifNextPixel();
1627                 if ((rle.rl_count > 0) && (c != rle.rl_pixel)) rle_flush(&rle);
1628                 if (c == EOF) break;
1629                 if (rle.rl_pixel == c){
1630                         rle.rl_count++;
1631                 } else {
1632                         rle.rl_pixel = c;
1633                         rle.rl_count = 1;
1634                 }
1635         }
1636         rle_output(rle.code_eof,&rle);
1637         rle_output_flush(&rle);
1638 }
1639 ////////////////////////////////////////////////////////////////////////////////
1640 #endif // CXIMAGE_SUPPORT_GIF