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