themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_GIF_Image.cxx
blobc4d5811ef98a7e332c0b064908a00ef6069d944e
1 //
2 // "$Id: Fl_GIF_Image.cxx 7903 2010-11-28 21:06:39Z matt $"
3 //
4 // Fl_GIF_Image routines.
5 //
6 // Copyright 1997-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
27 // Contents:
32 // Include necessary header files...
35 #include <FL/Fl.H>
36 #include <FL/Fl_GIF_Image.H>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <FL/fl_utf8.h>
40 #include "flstring.h"
42 // Read a .gif file and convert it to a "xpm" format (actually my
43 // modified one with compressed colormaps).
45 // Extensively modified from original code for gif2ras by
46 // Patrick J. Naughton of Sun Microsystems. The original
47 // copyright notice follows:
49 /* gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
51 * Copyright (c) 1988 by Patrick J. Naughton
53 * Author: Patrick J. Naughton
54 * naughton@wind.sun.com
56 * Permission to use, copy, modify, and distribute this software and its
57 * documentation for any purpose and without fee is hereby granted,
58 * provided that the above copyright notice appear in all copies and that
59 * both that copyright notice and this permission notice appear in
60 * supporting documentation.
62 * This file is provided AS IS with no warranties of any kind. The author
63 * shall have no liability with respect to the infringement of copyrights,
64 * trade secrets or any patents by this file or any part thereof. In no
65 * event will the author be liable for any lost revenue or profits or
66 * other special, indirect and consequential damages.
68 * Comments and additions should be sent to the author:
70 * Patrick J. Naughton
71 * Sun Microsystems, Inc.
72 * 2550 Garcia Ave, MS 14-40
73 * Mountain View, CA 94043
74 * (415) 336-1080
77 typedef unsigned char uchar;
79 #define NEXTBYTE (uchar)getc(GifFile)
80 #define GETSHORT(var) var = NEXTBYTE; var += NEXTBYTE << 8
82 /**
83 The constructor loads the named GIF image.
84 <P>The inherited destructor free all memory and server resources that are used by
85 the image.
87 Fl_GIF_Image::Fl_GIF_Image(const char *infname) : Fl_Pixmap((char *const*)0) {
88 FILE *GifFile; // File to read
89 char **new_data; // Data array
91 if ((GifFile = fl_fopen(infname, "rb")) == NULL) {
92 Fl::error("Fl_GIF_Image: Unable to open %s!", infname);
93 return;
96 {char b[6];
97 if (fread(b,1,6,GifFile)<6) {
98 fclose(GifFile);
99 return; /* quit on eof */
101 if (b[0]!='G' || b[1]!='I' || b[2] != 'F') {
102 fclose(GifFile);
103 Fl::error("Fl_GIF_Image: %s is not a GIF file.\n", infname);
104 return;
106 if (b[3]!='8' || b[4]>'9' || b[5]!= 'a')
107 Fl::warning("%s is version %c%c%c.",infname,b[3],b[4],b[5]);
110 int Width; GETSHORT(Width);
111 int Height; GETSHORT(Height);
113 uchar ch = NEXTBYTE;
114 char HasColormap = ((ch & 0x80) != 0);
115 int BitsPerPixel = (ch & 7) + 1;
116 int ColorMapSize = 1 << BitsPerPixel;
117 // int OriginalResolution = ((ch>>4)&7)+1;
118 // int SortedTable = (ch&8)!=0;
119 ch = NEXTBYTE; // Background Color index
120 ch = NEXTBYTE; // Aspect ratio is N/64
122 // Read in global colormap:
123 uchar transparent_pixel = 0;
124 char has_transparent = 0;
125 uchar Red[256], Green[256], Blue[256]; /* color map */
126 if (HasColormap) {
127 for (int i=0; i < ColorMapSize; i++) {
128 Red[i] = NEXTBYTE;
129 Green[i] = NEXTBYTE;
130 Blue[i] = NEXTBYTE;
132 } else {
133 Fl::warning("%s does not have a colormap.", infname);
134 for (int i = 0; i < ColorMapSize; i++)
135 Red[i] = Green[i] = Blue[i] = (uchar)(255 * i / (ColorMapSize-1));
138 int CodeSize; /* Code size, init from GIF header, increases... */
139 char Interlace;
141 for (;;) {
143 int i = NEXTBYTE;
144 if (i<0) {
145 fclose(GifFile);
146 Fl::error("Fl_GIF_Image: %s - unexpected EOF",infname);
147 return;
149 int blocklen;
151 // if (i == 0x3B) return 0; eof code
153 if (i == 0x21) { // a "gif extension"
155 ch = NEXTBYTE;
156 blocklen = NEXTBYTE;
158 if (ch==0xF9 && blocklen==4) { // Netscape animation extension
160 char bits;
161 bits = NEXTBYTE;
162 getc(GifFile); getc(GifFile); // GETSHORT(delay);
163 transparent_pixel = NEXTBYTE;
164 if (bits & 1) has_transparent = 1;
165 blocklen = NEXTBYTE;
167 } else if (ch == 0xFF) { // Netscape repeat count
170 } else if (ch != 0xFE) { //Gif Comment
171 Fl::warning("%s: unknown gif extension 0x%02x.", infname, ch);
173 } else if (i == 0x2c) { // an image
175 ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(x_position);
176 ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(y_position);
177 GETSHORT(Width);
178 GETSHORT(Height);
179 ch = NEXTBYTE;
180 Interlace = ((ch & 0x40) != 0);
181 if (ch&0x80) {
182 // read local color map
183 int n = 2<<(ch&7);
184 for (i=0; i < n; i++) {
185 Red[i] = NEXTBYTE;
186 Green[i] = NEXTBYTE;
187 Blue[i] = NEXTBYTE;
190 CodeSize = NEXTBYTE+1;
191 break; // okay, this is the image we want
192 } else {
193 Fl::warning("%s: unknown gif code 0x%02x", infname, i);
194 blocklen = 0;
197 // skip the data:
198 while (blocklen>0) {while (blocklen--) {ch = NEXTBYTE;} blocklen=NEXTBYTE;}
201 if (BitsPerPixel >= CodeSize)
203 // Workaround for broken GIF files...
204 BitsPerPixel = CodeSize - 1;
205 ColorMapSize = 1 << BitsPerPixel;
208 uchar *Image = new uchar[Width*Height];
210 int YC = 0, Pass = 0; /* Used to de-interlace the picture */
211 uchar *p = Image;
212 uchar *eol = p+Width;
214 int InitCodeSize = CodeSize;
215 int ClearCode = (1 << (CodeSize-1));
216 int EOFCode = ClearCode + 1;
217 int FirstFree = ClearCode + 2;
218 int FinChar = 0;
219 int ReadMask = (1<<CodeSize) - 1;
220 int FreeCode = FirstFree;
221 int OldCode = ClearCode;
223 // tables used by LZW decompresser:
224 short int Prefix[4096];
225 uchar Suffix[4096];
227 int blocklen = NEXTBYTE;
228 uchar thisbyte = NEXTBYTE; blocklen--;
229 int frombit = 0;
231 for (;;) {
233 /* Fetch the next code from the raster data stream. The codes can be
234 * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
235 * maintain our location as a pointer and a bit offset.
236 * In addition, gif adds totally useless and annoying block counts
237 * that must be correctly skipped over. */
238 int CurCode = thisbyte;
239 if (frombit+CodeSize > 7) {
240 if (blocklen <= 0) {
241 blocklen = NEXTBYTE;
242 if (blocklen <= 0) break;
244 thisbyte = NEXTBYTE; blocklen--;
245 CurCode |= thisbyte<<8;
247 if (frombit+CodeSize > 15) {
248 if (blocklen <= 0) {
249 blocklen = NEXTBYTE;
250 if (blocklen <= 0) break;
252 thisbyte = NEXTBYTE; blocklen--;
253 CurCode |= thisbyte<<16;
255 CurCode = (CurCode>>frombit)&ReadMask;
256 frombit = (frombit+CodeSize)%8;
258 if (CurCode == ClearCode) {
259 CodeSize = InitCodeSize;
260 ReadMask = (1<<CodeSize) - 1;
261 FreeCode = FirstFree;
262 OldCode = ClearCode;
263 continue;
266 if (CurCode == EOFCode) break;
268 uchar OutCode[1025]; // temporary array for reversing codes
269 uchar *tp = OutCode;
270 int i;
271 if (CurCode < FreeCode) i = CurCode;
272 else if (CurCode == FreeCode) {*tp++ = (uchar)FinChar; i = OldCode;}
273 else {Fl::error("Fl_GIF_Image: %s - LZW Barf!", infname); break;}
275 while (i >= ColorMapSize) {*tp++ = Suffix[i]; i = Prefix[i];}
276 *tp++ = FinChar = i;
277 do {
278 *p++ = *--tp;
279 if (p >= eol) {
280 if (!Interlace) YC++;
281 else switch (Pass) {
282 case 0: YC += 8; if (YC >= Height) {Pass++; YC = 4;} break;
283 case 1: YC += 8; if (YC >= Height) {Pass++; YC = 2;} break;
284 case 2: YC += 4; if (YC >= Height) {Pass++; YC = 1;} break;
285 case 3: YC += 2; break;
287 if (YC>=Height) YC=0; /* cheap bug fix when excess data */
288 p = Image + YC*Width;
289 eol = p+Width;
291 } while (tp > OutCode);
293 if (OldCode != ClearCode) {
294 Prefix[FreeCode] = (short)OldCode;
295 Suffix[FreeCode] = FinChar;
296 FreeCode++;
297 if (FreeCode > ReadMask) {
298 if (CodeSize < 12) {
299 CodeSize++;
300 ReadMask = (1 << CodeSize) - 1;
302 else FreeCode--;
305 OldCode = CurCode;
308 // We are done reading the file, now convert to xpm:
310 // allocate line pointer arrays:
311 w(Width);
312 h(Height);
313 d(1);
314 new_data = new char*[Height+2];
316 // transparent pixel must be zero, swap if it isn't:
317 if (has_transparent && transparent_pixel != 0) {
318 // swap transparent pixel with zero
319 p = Image+Width*Height;
320 while (p-- > Image) {
321 if (*p==transparent_pixel) *p = 0;
322 else if (!*p) *p = transparent_pixel;
324 uchar t;
325 t = Red[0];
326 Red[0] = Red[transparent_pixel];
327 Red[transparent_pixel] = t;
329 t = Green[0];
330 Green[0] = Green[transparent_pixel];
331 Green[transparent_pixel] = t;
333 t = Blue[0];
334 Blue[0] = Blue[transparent_pixel];
335 Blue[transparent_pixel] = t;
338 // find out what colors are actually used:
339 uchar used[256]; uchar remap[256];
340 int i;
341 for (i = 0; i < ColorMapSize; i++) used[i] = 0;
342 p = Image+Width*Height;
343 while (p-- > Image) used[*p] = 1;
345 // remap them to start with printing characters:
346 int base = has_transparent && used[0] ? ' ' : ' '+1;
347 int numcolors = 0;
348 for (i = 0; i < ColorMapSize; i++) if (used[i]) {
349 remap[i] = (uchar)(base++);
350 numcolors++;
353 // write the first line of xpm data (use suffix as temp array):
354 int length = sprintf((char*)(Suffix),
355 "%d %d %d %d",Width,Height,-numcolors,1);
356 new_data[0] = new char[length+1];
357 strcpy(new_data[0], (char*)Suffix);
359 // write the colormap
360 new_data[1] = (char*)(p = new uchar[4*numcolors]);
361 for (i = 0; i < ColorMapSize; i++) if (used[i]) {
362 *p++ = remap[i];
363 *p++ = Red[i];
364 *p++ = Green[i];
365 *p++ = Blue[i];
368 // remap the image data:
369 p = Image+Width*Height;
370 while (p-- > Image) *p = remap[*p];
372 // split the image data into lines:
373 for (i=0; i<Height; i++) {
374 new_data[i+2] = new char[Width+1];
375 memcpy(new_data[i + 2], (char*)(Image + i*Width), Width);
376 new_data[i + 2][Width] = 0;
379 data((const char **)new_data, Height + 2);
380 alloc_data = 1;
382 delete[] Image;
384 fclose(GifFile);
389 // End of "$Id: Fl_GIF_Image.cxx 7903 2010-11-28 21:06:39Z matt $".