fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_GIF_Image.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_GIF_Image.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // Fl_GIF_Image routines.
00005 //
00006 // Copyright 1997-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 // Contents:
00028 //
00029 //
00030 
00031 //
00032 // Include necessary header files...
00033 //
00034 
00035 #include <FL/Fl.H>
00036 #include <FL/Fl_GIF_Image.H>
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <FL/fl_utf8.h>
00040 #include "flstring.h"
00041 
00042 // Read a .gif file and convert it to a "xpm" format (actually my
00043 // modified one with compressed colormaps).
00044 
00045 // Extensively modified from original code for gif2ras by
00046 // Patrick J. Naughton of Sun Microsystems.  The original
00047 // copyright notice follows:
00048 
00049 /* gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
00050  *
00051  * Copyright (c) 1988 by Patrick J. Naughton
00052  *
00053  * Author: Patrick J. Naughton
00054  * naughton@wind.sun.com
00055  *
00056  * Permission to use, copy, modify, and distribute this software and its
00057  * documentation for any purpose and without fee is hereby granted,
00058  * provided that the above copyright notice appear in all copies and that
00059  * both that copyright notice and this permission notice appear in
00060  * supporting documentation.
00061  *
00062  * This file is provided AS IS with no warranties of any kind.  The author
00063  * shall have no liability with respect to the infringement of copyrights,
00064  * trade secrets or any patents by this file or any part thereof.  In no
00065  * event will the author be liable for any lost revenue or profits or
00066  * other special, indirect and consequential damages.
00067  *
00068  * Comments and additions should be sent to the author:
00069  *
00070  *                     Patrick J. Naughton
00071  *                     Sun Microsystems, Inc.
00072  *                     2550 Garcia Ave, MS 14-40
00073  *                     Mountain View, CA 94043
00074  *                     (415) 336-1080
00075  */
00076 
00077 typedef unsigned char uchar;
00078 
00079 #define NEXTBYTE (uchar)getc(GifFile)
00080 #define GETSHORT(var) var = NEXTBYTE; var += NEXTBYTE << 8
00081 
00087 Fl_GIF_Image::Fl_GIF_Image(const char *infname) : Fl_Pixmap((char *const*)0) {
00088   FILE *GifFile;        // File to read
00089   char **new_data;      // Data array
00090 
00091   if ((GifFile = fl_fopen(infname, "rb")) == NULL) {
00092     Fl::error("Fl_GIF_Image: Unable to open %s!", infname);
00093     return;
00094   }
00095 
00096   {char b[6];
00097   if (fread(b,1,6,GifFile)<6) {
00098     fclose(GifFile);
00099     return; /* quit on eof */
00100   }
00101   if (b[0]!='G' || b[1]!='I' || b[2] != 'F') {
00102     fclose(GifFile);
00103     Fl::error("Fl_GIF_Image: %s is not a GIF file.\n", infname);
00104     return;
00105   }
00106   if (b[3]!='8' || b[4]>'9' || b[5]!= 'a')
00107     Fl::warning("%s is version %c%c%c.",infname,b[3],b[4],b[5]);
00108   }
00109 
00110   int Width; GETSHORT(Width);
00111   int Height; GETSHORT(Height);
00112 
00113   uchar ch = NEXTBYTE;
00114   char HasColormap = ((ch & 0x80) != 0);
00115   int BitsPerPixel = (ch & 7) + 1;
00116   int ColorMapSize = 1 << BitsPerPixel;
00117   // int OriginalResolution = ((ch>>4)&7)+1;
00118   // int SortedTable = (ch&8)!=0;
00119   ch = NEXTBYTE; // Background Color index
00120   ch = NEXTBYTE; // Aspect ratio is N/64
00121 
00122   // Read in global colormap:
00123   uchar transparent_pixel = 0;
00124   char has_transparent = 0;
00125   uchar Red[256], Green[256], Blue[256]; /* color map */
00126   if (HasColormap) {
00127     for (int i=0; i < ColorMapSize; i++) {      
00128       Red[i] = NEXTBYTE;
00129       Green[i] = NEXTBYTE;
00130       Blue[i] = NEXTBYTE;
00131     }
00132   } else {
00133     Fl::warning("%s does not have a colormap.", infname);
00134     for (int i = 0; i < ColorMapSize; i++)
00135       Red[i] = Green[i] = Blue[i] = (uchar)(255 * i / (ColorMapSize-1));
00136   }
00137 
00138   int CodeSize;         /* Code size, init from GIF header, increases... */
00139   char Interlace;
00140 
00141   for (;;) {
00142 
00143     int i = NEXTBYTE;
00144     if (i<0) {
00145       fclose(GifFile);
00146       Fl::error("Fl_GIF_Image: %s - unexpected EOF",infname); 
00147       return;
00148     }
00149     int blocklen;
00150 
00151     //  if (i == 0x3B) return 0;  eof code
00152 
00153     if (i == 0x21) {            // a "gif extension"
00154 
00155       ch = NEXTBYTE;
00156       blocklen = NEXTBYTE;
00157 
00158       if (ch==0xF9 && blocklen==4) { // Netscape animation extension
00159 
00160         char bits;
00161         bits = NEXTBYTE;
00162         getc(GifFile); getc(GifFile); // GETSHORT(delay);
00163         transparent_pixel = NEXTBYTE;
00164         if (bits & 1) has_transparent = 1;
00165         blocklen = NEXTBYTE;
00166 
00167       } else if (ch == 0xFF) { // Netscape repeat count
00168         ;
00169 
00170       } else if (ch != 0xFE) { //Gif Comment
00171         Fl::warning("%s: unknown gif extension 0x%02x.", infname, ch);
00172       }
00173     } else if (i == 0x2c) {     // an image
00174 
00175       ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(x_position);
00176       ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(y_position);
00177       GETSHORT(Width);
00178       GETSHORT(Height);
00179       ch = NEXTBYTE;
00180       Interlace = ((ch & 0x40) != 0);
00181       if (ch&0x80) { 
00182         // read local color map
00183         int n = 2<<(ch&7);
00184         for (i=0; i < n; i++) { 
00185           Red[i] = NEXTBYTE;
00186           Green[i] = NEXTBYTE;
00187           Blue[i] = NEXTBYTE;
00188         }
00189       }
00190       CodeSize = NEXTBYTE+1;
00191       break; // okay, this is the image we want
00192     } else {
00193       Fl::warning("%s: unknown gif code 0x%02x", infname, i);
00194       blocklen = 0;
00195     }
00196 
00197     // skip the data:
00198     while (blocklen>0) {while (blocklen--) {ch = NEXTBYTE;} blocklen=NEXTBYTE;}
00199   }
00200 
00201   if (BitsPerPixel >= CodeSize)
00202   {
00203     // Workaround for broken GIF files...
00204     BitsPerPixel = CodeSize - 1;
00205     ColorMapSize = 1 << BitsPerPixel;
00206   }
00207 
00208   uchar *Image = new uchar[Width*Height];
00209 
00210   int YC = 0, Pass = 0; /* Used to de-interlace the picture */
00211   uchar *p = Image;
00212   uchar *eol = p+Width;
00213 
00214   int InitCodeSize = CodeSize;
00215   int ClearCode = (1 << (CodeSize-1));
00216   int EOFCode = ClearCode + 1;
00217   int FirstFree = ClearCode + 2;
00218   int FinChar = 0;
00219   int ReadMask = (1<<CodeSize) - 1;
00220   int FreeCode = FirstFree;
00221   int OldCode = ClearCode;
00222 
00223   // tables used by LZW decompresser:
00224   short int Prefix[4096];
00225   uchar Suffix[4096];
00226 
00227   int blocklen = NEXTBYTE;
00228   uchar thisbyte = NEXTBYTE; blocklen--;
00229   int frombit = 0;
00230 
00231   for (;;) {
00232 
00233 /* Fetch the next code from the raster data stream.  The codes can be
00234  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
00235  * maintain our location as a pointer and a bit offset.
00236  * In addition, gif adds totally useless and annoying block counts
00237  * that must be correctly skipped over. */
00238     int CurCode = thisbyte;
00239     if (frombit+CodeSize > 7) {
00240       if (blocklen <= 0) {
00241         blocklen = NEXTBYTE;
00242         if (blocklen <= 0) break;
00243       }
00244       thisbyte = NEXTBYTE; blocklen--;
00245       CurCode |= thisbyte<<8;
00246     }
00247     if (frombit+CodeSize > 15) {
00248       if (blocklen <= 0) {
00249         blocklen = NEXTBYTE;
00250         if (blocklen <= 0) break;
00251       }
00252       thisbyte = NEXTBYTE; blocklen--;
00253       CurCode |= thisbyte<<16;
00254     }
00255     CurCode = (CurCode>>frombit)&ReadMask;
00256     frombit = (frombit+CodeSize)%8;
00257 
00258     if (CurCode == ClearCode) {
00259       CodeSize = InitCodeSize;
00260       ReadMask = (1<<CodeSize) - 1;
00261       FreeCode = FirstFree;
00262       OldCode = ClearCode;
00263       continue;
00264     }
00265 
00266     if (CurCode == EOFCode) break;
00267 
00268     uchar OutCode[1025]; // temporary array for reversing codes
00269     uchar *tp = OutCode;
00270     int i;
00271     if (CurCode < FreeCode) i = CurCode;
00272     else if (CurCode == FreeCode) {*tp++ = (uchar)FinChar; i = OldCode;}
00273     else {Fl::error("Fl_GIF_Image: %s - LZW Barf!", infname); break;}
00274 
00275     while (i >= ColorMapSize) {*tp++ = Suffix[i]; i = Prefix[i];}
00276     *tp++ = FinChar = i;
00277     do {
00278       *p++ = *--tp;
00279       if (p >= eol) {
00280         if (!Interlace) YC++;
00281         else switch (Pass) {
00282         case 0: YC += 8; if (YC >= Height) {Pass++; YC = 4;} break;
00283         case 1: YC += 8; if (YC >= Height) {Pass++; YC = 2;} break;
00284         case 2: YC += 4; if (YC >= Height) {Pass++; YC = 1;} break;
00285         case 3: YC += 2; break;
00286         }
00287         if (YC>=Height) YC=0; /* cheap bug fix when excess data */
00288         p = Image + YC*Width;
00289         eol = p+Width;
00290       }
00291     } while (tp > OutCode);
00292 
00293     if (OldCode != ClearCode) {
00294       Prefix[FreeCode] = (short)OldCode;
00295       Suffix[FreeCode] = FinChar;
00296       FreeCode++;
00297       if (FreeCode > ReadMask) {
00298         if (CodeSize < 12) {
00299           CodeSize++;
00300           ReadMask = (1 << CodeSize) - 1;
00301         }
00302         else FreeCode--;
00303       }
00304     }
00305     OldCode = CurCode;
00306   }
00307 
00308   // We are done reading the file, now convert to xpm:
00309 
00310   // allocate line pointer arrays:
00311   w(Width);
00312   h(Height);
00313   d(1);
00314   new_data = new char*[Height+2];
00315 
00316   // transparent pixel must be zero, swap if it isn't:
00317   if (has_transparent && transparent_pixel != 0) {
00318     // swap transparent pixel with zero
00319     p = Image+Width*Height;
00320     while (p-- > Image) {
00321       if (*p==transparent_pixel) *p = 0;
00322       else if (!*p) *p = transparent_pixel;
00323     }
00324     uchar t;
00325     t                        = Red[0];
00326     Red[0]                   = Red[transparent_pixel];
00327     Red[transparent_pixel]   = t;
00328 
00329     t                        = Green[0];
00330     Green[0]                 = Green[transparent_pixel];
00331     Green[transparent_pixel] = t;
00332 
00333     t                        = Blue[0];
00334     Blue[0]                  = Blue[transparent_pixel];
00335     Blue[transparent_pixel]  = t;
00336   }
00337 
00338   // find out what colors are actually used:
00339   uchar used[256]; uchar remap[256];
00340   int i;
00341   for (i = 0; i < ColorMapSize; i++) used[i] = 0;
00342   p = Image+Width*Height;
00343   while (p-- > Image) used[*p] = 1;
00344 
00345   // remap them to start with printing characters:
00346   int base = has_transparent && used[0] ? ' ' : ' '+1;
00347   int numcolors = 0;
00348   for (i = 0; i < ColorMapSize; i++) if (used[i]) {
00349     remap[i] = (uchar)(base++);
00350     numcolors++;
00351   }
00352 
00353   // write the first line of xpm data (use suffix as temp array):
00354   int length = sprintf((char*)(Suffix),
00355                        "%d %d %d %d",Width,Height,-numcolors,1);
00356   new_data[0] = new char[length+1];
00357   strcpy(new_data[0], (char*)Suffix);
00358 
00359   // write the colormap
00360   new_data[1] = (char*)(p = new uchar[4*numcolors]);
00361   for (i = 0; i < ColorMapSize; i++) if (used[i]) {
00362     *p++ = remap[i];
00363     *p++ = Red[i];
00364     *p++ = Green[i];
00365     *p++ = Blue[i];
00366   }
00367 
00368   // remap the image data:
00369   p = Image+Width*Height;
00370   while (p-- > Image) *p = remap[*p];
00371 
00372   // split the image data into lines:
00373   for (i=0; i<Height; i++) {
00374     new_data[i+2] = new char[Width+1];
00375     memcpy(new_data[i + 2], (char*)(Image + i*Width), Width);
00376     new_data[i + 2][Width] = 0;
00377   }
00378 
00379   data((const char **)new_data, Height + 2);
00380   alloc_data = 1;
00381 
00382   delete[] Image;
00383 
00384   fclose(GifFile);
00385 }
00386 
00387 
00388 //
00389 // End of "$Id: Fl_GIF_Image.cxx 7903 2010-11-28 21:06:39Z matt $".
00390 //