I'll push a formatting guide at some point. There may still be outstanding changes, but please feel free to resolve those as you arrive a them. To the best of my knowledge, there is no changes to the actual code content, but the formatter does have the occasional bug. If you run into an issue, please fix it!
713 lines
19 KiB
C
713 lines
19 KiB
C
/* GIF reading routines based on those in pbmplus:ppm/giftoppm.c, bearing
|
|
* following copyright notice:
|
|
*/
|
|
|
|
/* +-------------------------------------------------------------------+ */
|
|
/* | Copyright 1990, David Koblas. | */
|
|
/* | Permission to use, copy, modify, and distribute this software | */
|
|
/* | and its documentation for any purpose and without fee is hereby | */
|
|
/* | granted, provided that the above copyright notice appear in all | */
|
|
/* | copies and that both that copyright notice and this permission | */
|
|
/* | notice appear in supporting documentation. This software is | */
|
|
/* | provided "as is" without express or implied warranty. | */
|
|
/* +-------------------------------------------------------------------+ */
|
|
|
|
/*
|
|
* $NHDT-Date: 1431192770 2015/05/09 17:32:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.4 $
|
|
* $Date: 2002/01/05 21:06:02 $ $Revision: 1.1 $
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "tile.h"
|
|
|
|
#ifndef MONITOR_HEAP
|
|
extern long *FDECL(alloc, (unsigned int));
|
|
#endif
|
|
|
|
#define PPM_ASSIGN(p, red, grn, blu) \
|
|
do { \
|
|
(p).r = (red); \
|
|
(p).g = (grn); \
|
|
(p).b = (blu); \
|
|
} while (0)
|
|
|
|
#define MAX_LWZ_BITS 12
|
|
|
|
#define INTERLACE 0x40
|
|
#define LOCALCOLORMAP 0x80
|
|
#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
|
|
|
|
#define ReadOK(file, buffer, len) \
|
|
(fread((genericptr_t) buffer, (int) len, 1, file) != 0)
|
|
|
|
#define LM_to_uint(a, b) (((b) << 8) | (a))
|
|
|
|
struct gifscreen {
|
|
int Width;
|
|
int Height;
|
|
int Colors;
|
|
int ColorResolution;
|
|
int Background;
|
|
int AspectRatio;
|
|
int Interlace;
|
|
} GifScreen;
|
|
|
|
struct {
|
|
int transparent;
|
|
int delayTime;
|
|
int inputFlag;
|
|
int disposal;
|
|
} Gif89 = { -1, -1, -1, 0 };
|
|
|
|
int ZeroDataBlock = FALSE;
|
|
|
|
static FILE *gif_file;
|
|
static int tiles_across, tiles_down, curr_tiles_across, curr_tiles_down;
|
|
static pixel **image;
|
|
static unsigned char input_code_size;
|
|
|
|
static int FDECL(GetDataBlock, (FILE * fd, unsigned char *buf));
|
|
static void FDECL(DoExtension, (FILE * fd, int label));
|
|
static boolean FDECL(ReadColorMap, (FILE * fd, int number));
|
|
static void FDECL(read_header, (FILE * fd));
|
|
static int FDECL(GetCode, (FILE * fd, int code_size, int flag));
|
|
static int FDECL(LWZReadByte, (FILE * fd, int flag, int input_code_size));
|
|
static void FDECL(ReadInterleavedImage, (FILE * fd, int len, int height));
|
|
static void FDECL(ReadTileStrip, (FILE * fd, int len));
|
|
|
|
/* These should be in gif.h, but there isn't one. */
|
|
boolean FDECL(fopen_gif_file, (const char *, const char *));
|
|
boolean FDECL(read_gif_tile, (pixel(*) [TILE_X]));
|
|
int NDECL(fclose_gif_file);
|
|
|
|
static int
|
|
GetDataBlock(fd, buf)
|
|
FILE *fd;
|
|
unsigned char *buf;
|
|
{
|
|
unsigned char count;
|
|
|
|
if (!ReadOK(fd, &count, 1)) {
|
|
Fprintf(stderr, "error in getting DataBlock size\n");
|
|
return -1;
|
|
}
|
|
|
|
ZeroDataBlock = (count == 0);
|
|
|
|
if ((count != 0) && (!ReadOK(fd, buf, count))) {
|
|
Fprintf(stderr, "error in reading DataBlock\n");
|
|
return -1;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static void
|
|
DoExtension(fd, label)
|
|
FILE *fd;
|
|
int label;
|
|
{
|
|
static char buf[256];
|
|
char *str;
|
|
|
|
switch (label) {
|
|
case 0x01: /* Plain Text Extension */
|
|
str = "Plain Text Extension";
|
|
#ifdef notdef
|
|
if (GetDataBlock(fd, (unsigned char *) buf) == 0)
|
|
;
|
|
|
|
lpos = LM_to_uint(buf[0], buf[1]);
|
|
tpos = LM_to_uint(buf[2], buf[3]);
|
|
width = LM_to_uint(buf[4], buf[5]);
|
|
height = LM_to_uint(buf[6], buf[7]);
|
|
cellw = buf[8];
|
|
cellh = buf[9];
|
|
foreground = buf[10];
|
|
background = buf[11];
|
|
|
|
while (GetDataBlock(fd, (unsigned char *) buf) != 0) {
|
|
PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v], cmap[CM_GREEN][v],
|
|
cmap[CM_BLUE][v]);
|
|
++index;
|
|
}
|
|
|
|
return;
|
|
#else
|
|
break;
|
|
#endif
|
|
case 0xff: /* Application Extension */
|
|
str = "Application Extension";
|
|
break;
|
|
case 0xfe: /* Comment Extension */
|
|
str = "Comment Extension";
|
|
while (GetDataBlock(fd, (unsigned char *) buf) != 0) {
|
|
Fprintf(stderr, "gif comment: %s\n", buf);
|
|
}
|
|
return;
|
|
case 0xf9: /* Graphic Control Extension */
|
|
str = "Graphic Control Extension";
|
|
(void) GetDataBlock(fd, (unsigned char *) buf);
|
|
Gif89.disposal = (buf[0] >> 2) & 0x7;
|
|
Gif89.inputFlag = (buf[0] >> 1) & 0x1;
|
|
Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
|
|
if ((buf[0] & 0x1) != 0)
|
|
Gif89.transparent = buf[3];
|
|
|
|
while (GetDataBlock(fd, (unsigned char *) buf) != 0)
|
|
;
|
|
return;
|
|
default:
|
|
str = buf;
|
|
Sprintf(buf, "UNKNOWN (0x%02x)", label);
|
|
break;
|
|
}
|
|
|
|
Fprintf(stderr, "got a '%s' extension\n", str);
|
|
|
|
while (GetDataBlock(fd, (unsigned char *) buf) != 0)
|
|
;
|
|
}
|
|
|
|
static boolean
|
|
ReadColorMap(fd, number)
|
|
FILE *fd;
|
|
int number;
|
|
{
|
|
int i;
|
|
unsigned char rgb[3];
|
|
|
|
for (i = 0; i < number; ++i) {
|
|
if (!ReadOK(fd, rgb, sizeof(rgb))) {
|
|
return (FALSE);
|
|
}
|
|
|
|
ColorMap[CM_RED][i] = rgb[0];
|
|
ColorMap[CM_GREEN][i] = rgb[1];
|
|
ColorMap[CM_BLUE][i] = rgb[2];
|
|
}
|
|
colorsinmap = number;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Read gif header, including colormaps. We expect only one image per
|
|
* file, so if that image has a local colormap, overwrite the global one.
|
|
*/
|
|
static void
|
|
read_header(fd)
|
|
FILE *fd;
|
|
{
|
|
unsigned char buf[16];
|
|
unsigned char c;
|
|
char version[4];
|
|
|
|
if (!ReadOK(fd, buf, 6)) {
|
|
Fprintf(stderr, "error reading magic number\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (strncmp((genericptr_t) buf, "GIF", 3) != 0) {
|
|
Fprintf(stderr, "not a GIF file\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
(void) strncpy(version, (char *) buf + 3, 3);
|
|
version[3] = '\0';
|
|
|
|
if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
|
|
Fprintf(stderr, "bad version number, not '87a' or '89a'\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (!ReadOK(fd, buf, 7)) {
|
|
Fprintf(stderr, "failed to read screen descriptor\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
GifScreen.Width = LM_to_uint(buf[0], buf[1]);
|
|
GifScreen.Height = LM_to_uint(buf[2], buf[3]);
|
|
GifScreen.Colors = 2 << (buf[4] & 0x07);
|
|
GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
|
|
GifScreen.Background = buf[5];
|
|
GifScreen.AspectRatio = buf[6];
|
|
|
|
if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
|
|
if (!ReadColorMap(fd, GifScreen.Colors)) {
|
|
Fprintf(stderr, "error reading global colormap\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) {
|
|
Fprintf(stderr, "warning - non-square pixels\n");
|
|
}
|
|
|
|
for (;;) {
|
|
if (!ReadOK(fd, &c, 1)) {
|
|
Fprintf(stderr, "EOF / read error on image data\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (c == ';') { /* GIF terminator */
|
|
return;
|
|
}
|
|
|
|
if (c == '!') { /* Extension */
|
|
if (!ReadOK(fd, &c, 1)) {
|
|
Fprintf(stderr,
|
|
"EOF / read error on extension function code\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
DoExtension(fd, (int) c);
|
|
continue;
|
|
}
|
|
|
|
if (c != ',') { /* Not a valid start character */
|
|
Fprintf(stderr, "bogus character 0x%02x, ignoring\n", (int) c);
|
|
continue;
|
|
}
|
|
|
|
if (!ReadOK(fd, buf, 9)) {
|
|
Fprintf(stderr, "couldn't read left/top/width/height\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (BitSet(buf[8], LOCALCOLORMAP)) {
|
|
/* replace global color map with local */
|
|
GifScreen.Colors = 1 << ((buf[8] & 0x07) + 1);
|
|
if (!ReadColorMap(fd, GifScreen.Colors)) {
|
|
Fprintf(stderr, "error reading local colormap\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
if (GifScreen.Width != LM_to_uint(buf[4], buf[5])) {
|
|
Fprintf(stderr, "warning: widths don't match\n");
|
|
GifScreen.Width = LM_to_uint(buf[4], buf[5]);
|
|
}
|
|
if (GifScreen.Height != LM_to_uint(buf[6], buf[7])) {
|
|
Fprintf(stderr, "warning: heights don't match\n");
|
|
GifScreen.Height = LM_to_uint(buf[6], buf[7]);
|
|
}
|
|
GifScreen.Interlace = BitSet(buf[8], INTERLACE);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static int
|
|
GetCode(fd, code_size, flag)
|
|
FILE *fd;
|
|
int code_size;
|
|
int flag;
|
|
{
|
|
static unsigned char buf[280];
|
|
static int curbit, lastbit, done, last_byte;
|
|
int i, j, ret;
|
|
unsigned char count;
|
|
|
|
if (flag) {
|
|
curbit = 0;
|
|
lastbit = 0;
|
|
done = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
if ((curbit + code_size) >= lastbit) {
|
|
if (done) {
|
|
if (curbit >= lastbit)
|
|
Fprintf(stderr, "ran off the end of my bits\n");
|
|
return -1;
|
|
}
|
|
buf[0] = buf[last_byte - 2];
|
|
buf[1] = buf[last_byte - 1];
|
|
|
|
if ((count = GetDataBlock(fd, &buf[2])) == 0)
|
|
done = TRUE;
|
|
|
|
last_byte = 2 + count;
|
|
curbit = (curbit - lastbit) + 16;
|
|
lastbit = (2 + count) * 8;
|
|
}
|
|
|
|
ret = 0;
|
|
for (i = curbit, j = 0; j < code_size; ++i, ++j)
|
|
ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
|
|
|
|
curbit += code_size;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
LWZReadByte(fd, flag, input_code_size)
|
|
FILE *fd;
|
|
int flag;
|
|
int input_code_size;
|
|
{
|
|
static int fresh = FALSE;
|
|
int code, incode;
|
|
static int code_size, set_code_size;
|
|
static int max_code, max_code_size;
|
|
static int firstcode, oldcode;
|
|
static int clear_code, end_code;
|
|
static int table[2][(1 << MAX_LWZ_BITS)];
|
|
static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
|
|
register int i;
|
|
|
|
if (flag) {
|
|
set_code_size = input_code_size;
|
|
code_size = set_code_size + 1;
|
|
clear_code = 1 << set_code_size;
|
|
end_code = clear_code + 1;
|
|
max_code_size = 2 * clear_code;
|
|
max_code = clear_code + 2;
|
|
|
|
(void) GetCode(fd, 0, TRUE);
|
|
|
|
fresh = TRUE;
|
|
|
|
for (i = 0; i < clear_code; ++i) {
|
|
table[0][i] = 0;
|
|
table[1][i] = i;
|
|
}
|
|
for (; i < (1 << MAX_LWZ_BITS); ++i)
|
|
table[0][i] = table[1][0] = 0;
|
|
|
|
sp = stack;
|
|
|
|
return 0;
|
|
} else if (fresh) {
|
|
fresh = FALSE;
|
|
do {
|
|
firstcode = oldcode = GetCode(fd, code_size, FALSE);
|
|
} while (firstcode == clear_code);
|
|
return firstcode;
|
|
}
|
|
|
|
if (sp > stack)
|
|
return *--sp;
|
|
|
|
while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
|
|
if (code == clear_code) {
|
|
for (i = 0; i < clear_code; ++i) {
|
|
table[0][i] = 0;
|
|
table[1][i] = i;
|
|
}
|
|
for (; i < (1 << MAX_LWZ_BITS); ++i)
|
|
table[0][i] = table[1][i] = 0;
|
|
code_size = set_code_size + 1;
|
|
max_code_size = 2 * clear_code;
|
|
max_code = clear_code + 2;
|
|
sp = stack;
|
|
firstcode = oldcode = GetCode(fd, code_size, FALSE);
|
|
return firstcode;
|
|
} else if (code == end_code) {
|
|
int count;
|
|
unsigned char buf[260];
|
|
|
|
if (ZeroDataBlock)
|
|
return -2;
|
|
|
|
while ((count = GetDataBlock(fd, buf)) > 0)
|
|
;
|
|
|
|
if (count != 0)
|
|
Fprintf(stderr,
|
|
"missing EOD in data stream (common occurrence)\n");
|
|
return -2;
|
|
}
|
|
|
|
incode = code;
|
|
|
|
if (code >= max_code) {
|
|
*sp++ = firstcode;
|
|
code = oldcode;
|
|
}
|
|
|
|
while (code >= clear_code) {
|
|
*sp++ = table[1][code];
|
|
if (code == table[0][code]) {
|
|
Fprintf(stderr, "circular table entry BIG ERROR\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
code = table[0][code];
|
|
}
|
|
|
|
*sp++ = firstcode = table[1][code];
|
|
|
|
if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
|
|
table[0][code] = oldcode;
|
|
table[1][code] = firstcode;
|
|
++max_code;
|
|
if ((max_code >= max_code_size)
|
|
&& (max_code_size < (1 << MAX_LWZ_BITS))) {
|
|
max_code_size *= 2;
|
|
++code_size;
|
|
}
|
|
}
|
|
|
|
oldcode = incode;
|
|
|
|
if (sp > stack)
|
|
return *--sp;
|
|
}
|
|
return code;
|
|
}
|
|
|
|
static void
|
|
ReadInterleavedImage(fd, len, height)
|
|
FILE *fd;
|
|
int len, height;
|
|
{
|
|
int v;
|
|
int xpos = 0, ypos = 0, pass = 0;
|
|
|
|
while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) {
|
|
PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v],
|
|
ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]);
|
|
|
|
++xpos;
|
|
if (xpos == len) {
|
|
xpos = 0;
|
|
switch (pass) {
|
|
case 0:
|
|
case 1:
|
|
ypos += 8;
|
|
break;
|
|
case 2:
|
|
ypos += 4;
|
|
break;
|
|
case 3:
|
|
ypos += 2;
|
|
break;
|
|
}
|
|
|
|
if (ypos >= height) {
|
|
++pass;
|
|
switch (pass) {
|
|
case 1:
|
|
ypos = 4;
|
|
break;
|
|
case 2:
|
|
ypos = 2;
|
|
break;
|
|
case 3:
|
|
ypos = 1;
|
|
break;
|
|
default:
|
|
goto fini;
|
|
}
|
|
}
|
|
}
|
|
if (ypos >= height)
|
|
break;
|
|
}
|
|
|
|
fini:
|
|
if (LWZReadByte(fd, FALSE, (int) input_code_size) >= 0)
|
|
Fprintf(stderr, "too much input data, ignoring extra...\n");
|
|
}
|
|
|
|
static void
|
|
ReadTileStrip(fd, len)
|
|
FILE *fd;
|
|
int len;
|
|
{
|
|
int v;
|
|
int xpos = 0, ypos = 0;
|
|
|
|
while ((v = LWZReadByte(fd, FALSE, (int) input_code_size)) >= 0) {
|
|
PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v],
|
|
ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]);
|
|
|
|
++xpos;
|
|
if (xpos == len) {
|
|
xpos = 0;
|
|
++ypos;
|
|
}
|
|
if (ypos >= TILE_Y)
|
|
break;
|
|
}
|
|
}
|
|
|
|
boolean
|
|
fopen_gif_file(filename, type)
|
|
const char *filename;
|
|
const char *type;
|
|
{
|
|
int i;
|
|
|
|
if (strcmp(type, RDBMODE)) {
|
|
Fprintf(stderr, "using reading routine for non-reading?\n");
|
|
return FALSE;
|
|
}
|
|
gif_file = fopen(filename, type);
|
|
if (gif_file == (FILE *) 0) {
|
|
Fprintf(stderr, "cannot open gif file %s\n", filename);
|
|
return FALSE;
|
|
}
|
|
|
|
read_header(gif_file);
|
|
if (GifScreen.Width % TILE_X) {
|
|
Fprintf(stderr, "error: width %d not divisible by %d\n",
|
|
GifScreen.Width, TILE_X);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
tiles_across = GifScreen.Width / TILE_X;
|
|
curr_tiles_across = 0;
|
|
if (GifScreen.Height % TILE_Y) {
|
|
Fprintf(stderr, "error: height %d not divisible by %d\n",
|
|
GifScreen.Height, TILE_Y);
|
|
/* exit(EXIT_FAILURE) */;
|
|
}
|
|
tiles_down = GifScreen.Height / TILE_Y;
|
|
curr_tiles_down = 0;
|
|
|
|
if (GifScreen.Interlace) {
|
|
/* sigh -- hope this doesn't happen on micros */
|
|
image = (pixel **) alloc(GifScreen.Height * sizeof(pixel *));
|
|
for (i = 0; i < GifScreen.Height; i++) {
|
|
image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel));
|
|
}
|
|
} else {
|
|
image = (pixel **) alloc(TILE_Y * sizeof(pixel *));
|
|
for (i = 0; i < TILE_Y; i++) {
|
|
image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel));
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Initialize the Compression routines
|
|
*/
|
|
if (!ReadOK(gif_file, &input_code_size, 1)) {
|
|
Fprintf(stderr, "EOF / read error on image data\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (LWZReadByte(gif_file, TRUE, (int) input_code_size) < 0) {
|
|
Fprintf(stderr, "error reading image\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* read first section */
|
|
if (GifScreen.Interlace) {
|
|
ReadInterleavedImage(gif_file, GifScreen.Width, GifScreen.Height);
|
|
} else {
|
|
ReadTileStrip(gif_file, GifScreen.Width);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* Read a tile. Returns FALSE when there are no more tiles */
|
|
boolean
|
|
read_gif_tile(pixels)
|
|
pixel (*pixels)[TILE_X];
|
|
{
|
|
int i, j;
|
|
|
|
if (curr_tiles_down >= tiles_down)
|
|
return FALSE;
|
|
if (curr_tiles_across == tiles_across) {
|
|
curr_tiles_across = 0;
|
|
curr_tiles_down++;
|
|
if (curr_tiles_down >= tiles_down)
|
|
return FALSE;
|
|
if (!GifScreen.Interlace)
|
|
ReadTileStrip(gif_file, GifScreen.Width);
|
|
}
|
|
if (GifScreen.Interlace) {
|
|
for (j = 0; j < TILE_Y; j++) {
|
|
for (i = 0; i < TILE_X; i++) {
|
|
pixels[j][i] = image[curr_tiles_down * TILE_Y
|
|
+ j][curr_tiles_across * TILE_X + i];
|
|
}
|
|
}
|
|
} else {
|
|
for (j = 0; j < TILE_Y; j++) {
|
|
for (i = 0; i < TILE_X; i++) {
|
|
pixels[j][i] = image[j][curr_tiles_across * TILE_X + i];
|
|
}
|
|
}
|
|
}
|
|
curr_tiles_across++;
|
|
|
|
/* check for "filler" tile */
|
|
for (j = 0; j < TILE_Y; j++) {
|
|
for (i = 0; i < TILE_X && i < 4; i += 2) {
|
|
if (pixels[j][i].r != ColorMap[CM_RED][0]
|
|
|| pixels[j][i].g != ColorMap[CM_GREEN][0]
|
|
|| pixels[j][i].b != ColorMap[CM_BLUE][0]
|
|
|| pixels[j][i + 1].r != ColorMap[CM_RED][1]
|
|
|| pixels[j][i + 1].g != ColorMap[CM_GREEN][1]
|
|
|| pixels[j][i + 1].b != ColorMap[CM_BLUE][1])
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int
|
|
fclose_gif_file()
|
|
{
|
|
int i;
|
|
|
|
if (GifScreen.Interlace) {
|
|
for (i = 0; i < GifScreen.Height; i++) {
|
|
free((genericptr_t) image[i]);
|
|
}
|
|
free((genericptr_t) image);
|
|
} else {
|
|
for (i = 0; i < TILE_Y; i++) {
|
|
free((genericptr_t) image[i]);
|
|
}
|
|
free((genericptr_t) image);
|
|
}
|
|
return (fclose(gif_file));
|
|
}
|
|
|
|
#ifndef AMIGA
|
|
static char *std_args[] = { "tilemap", /* dummy argv[0] */
|
|
"monsters.gif", "monsters.txt", "objects.gif",
|
|
"objects.txt", "other.gif", "other.txt" };
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
pixel pixels[TILE_Y][TILE_X];
|
|
|
|
if (argc == 1) {
|
|
argc = SIZE(std_args);
|
|
argv = std_args;
|
|
} else if (argc != 3) {
|
|
Fprintf(stderr, "usage: gif2txt giffile txtfile\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while (argc > 1) {
|
|
if (!fopen_gif_file(argv[1], RDBMODE))
|
|
exit(EXIT_FAILURE);
|
|
|
|
init_colormap();
|
|
|
|
if (!fopen_text_file(argv[2], WRTMODE)) {
|
|
(void) fclose_gif_file();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while (read_gif_tile(pixels))
|
|
(void) write_text_tile(pixels);
|
|
|
|
(void) fclose_gif_file();
|
|
(void) fclose_text_file();
|
|
|
|
argc -= 2;
|
|
argv += 2;
|
|
}
|
|
exit(EXIT_SUCCESS);
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
#endif
|