|
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) ![]() |
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 //