2 // "$Id: Fl_GIF_Image.cxx 7903 2010-11-28 21:06:39Z matt $"
4 // Fl_GIF_Image routines.
6 // Copyright 1997-2010 by Bill Spitzak and others.
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
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
32 // Include necessary header files...
36 #include <FL/Fl_GIF_Image.H>
39 #include <FL/fl_utf8.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:
71 * Sun Microsystems, Inc.
72 * 2550 Garcia Ave, MS 14-40
73 * Mountain View, CA 94043
77 typedef unsigned char uchar
;
79 #define NEXTBYTE (uchar)getc(GifFile)
80 #define GETSHORT(var) var = NEXTBYTE; var += NEXTBYTE << 8
83 The constructor loads the named GIF image.
84 <P>The inherited destructor free all memory and server resources that are used by
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
);
97 if (fread(b
,1,6,GifFile
)<6) {
99 return; /* quit on eof */
101 if (b
[0]!='G' || b
[1]!='I' || b
[2] != 'F') {
103 Fl::error("Fl_GIF_Image: %s is not a GIF file.\n", infname
);
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
);
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 */
127 for (int i
=0; i
< ColorMapSize
; i
++) {
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... */
146 Fl::error("Fl_GIF_Image: %s - unexpected EOF",infname
);
151 // if (i == 0x3B) return 0; eof code
153 if (i
== 0x21) { // a "gif extension"
158 if (ch
==0xF9 && blocklen
==4) { // Netscape animation extension
162 getc(GifFile
); getc(GifFile
); // GETSHORT(delay);
163 transparent_pixel
= NEXTBYTE
;
164 if (bits
& 1) has_transparent
= 1;
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);
180 Interlace
= ((ch
& 0x40) != 0);
182 // read local color map
184 for (i
=0; i
< n
; i
++) {
190 CodeSize
= NEXTBYTE
+1;
191 break; // okay, this is the image we want
193 Fl::warning("%s: unknown gif code 0x%02x", infname
, i
);
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 */
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;
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];
227 int blocklen
= NEXTBYTE
;
228 uchar thisbyte
= NEXTBYTE
; blocklen
--;
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) {
242 if (blocklen
<= 0) break;
244 thisbyte
= NEXTBYTE
; blocklen
--;
245 CurCode
|= thisbyte
<<8;
247 if (frombit
+CodeSize
> 15) {
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
;
266 if (CurCode
== EOFCode
) break;
268 uchar OutCode
[1025]; // temporary array for reversing codes
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
];}
280 if (!Interlace
) YC
++;
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
;
291 } while (tp
> OutCode
);
293 if (OldCode
!= ClearCode
) {
294 Prefix
[FreeCode
] = (short)OldCode
;
295 Suffix
[FreeCode
] = FinChar
;
297 if (FreeCode
> ReadMask
) {
300 ReadMask
= (1 << CodeSize
) - 1;
308 // We are done reading the file, now convert to xpm:
310 // allocate line pointer arrays:
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
;
326 Red
[0] = Red
[transparent_pixel
];
327 Red
[transparent_pixel
] = t
;
330 Green
[0] = Green
[transparent_pixel
];
331 Green
[transparent_pixel
] = t
;
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];
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;
348 for (i
= 0; i
< ColorMapSize
; i
++) if (used
[i
]) {
349 remap
[i
] = (uchar
)(base
++);
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
]) {
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);
389 // End of "$Id: Fl_GIF_Image.cxx 7903 2010-11-28 21:06:39Z matt $".