1 /* -*- c -*- */
2
3 /*
4 * rwgif.c
5 *
6 * rwimg
7 *
8 * Copyright (C) 2006 Xavier Martin
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <stdio.h>
26 #include <assert.h>
27 #include <stdlib.h>
28
29 #include <gif_lib.h>
30 #include <string.h>
31
32 typedef struct
33 {
34 GifFileType *file;
35 int width;
36 int height;
37 unsigned char *rgb;
38 } gif_data_t;
39
40 void*
open_gif_file(const char * filename,int * width,int * height)41 open_gif_file (const char *filename, int *width, int *height)
42 {
43 int interlace_offset[] = { 0, 4, 2, 1 };
44 int interlace_jump[] = { 8, 8, 4, 2 };
45 GifColorType *colormap;
46 GifRecordType record_type;
47 GifRowType *buffer = NULL;
48
49 int i, j;
50 int color_index;
51 unsigned char *ptr = NULL;
52
53 gif_data_t *data = (gif_data_t*)malloc(sizeof(gif_data_t));
54
55 assert(data != 0);
56
57 #if GIFLIB_MAJOR >= 5
58 data->file = DGifOpenFileName(filename, NULL);
59 #else
60 data->file = DGifOpenFileName(filename);
61 #endif
62
63 assert(data->file !=0);
64
65 do
66 {
67 assert(DGifGetRecordType(data->file, &record_type) != GIF_ERROR) ;
68
69 switch (record_type)
70 {
71 case IMAGE_DESC_RECORD_TYPE:
72 assert(DGifGetImageDesc(data->file) != GIF_ERROR);
73
74 *width = data->file->Image.Width;
75 *height = data->file->Image.Height;
76 data->width = *width;
77 data->height = *height;
78
79 buffer = malloc(*height * sizeof(GifRowType *));
80 assert(buffer != NULL);
81
82 for (i = 0; i < *height; i++)
83 {
84 buffer[i] = malloc(*width * sizeof(GifPixelType));
85 assert(buffer[i] != NULL);
86 }
87
88 if (data->file->Image.Interlace)
89 {
90 for (i = 0; i < 4; i++)
91 for (j = interlace_offset[i]; j < *height;
92 j += interlace_jump[i])
93 DGifGetLine(data->file, buffer[j], *width);
94 }
95 else
96 {
97 for (i = 0; i < *height; i++)
98 DGifGetLine(data->file, buffer[i], *width);
99 }
100 break;
101 case EXTENSION_RECORD_TYPE:
102 {
103 /* Skip extension blocks */
104 int ext_code;
105 GifByteType *ext;
106 assert(DGifGetExtension(data->file, &ext_code, &ext) != GIF_ERROR);
107
108 while (ext != NULL)
109 {
110 assert(DGifGetExtensionNext(data->file, &ext) != GIF_ERROR);
111 }
112 }
113 break;
114 case TERMINATE_RECORD_TYPE:
115 break;
116 default:
117 fprintf(stderr, "unknown record type in GIF file\n");
118 break;
119 }
120 } while (record_type != TERMINATE_RECORD_TYPE);
121
122
123 colormap = (data->file->Image.ColorMap ? data->file->Image.ColorMap->Colors
124 : data->file->SColorMap->Colors);
125
126 data->rgb = (unsigned char*)malloc( (data->width* data->height * 3) );
127 assert(data->rgb != NULL);
128
129 ptr = data->rgb;
130
131 for (j = 0; j < *height; j++)
132 {
133 for (i = 0; i < *width; i++)
134 {
135 color_index = (int) buffer[j][i];
136 *ptr++ = (unsigned char) colormap[color_index].Red;
137 *ptr++ = (unsigned char) colormap[color_index].Green;
138 *ptr++ = (unsigned char) colormap[color_index].Blue;
139 }
140 free(buffer[j]);
141 }
142 free(buffer);
143
144 #if GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 || GIFLIB_MAJOR > 5
145 assert(DGifCloseFile(data->file, NULL) == GIF_OK);
146 #else
147 assert(DGifCloseFile(data->file) == GIF_OK);
148 #endif
149
150 return data;
151 }
152
153 void
gif_read_lines(void * _data,unsigned char * lines,int num_lines)154 gif_read_lines (void *_data, unsigned char *lines, int num_lines)
155 {
156 gif_data_t *data = (gif_data_t*)_data;
157
158 memcpy(lines, data->rgb, data->width * num_lines * 3);
159 }
160
161 void
gif_free_data(void * _data)162 gif_free_data (void *_data)
163 {
164 gif_data_t *data = (gif_data_t*)_data;
165
166 free(data->rgb);
167 free(data);
168 }
169