Skip to content

Commit fbf2d0c

Browse files
committed
Merge branch 'gif2txt'
2 parents a604f35 + bf8eb6d commit fbf2d0c

4 files changed

Lines changed: 354 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.o
22
SDLaffgif
33
gif2tga
4+
gif2txt
45
tmp/
56
*.d

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ ifeq ($(OS), Darwin)
1414
LDLIBS += -framework Cocoa
1515
endif
1616

17-
EXECUTABLES=gif2tga SDLaffgif
17+
EXECUTABLES=gif2tga SDLaffgif gif2txt
1818

1919
SRCS = $(wildcard *.c)
2020
OBJS = $(patsubst %.c,%.o,$(SRCS))
@@ -59,6 +59,8 @@ SDLaffgif: SDLaffgif.o ngiflibSDL.o ngiflib.o
5959

6060
gif2tga: gif2tga.o ngiflib.o
6161

62+
gif2txt: gif2txt.o ngiflib.o
63+
6264
%.o: %.c %.d
6365

6466
%.d: %.c

gif2txt.c

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
#include <stdio.h>
2+
3+
#include "ngiflib.h"
4+
5+
/* #define ANSI_COLOR_LUT */
6+
7+
enum ansi_color_mode {
8+
BASIC, /* 8 colors */
9+
VGACOLORS, /* 216 colors */
10+
TRUECOLORS /* 24 bits colors */
11+
};
12+
13+
/**
14+
* Output an unicode character in utf-8 encoding
15+
*/
16+
int fputc_utf8(int c, FILE *stream) {
17+
if (c < 0x80) {
18+
return fputc(c, stream);
19+
}
20+
if (c < 0x800) {
21+
if (fputc(0xc0 | (c >> 6), stream) == EOF)
22+
return EOF;
23+
if (fputc(0x80 | (c & 0x7f), stream) == EOF)
24+
return EOF;
25+
} else if (c < 0x10000) {
26+
if (fputc(0xe0 | (c >> 12), stream) == EOF)
27+
return EOF;
28+
if (fputc(0x80 | ((c >> 6) & 0x3f), stream) == EOF)
29+
return EOF;
30+
if (fputc(0x80 | (c & 0x3f), stream) == EOF)
31+
return EOF;
32+
} else {
33+
if (fputc(0xf0 | (c >> 18), stream) == EOF)
34+
return EOF;
35+
if (fputc(0x80 | ((c >> 12) & 0x3f), stream) == EOF)
36+
return EOF;
37+
if (fputc(0x80 | ((c >> 6) & 0x3f), stream) == EOF)
38+
return EOF;
39+
if (fputc(0x80 | (c & 0x3f), stream) == EOF)
40+
return EOF;
41+
}
42+
return c;
43+
}
44+
45+
/**
46+
* Convert from RGB 24 bits to 16 ANSI colors.
47+
* https://en.wikipedia.org/wiki/ANSI_escape_code#3-bit_and_4-bit
48+
*/
49+
unsigned int rgb24toansi(u32 c) {
50+
#ifdef ANSI_COLOR_LUT
51+
unsigned int r = (((c >> 16) & 0xff) * 3 + 1) >> 8;
52+
unsigned int g = (((c >> 8) & 0xff) * 3 + 1) >> 8;
53+
unsigned int b = ((c & 0xff) * 3 + 1) >> 8;
54+
static const unsigned char ansicolors[] = {
55+
/* 0 - G = 0, B = 0 */
56+
0 /* Black */, 1 /* Red */, 61 /* Bright Red */,
57+
/* 3 - G = 1, B = 0 */
58+
2 /* Green */, 3 /* Yellow */, 61 /* Bright Red */,
59+
/* 6 - G = 2, B = 0 */
60+
62 /* Bright Green */, 62 /* Bright Green */, 63 /* Bright Yellow */,
61+
/* 9 - G = 0, B = 1 */
62+
4 /* Blue */, 5 /* Magenta */, 61 /* Bright Red */,
63+
/* 12 - G = 1, B = 1 */
64+
6 /* Cyan */, 7 /* White */, 61 /* Bright Red */,
65+
/* 15 - G = 2, B = 1 */
66+
62 /* Bright Green */, 62 /* Bright Green */, 63 /* Bright Yellow */,
67+
/* 18 - G = 0, B = 2 */
68+
64 /* Bright Blue */, 64 /* Bright Blue */, 65 /* Bright Magenta */,
69+
/* 21 - G = 1, B = 2 */
70+
64 /* Bright Blue */, 64 /* Bright Blue */, 65 /* Bright Magenta */,
71+
/* 24 - G = 2, B = 2 */
72+
66 /* Bright Cyan */, 66 /* Bright Cyan */, 67 /* Bright White */
73+
};
74+
return (unsigned int)ansicolors[r + g * 3 + b * 9];
75+
#else
76+
static const u32 xterm_cols[] = {
77+
0x000000, /* 0 - Black */
78+
0xcd0000, /* 1 - Red */
79+
0x00cd00, /* 2 - Green */
80+
0xcdcd00, /* 3 - Yellow */
81+
0x0000ee, /* 4 - Blue */
82+
0xcd00cd, /* 5 - Magenta */
83+
0x00cdcd, /* 6 - Cyan */
84+
0xe5e5e5, /* 7 - White */
85+
0x7f7f7f, /* 60 - Gray */
86+
0xff0000, /* 61 - Bright Red */
87+
0x00ff00, /* 62 - Bright Green */
88+
0xffff00, /* 63 - Bright Yellow */
89+
0x5c5cff, /* 64 - Bright Blue */
90+
0xff00ff, /* 65 - Bright Magenta */
91+
0x00ffff, /* 66 - Bright Cyan */
92+
0xffffff /* 67 - Bright White */
93+
};
94+
int i, best = 0;
95+
u32 mindist = 0xffffffff;
96+
int r, g, b;
97+
b = c & 0xff;
98+
c >>= 8;
99+
g = c & 0xff;
100+
c >>= 8;
101+
r = c & 0xff;
102+
for (i = 0; i < (int)(sizeof(xterm_cols)/sizeof(u32)); i++) {
103+
int dr, dg, db;
104+
u32 dist; /* squared */
105+
dr = (int)(xterm_cols[i] >> 16) - r;
106+
dg = (int)((xterm_cols[i] >> 8) & 0xff) - g;
107+
db = (int)(xterm_cols[i] & 0xff) - b;
108+
dist = dr * dr + dg * dg + db * db;
109+
if (dist < mindist) {
110+
mindist = dist;
111+
best = i;
112+
}
113+
}
114+
return (unsigned)((best < 8) ? best : best + 52);
115+
#endif
116+
}
117+
118+
/*
119+
* Convert RGB 24 bits to 6x6x6 VGA color cube (16-231)
120+
* and VGA grayscale (232-255)
121+
* https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
122+
*/
123+
unsigned int rgb24tovga216(u32 c) {
124+
#if VGA_NOGRAYSCALE
125+
unsigned int r = (((c >> 16) & 0xff) * 6 + 3) >> 8;
126+
unsigned int g = (((c >> 8) & 0xff) * 6 + 3) >> 8;
127+
unsigned int b = ((c & 0xff) * 6 + 3) >> 8;
128+
#else
129+
unsigned int r = (((c >> 16) & 0xff) * 24 + 12) >> 8;
130+
unsigned int g = (((c >> 8) & 0xff) * 24 + 12) >> 8;
131+
unsigned int b = ((c & 0xff) * 24 + 12) >> 8;
132+
if ((((r ^ g) | (g ^ b)) & ~3) == 0)
133+
return 232 + r; /* 24 grayscale colors */
134+
r >>= 2;
135+
g >>= 2;
136+
b >>= 2;
137+
#endif
138+
return 16 + (r * 6 + g) * 6 + b;
139+
}
140+
141+
/**
142+
* Set foreground color.
143+
* ANSI codes :
144+
* ESC[30m to ESC[37m set foreground color (90 to 97 for bright color)
145+
* ESC[38;5;<n>m set 8 bits foreground color
146+
* ESC[38;2;<r>,<g>,<b>m set 24 bits foreground color
147+
*/
148+
static u32 setfg(u32 fg, enum ansi_color_mode m) {
149+
switch (m) {
150+
case BASIC:
151+
printf("\033[%um", 30 + fg);
152+
break;
153+
case VGACOLORS:
154+
printf("\033[38;5;%um", fg);
155+
break;
156+
case TRUECOLORS:
157+
printf("\033[38;2;%u;%u;%um", (fg >> 16) & 0xff, (fg >> 8) & 0xff, fg & 0xff);
158+
}
159+
return fg;
160+
}
161+
162+
/**
163+
* Set background color.
164+
* ANSI codes :
165+
* ESC[40m to ESC[47m set background color (100 to 107 for bright color)
166+
* ESC[48;5;<n>m set 8 bits background color
167+
* ESC[48;2;<r>,<g>,<b>m set 24 bits background color
168+
* see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
169+
*/
170+
static u32 setbg(u32 bg, enum ansi_color_mode m) {
171+
switch (m) {
172+
case BASIC:
173+
printf("\033[%um", 40 + bg);
174+
break;
175+
case VGACOLORS:
176+
printf("\033[48;5;%um", bg);
177+
break;
178+
case TRUECOLORS:
179+
printf("\033[48;2;%u;%u;%um", (bg >> 16) & 0xff, (bg >> 8) & 0xff, bg & 0xff);
180+
}
181+
return bg;
182+
}
183+
184+
/**
185+
* Output text corresponding to two lines using ANSI escape sequences :
186+
* https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
187+
*
188+
* https://en.wikipedia.org/wiki/Block_Elements
189+
*/
190+
void twolines(const u32 *p, u16 width, int nosecondline, enum ansi_color_mode m) {
191+
#define NOCOL 0xffffffff
192+
int x = (int)width;
193+
u32 fg = NOCOL;
194+
u32 bg = NOCOL;
195+
while (--x >= 0) {
196+
u32 upper, lower;
197+
switch (m) {
198+
case BASIC:
199+
upper = rgb24toansi(p[0]);
200+
lower = nosecondline ? NOCOL : rgb24toansi(p[width]);
201+
break;
202+
case VGACOLORS:
203+
upper = rgb24tovga216(p[0]);
204+
lower = nosecondline ? NOCOL : rgb24tovga216(p[width]);
205+
break;
206+
case TRUECOLORS:
207+
upper = p[0];
208+
lower = nosecondline ? NOCOL : p[width];
209+
}
210+
p++;
211+
if (upper == lower) {
212+
/* both pixels have same color */
213+
if (upper == fg) {
214+
fputc_utf8(0x2588, stdout); /* U+2588 Full block */
215+
} else if(upper == bg) {
216+
fputc(' ', stdout); /* U+0020 space */
217+
} else {
218+
/* Looking for the color that will be useful first, and change the other one */
219+
u32 tochange = fg; /* default */
220+
int x2 = x;
221+
const u32* p2 = p;
222+
while(--x2 >= 0) {
223+
u32 upper2, lower2;
224+
switch (m) {
225+
case BASIC:
226+
upper2 = rgb24toansi(p2[0]);
227+
lower2 = nosecondline ? NOCOL : rgb24toansi(p2[width]);
228+
break;
229+
case VGACOLORS:
230+
upper2 = rgb24tovga216(p2[0]);
231+
lower2 = nosecondline ? NOCOL : rgb24tovga216(p2[width]);
232+
break;
233+
case TRUECOLORS:
234+
upper2 = p2[0];
235+
lower2 = nosecondline ? NOCOL : p2[width];
236+
}
237+
if (bg == upper2 || bg == lower2) {
238+
break;
239+
} else if (fg == upper2 || fg == lower2) {
240+
tochange = bg;
241+
break;
242+
}
243+
p2++;
244+
}
245+
if (tochange == fg) {
246+
fg = setfg(upper, m);
247+
fputc_utf8(0x2588, stdout); /* U+2588 Full block */
248+
} else {
249+
bg = setbg(upper, m);
250+
fputc(' ', stdout); /* U+0020 space */
251+
}
252+
}
253+
} else if (upper == bg || (lower == fg && lower != NOCOL)) {
254+
/* upper pixel is background, lower is foreground */
255+
if (lower != fg) {
256+
fg = setfg(lower, m);
257+
} else if (upper != bg) {
258+
bg = setbg(upper, m);
259+
}
260+
fputc_utf8(0x2584, stdout); /* U+2584 : lower half block */
261+
} else {
262+
/* upper pixel is foreground, lower is background */
263+
if (upper != fg) {
264+
fg = setfg(upper, m);
265+
}
266+
if (lower != bg) {
267+
bg = setbg(lower, m);
268+
}
269+
fputc_utf8(0x2580, stdout); /* U+2580 : upper half block */
270+
}
271+
}
272+
puts("\033[0m"); /* reset colors */
273+
#undef NOCOL
274+
}
275+
276+
static void usage(FILE * out, const char * argv0) {
277+
fprintf(out, "Usage: %s [--tc|--vga|--ansi] <file.gif>\n", argv0);
278+
fprintf(out, " --tc use 24 bits true colors\n");
279+
fprintf(out, " --vga use vga colors\n");
280+
fprintf(out, " --ansi use the standard 16 \"ANSI\" colors\n");
281+
}
282+
283+
int main(int argc, char **argv) {
284+
struct ngiflib_gif *gif;
285+
FILE *fgif;
286+
const char *input_file = NULL;
287+
enum ansi_color_mode mode = BASIC;
288+
int i;
289+
290+
for (i = 1; i < argc; i++) {
291+
if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
292+
usage(stdout, argv[0]);
293+
return 0;
294+
} else if (i == argc - 1) {
295+
/* last argument => filename */
296+
input_file = argv[i];
297+
} else if(strcmp(argv[i], "--tc") == 0) {
298+
mode = TRUECOLORS;
299+
} else if(strcmp(argv[i], "--vga") == 0) {
300+
mode = VGACOLORS;
301+
} else if(strcmp(argv[i], "--ansi") == 0) {
302+
mode = BASIC;
303+
} else {
304+
fprintf(stderr, "Unrecognized argument : \"%s\"\n", argv[i]);
305+
usage(stderr, argv[0]);
306+
return 1;
307+
}
308+
}
309+
310+
if (input_file == NULL) {
311+
fprintf(stderr, "Missing argument\n");
312+
return 1;
313+
}
314+
315+
gif = (struct ngiflib_gif *)ngiflib_malloc(sizeof(struct ngiflib_gif));
316+
#ifdef EXTRA_MALLOC_CHECK
317+
if(gif == NULL) {
318+
printf("Cannot allocate %ld bytes of memory.\n", sizeof(struct ngiflib_gif));
319+
return 4;
320+
}
321+
#endif /* EXTRA_MALLOC_CHECK */
322+
ngiflib_memset(gif, 0, sizeof(struct ngiflib_gif));
323+
324+
fgif = fopen(input_file, "rb");
325+
if (fgif == NULL) {
326+
fprintf(stderr, "Cannot open file \"%s\"\n", input_file);
327+
return 1;
328+
}
329+
#ifdef NGIFLIB_NO_FILE
330+
/* TODO */
331+
#else /* NGIFLIB_NO_FILE */
332+
gif->input.file = fgif;
333+
gif->mode = NGIFLIB_MODE_FROM_FILE;
334+
#endif /* NGIFLIB_NO_FILE */
335+
gif->mode |= NGIFLIB_MODE_TRUE_COLOR;
336+
#if defined(DEBUG)
337+
gif->log = stderr;
338+
#endif
339+
340+
while (LoadGif(gif) == 1) {
341+
int y;
342+
343+
for (y = 0; y < gif->height; y += 2) {
344+
twolines(gif->frbuff.p32 + (y * gif->width), gif->width, y == gif->height - 1, mode);
345+
}
346+
}
347+
fclose(fgif);
348+
GifDestroy(gif);
349+
return 0;
350+
}

samples/Stay_atari.gif

2.28 KB
Loading

0 commit comments

Comments
 (0)