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

Fl_GIF_Image.cxx
Go to the documentation of this file.
1 //
2 // "$Id$"
3 //
4 // Fl_GIF_Image routines.
5 //
6 // Copyright 1997-2019 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file. If this
10 // file is missing or damaged, see the license at:
11 //
12 // http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 // http://www.fltk.org/str.php
17 //
18 // Contents:
19 //
20 //
21 
22 //
23 // Reference: GIF89a Specification (links valid as of Jan 05, 2019):
24 //
25 // "GRAPHICS INTERCHANGE FORMAT(sm), Version 89a" (authoritative):
26 // https://www.w3.org/Graphics/GIF/spec-gif89a.txt
27 //
28 // HTML version (non-authoritative):
29 // https://web.archive.org/web/20160304075538/http://qalle.net/gif89a.php
30 //
31 
32 //
33 // Include necessary header files...
34 //
35 
36 #include <FL/Fl.H>
37 #include <FL/Fl_GIF_Image.H>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <FL/fl_utf8.h>
41 #include "flstring.h"
42 
43 // Read a .gif file and convert it to a "xpm" format (actually my
44 // modified one with compressed colormaps).
45 
46 // Extensively modified from original code for gif2ras by
47 // Patrick J. Naughton of Sun Microsystems. The original
48 // copyright notice follows:
49 
50 /* gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
51  *
52  * Copyright (c) 1988 by Patrick J. Naughton
53  *
54  * Author: Patrick J. Naughton
55  * naughton@wind.sun.com
56  *
57  * Permission to use, copy, modify, and distribute this software and its
58  * documentation for any purpose and without fee is hereby granted,
59  * provided that the above copyright notice appear in all copies and that
60  * both that copyright notice and this permission notice appear in
61  * supporting documentation.
62  *
63  * This file is provided AS IS with no warranties of any kind. The author
64  * shall have no liability with respect to the infringement of copyrights,
65  * trade secrets or any patents by this file or any part thereof. In no
66  * event will the author be liable for any lost revenue or profits or
67  * other special, indirect and consequential damages.
68  *
69  * Comments and additions should be sent to the author:
70  *
71  * Patrick J. Naughton
72  * Sun Microsystems, Inc.
73  * 2550 Garcia Ave, MS 14-40
74  * Mountain View, CA 94043
75  * (415) 336-1080
76  */
77 
78 typedef unsigned char uchar;
79 
80 #define NEXTBYTE (uchar)getc(GifFile)
81 #define GETSHORT(var) var = NEXTBYTE; var += NEXTBYTE << 8
82 
94 Fl_GIF_Image::Fl_GIF_Image(const char *infname) : Fl_Pixmap((char *const*)0) {
95  FILE *GifFile; // File to read
96  char **new_data; // Data array
97 
98  if ((GifFile = fl_fopen(infname, "rb")) == NULL) {
99  Fl::error("Fl_GIF_Image: Unable to open %s!", infname);
101  return;
102  }
103 
104  {char b[6];
105  if (fread(b,1,6,GifFile)<6) {
106  fclose(GifFile);
108  return; /* quit on eof */
109  }
110  if (b[0]!='G' || b[1]!='I' || b[2] != 'F') {
111  fclose(GifFile);
112  Fl::error("Fl_GIF_Image: %s is not a GIF file.\n", infname);
113  ld(ERR_FORMAT);
114  return;
115  }
116  if (b[3]!='8' || b[4]>'9' || b[5]!= 'a')
117  Fl::warning("%s is version %c%c%c.",infname,b[3],b[4],b[5]);
118  }
119 
120  int Width; GETSHORT(Width);
121  int Height; GETSHORT(Height);
122 
123  uchar ch = NEXTBYTE;
124  char HasColormap = ((ch & 0x80) != 0);
125  int BitsPerPixel = (ch & 7) + 1;
126  int ColorMapSize;
127  if (HasColormap) {
128  ColorMapSize = 2 << (ch & 7);
129  } else {
130  ColorMapSize = 0;
131  }
132  // int OriginalResolution = ((ch>>4)&7)+1;
133  // int SortedTable = (ch&8)!=0;
134  ch = NEXTBYTE; // Background Color index
135  ch = NEXTBYTE; // Aspect ratio is N/64
136 
137  // Read in global colormap:
138  uchar transparent_pixel = 0;
139  char has_transparent = 0;
140  uchar Red[256], Green[256], Blue[256]; /* color map */
141  if (HasColormap) {
142  for (int i=0; i < ColorMapSize; i++) {
143  Red[i] = NEXTBYTE;
144  Green[i] = NEXTBYTE;
145  Blue[i] = NEXTBYTE;
146  }
147  }
148 
149  int CodeSize; /* Code size, init from GIF header, increases... */
150  char Interlace;
151 
152  for (;;) {
153 
154  int i = NEXTBYTE;
155  if (i<0) {
156  fclose(GifFile);
157  Fl::error("Fl_GIF_Image: %s - unexpected EOF",infname);
158  w(0); h(0); d(0); ld(ERR_FORMAT);
159  return;
160  }
161  int blocklen;
162 
163  // if (i == 0x3B) return 0; eof code
164 
165  if (i == 0x21) { // a "gif extension"
166 
167  ch = NEXTBYTE;
168  blocklen = NEXTBYTE;
169 
170  if (ch==0xF9 && blocklen==4) { // Netscape animation extension
171 
172  char bits;
173  bits = NEXTBYTE;
174  getc(GifFile); getc(GifFile); // GETSHORT(delay);
175  transparent_pixel = NEXTBYTE;
176  if (bits & 1) has_transparent = 1;
177  blocklen = NEXTBYTE;
178 
179  } else if (ch == 0xFF) { // Netscape repeat count
180  ;
181 
182  } else if (ch != 0xFE) { //Gif Comment
183  Fl::warning("%s: unknown gif extension 0x%02x.", infname, ch);
184  }
185  } else if (i == 0x2c) { // an image
186 
187  ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(x_position);
188  ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(y_position);
189  GETSHORT(Width);
190  GETSHORT(Height);
191  ch = NEXTBYTE;
192  Interlace = ((ch & 0x40) != 0);
193  if (ch & 0x80) { // image has local color table
194  BitsPerPixel = (ch & 7) + 1;
195  ColorMapSize = 2 << (ch & 7);
196  for (i=0; i < ColorMapSize; i++) {
197  Red[i] = NEXTBYTE;
198  Green[i] = NEXTBYTE;
199  Blue[i] = NEXTBYTE;
200  }
201  }
202  CodeSize = NEXTBYTE+1;
203  break; // okay, this is the image we want
204  } else {
205  Fl::warning("%s: unknown gif code 0x%02x", infname, i);
206  blocklen = 0;
207  }
208 
209  // skip the data:
210  while (blocklen>0) {while (blocklen--) {ch = NEXTBYTE;} blocklen=NEXTBYTE;}
211  }
212 
213  if (BitsPerPixel >= CodeSize)
214  {
215  // Workaround for broken GIF files...
216  BitsPerPixel = CodeSize - 1;
217  ColorMapSize = 1 << BitsPerPixel;
218  }
219 
220  // Fix images w/o color table. The standard allows this and lets the
221  // decoder choose a default color table. The standard recommends the
222  // first two color table entries should be black and white.
223 
224  if (ColorMapSize == 0) { // no global and no local color table
225  Fl::warning("%s does not have a color table, using default.\n", infname);
226  BitsPerPixel = CodeSize - 1;
227  ColorMapSize = 1 << BitsPerPixel;
228  Red[0] = Green[0] = Blue[0] = 0; // black
229  Red[1] = Green[1] = Blue[1] = 255; // white
230  for (int i = 2; i < ColorMapSize; i++) {
231  Red[i] = Green[i] = Blue[i] = (uchar)(255 * i / (ColorMapSize - 1));
232  }
233 #if (0)
234  // fill color table to maximum size
235  for (int i = ColorMapSize; i < 256; i++) {
236  Red[i] = Green[i] = Blue[i] = 0; // black
237  }
238 #endif
239  }
240 
241  uchar *Image = new uchar[Width*Height];
242 
243  int YC = 0, Pass = 0; /* Used to de-interlace the picture */
244  uchar *p = Image;
245  uchar *eol = p+Width;
246 
247  int InitCodeSize = CodeSize;
248  int ClearCode = (1 << (CodeSize-1));
249  int EOFCode = ClearCode + 1;
250  int FirstFree = ClearCode + 2;
251  int FinChar = 0;
252  int ReadMask = (1<<CodeSize) - 1;
253  int FreeCode = FirstFree;
254  int OldCode = ClearCode;
255 
256  // tables used by LZW decompresser:
257  short int Prefix[4096];
258  uchar Suffix[4096];
259 
260  int blocklen = NEXTBYTE;
261  uchar thisbyte = NEXTBYTE; blocklen--;
262  int frombit = 0;
263 
264  for (;;) {
265 
266 /* Fetch the next code from the raster data stream. The codes can be
267  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
268  * maintain our location as a pointer and a bit offset.
269  * In addition, gif adds totally useless and annoying block counts
270  * that must be correctly skipped over. */
271  int CurCode = thisbyte;
272  if (frombit+CodeSize > 7) {
273  if (blocklen <= 0) {
274  blocklen = NEXTBYTE;
275  if (blocklen <= 0) break;
276  }
277  thisbyte = NEXTBYTE; blocklen--;
278  CurCode |= thisbyte<<8;
279  }
280  if (frombit+CodeSize > 15) {
281  if (blocklen <= 0) {
282  blocklen = NEXTBYTE;
283  if (blocklen <= 0) break;
284  }
285  thisbyte = NEXTBYTE; blocklen--;
286  CurCode |= thisbyte<<16;
287  }
288  CurCode = (CurCode>>frombit)&ReadMask;
289  frombit = (frombit+CodeSize)%8;
290 
291  if (CurCode == ClearCode) {
292  CodeSize = InitCodeSize;
293  ReadMask = (1<<CodeSize) - 1;
294  FreeCode = FirstFree;
295  OldCode = ClearCode;
296  continue;
297  }
298 
299  if (CurCode == EOFCode) break;
300 
301  uchar OutCode[1025]; // temporary array for reversing codes
302  uchar *tp = OutCode;
303  int i;
304  if (CurCode < FreeCode) i = CurCode;
305  else if (CurCode == FreeCode) {*tp++ = (uchar)FinChar; i = OldCode;}
306  else {Fl::error("Fl_GIF_Image: %s - LZW Barf!", infname); break;}
307 
308  while (i >= ColorMapSize) {*tp++ = Suffix[i]; i = Prefix[i];}
309  *tp++ = FinChar = i;
310  do {
311  *p++ = *--tp;
312  if (p >= eol) {
313  if (!Interlace) YC++;
314  else switch (Pass) {
315  case 0: YC += 8; if (YC >= Height) {Pass++; YC = 4;} break;
316  case 1: YC += 8; if (YC >= Height) {Pass++; YC = 2;} break;
317  case 2: YC += 4; if (YC >= Height) {Pass++; YC = 1;} break;
318  case 3: YC += 2; break;
319  }
320  if (YC>=Height) YC=0; /* cheap bug fix when excess data */
321  p = Image + YC*Width;
322  eol = p+Width;
323  }
324  } while (tp > OutCode);
325 
326  if (OldCode != ClearCode) {
327  Prefix[FreeCode] = (short)OldCode;
328  Suffix[FreeCode] = FinChar;
329  FreeCode++;
330  if (FreeCode > ReadMask) {
331  if (CodeSize < 12) {
332  CodeSize++;
333  ReadMask = (1 << CodeSize) - 1;
334  }
335  else FreeCode--;
336  }
337  }
338  OldCode = CurCode;
339  }
340 
341  // We are done reading the file, now convert to xpm:
342 
343  // allocate line pointer arrays:
344  w(Width);
345  h(Height);
346  d(1);
347  new_data = new char*[Height+2];
348 
349  // transparent pixel must be zero, swap if it isn't:
350  if (has_transparent && transparent_pixel != 0) {
351  // swap transparent pixel with zero
352  p = Image+Width*Height;
353  while (p-- > Image) {
354  if (*p==transparent_pixel) *p = 0;
355  else if (!*p) *p = transparent_pixel;
356  }
357  uchar t;
358  t = Red[0];
359  Red[0] = Red[transparent_pixel];
360  Red[transparent_pixel] = t;
361 
362  t = Green[0];
363  Green[0] = Green[transparent_pixel];
364  Green[transparent_pixel] = t;
365 
366  t = Blue[0];
367  Blue[0] = Blue[transparent_pixel];
368  Blue[transparent_pixel] = t;
369  }
370 
371  // find out what colors are actually used:
372  uchar used[256]; uchar remap[256];
373  int i;
374  for (i = 0; i < ColorMapSize; i++) used[i] = 0;
375  p = Image+Width*Height;
376  while (p-- > Image) used[*p] = 1;
377 
378  // remap them to start with printing characters:
379  int base = has_transparent && used[0] ? ' ' : ' '+1;
380  int numcolors = 0;
381  for (i = 0; i < ColorMapSize; i++) if (used[i]) {
382  remap[i] = (uchar)(base++);
383  numcolors++;
384  }
385 
386  // write the first line of xpm data (use suffix as temp array):
387  int length = sprintf((char*)(Suffix),
388  "%d %d %d %d",Width,Height,-numcolors,1);
389  new_data[0] = new char[length+1];
390  strcpy(new_data[0], (char*)Suffix);
391 
392  // write the colormap
393  new_data[1] = (char*)(p = new uchar[4*numcolors]);
394  for (i = 0; i < ColorMapSize; i++) if (used[i]) {
395  *p++ = remap[i];
396  *p++ = Red[i];
397  *p++ = Green[i];
398  *p++ = Blue[i];
399  }
400 
401  // remap the image data:
402  p = Image+Width*Height;
403  while (p-- > Image) *p = remap[*p];
404 
405  // split the image data into lines:
406  for (i=0; i<Height; i++) {
407  new_data[i+2] = new char[Width+1];
408  memcpy(new_data[i + 2], (char*)(Image + i*Width), Width);
409  new_data[i + 2][Width] = 0;
410  }
411 
412  data((const char **)new_data, Height + 2);
413  alloc_data = 1;
414 
415  delete[] Image;
416 
417  fclose(GifFile);
418 }
419 
420 
421 //
422 // End of "$Id$".
423 //
Fl.H
Fl_Image::data
const char *const * data() const
Definition: Fl_Image.H:138
Fl_Image::d
int d() const
Definition: Fl_Image.H:121
NULL
#define NULL
Definition: forms.H:34
NEXTBYTE
#define NEXTBYTE
Definition: Fl_GIF_Image.cxx:80
fl_fopen
FILE * fl_fopen(const char *f, const char *mode)
Definition: fl_utf8.cxx:498
b
long b
Definition: jpegint.h:397
Fl_Image::ld
int ld() const
Definition: Fl_Image.H:126
Fl_GIF_Image.H
GETSHORT
#define GETSHORT(var)
Definition: Fl_GIF_Image.cxx:81
p
static menustate * p
Definition: Fl_Menu.cxx:606
fl_utf8.h
header for Unicode and UTF-8 character handling
Fl_GIF_Image::Fl_GIF_Image
Fl_GIF_Image(const char *filename)
Definition: Fl_GIF_Image.cxx:94
Fl_Pixmap
Definition: Fl_Pixmap.H:41
Fl_Image::ERR_FORMAT
static const int ERR_FORMAT
Definition: Fl_Image.H:60
Fl_Image::h
int h() const
Definition: Fl_Image.H:115
Fl_Image::w
int w() const
Definition: Fl_Image.H:111
Fl_Pixmap::alloc_data
int alloc_data
Definition: Fl_Pixmap.H:58
Fl::warning
static void(* warning)(const char *,...)
Definition: Fl.H:498
uchar
unsigned char uchar
Definition: Fl_GIF_Image.cxx:78
flstring.h
Fl::error
static void(* error)(const char *,...)
Definition: Fl.H:513
length
png_uint_32 length
Definition: png.c:2173
Fl_Image::ERR_FILE_ACCESS
static const int ERR_FILE_ACCESS
Definition: Fl_Image.H:59
uchar
unsigned char uchar
Definition: fl_types.h:30
const
#define const
Definition: zconf.h:226