1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <string.h>
5 #include <gif_lib.h>
6
7 #include "readers.h"
8
9 #if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR >= 5)
10 #define GIF5DATA(e) e
PrintGifError(int err)11 static void PrintGifError(int err)
12 {
13 fprintf(stderr, "GIF library error: %s\n", GifErrorString(err));
14 }
15 #else
16 #define GIF5DATA(x)
17 #define PrintGifError(e) PrintGifError()
18 #define DGifOpenFileHandle(x,e) DGifOpenFileHandle(x)
19 #define DGifCloseFile(x,e) DGifCloseFile(x)
20 #endif
21
22 struct gif_state {
23 FILE *infile;
24 GifFileType *gif;
25 GifPixelType *row;
26 GifPixelType *il;
27 int w,h;
28 };
29
30 static GifRecordType
gif_fileread(struct gif_state * h)31 gif_fileread(struct gif_state *h)
32 {
33 GifRecordType RecordType;
34 GifByteType *Extension;
35 int ExtCode, rc;
36 char *type;
37
38 for (;;) {
39 if (GIF_ERROR == DGifGetRecordType(h->gif,&RecordType)) {
40 if (debug)
41 fprintf(stderr,"gif: DGifGetRecordType failed\n");
42 PrintGifError(h->gif->Error);
43 return -1;
44 }
45 switch (RecordType) {
46 case IMAGE_DESC_RECORD_TYPE:
47 if (debug)
48 fprintf(stderr,"gif: IMAGE_DESC_RECORD_TYPE found\n");
49 return RecordType;
50 case EXTENSION_RECORD_TYPE:
51 if (debug)
52 fprintf(stderr,"gif: EXTENSION_RECORD_TYPE found\n");
53 for (rc = DGifGetExtension(h->gif,&ExtCode,&Extension);
54 NULL != Extension;
55 rc = DGifGetExtensionNext(h->gif,&Extension)) {
56 if (rc == GIF_ERROR) {
57 if (debug)
58 fprintf(stderr,"gif: DGifGetExtension failed\n");
59 PrintGifError(h->gif->Error);
60 return -1;
61 }
62 if (debug) {
63 switch (ExtCode) {
64 case COMMENT_EXT_FUNC_CODE: type="comment"; break;
65 case GRAPHICS_EXT_FUNC_CODE: type="graphics"; break;
66 case PLAINTEXT_EXT_FUNC_CODE: type="plaintext"; break;
67 case APPLICATION_EXT_FUNC_CODE: type="appl"; break;
68 default: type="???"; break;
69 }
70 fprintf(stderr,"gif: extcode=0x%x [%s]\n",ExtCode,type);
71 }
72 }
73 break;
74 case TERMINATE_RECORD_TYPE:
75 if (debug)
76 fprintf(stderr,"gif: TERMINATE_RECORD_TYPE found\n");
77 return RecordType;
78 default:
79 if (debug)
80 fprintf(stderr,"gif: unknown record type [%d]\n",RecordType);
81 return -1;
82 }
83 }
84 }
85
86 #if 0
87 static void
88 gif_skipimage(struct gif_state *h)
89 {
90 unsigned char *line;
91 int i;
92
93 if (debug)
94 fprintf(stderr,"gif: skipping image record ...\n");
95 DGifGetImageDesc(h->gif);
96 line = malloc(h->gif->SWidth);
97 for (i = 0; i < h->gif->SHeight; i++)
98 DGifGetLine(h->gif, line, h->gif->SWidth);
99 free(line);
100 }
101 #endif
102
103 static void*
gif_init(FILE * fp,char * filename,unsigned int page,struct ida_image_info * info,int thumbnail)104 gif_init(FILE *fp, char *filename, unsigned int page,
105 struct ida_image_info *info, int thumbnail)
106 {
107 struct gif_state *h;
108 GifRecordType RecordType;
109 int i, image = 0;
110 GIF5DATA(int giferror = 0;)
111
112 h = malloc(sizeof(*h));
113 memset(h,0,sizeof(*h));
114
115 h->infile = fp;
116 h->gif = DGifOpenFileHandle(fileno(fp), &giferror);
117 h->row = malloc(h->gif->SWidth * sizeof(GifPixelType));
118
119 while (0 == image) {
120 RecordType = gif_fileread(h);
121 switch (RecordType) {
122 case IMAGE_DESC_RECORD_TYPE:
123 if (GIF_ERROR == DGifGetImageDesc(h->gif)) {
124 if (debug)
125 fprintf(stderr,"gif: DGifGetImageDesc failed\n");
126 PrintGifError(giferror);
127 }
128 if (NULL == h->gif->SColorMap &&
129 NULL == h->gif->Image.ColorMap) {
130 if (debug)
131 fprintf(stderr,"gif: oops: no colormap found\n");
132 goto oops;
133 }
134 #if 0
135 info->width = h->w = h->gif->SWidth;
136 info->height = h->h = h->gif->SHeight;
137 #else
138 info->width = h->w = h->gif->Image.Width;
139 info->height = h->h = h->gif->Image.Height;
140 #endif
141 info->npages = 1;
142 image = 1;
143 if (debug)
144 fprintf(stderr,"gif: reading image record ...\n");
145 if (h->gif->Image.Interlace) {
146 if (debug)
147 fprintf(stderr,"gif: interlaced\n");
148 h->il = malloc(h->w * h->h * sizeof(GifPixelType));
149 for (i = 0; i < h->h; i += 8)
150 DGifGetLine(h->gif, h->il + h->w*i,h->w);
151 for (i = 4; i < h->gif->SHeight; i += 8)
152 DGifGetLine(h->gif, h->il + h->w*i,h->w);
153 for (i = 2; i < h->gif->SHeight; i += 4)
154 DGifGetLine(h->gif, h->il + h->w*i,h->w);
155 }
156 break;
157 case TERMINATE_RECORD_TYPE:
158 default:
159 goto oops;
160 }
161 }
162 if (0 == info->width || 0 == info->height)
163 goto oops;
164
165 if (debug)
166 fprintf(stderr,"gif: s=%dx%d i=%dx%d\n",
167 h->gif->SWidth,h->gif->SHeight,
168 h->gif->Image.Width,h->gif->Image.Height);
169 return h;
170
171 oops:
172 if (debug)
173 fprintf(stderr,"gif: fatal error, aborting\n");
174 DGifCloseFile(h->gif, NULL);
175 fclose(h->infile);
176 free(h->row);
177 free(h);
178 return NULL;
179 }
180
181 static void
gif_read(unsigned char * dst,unsigned int line,void * data)182 gif_read(unsigned char *dst, unsigned int line, void *data)
183 {
184 struct gif_state *h = data;
185 GifColorType *cmap;
186 int x;
187
188 if (h->gif->Image.Interlace) {
189 if (line % 2) {
190 DGifGetLine(h->gif, h->row, h->w);
191 } else {
192 memcpy(h->row, h->il + h->w * line, h->w);
193 }
194 } else {
195 DGifGetLine(h->gif, h->row, h->w);
196 }
197 cmap = h->gif->Image.ColorMap ?
198 h->gif->Image.ColorMap->Colors : h->gif->SColorMap->Colors;
199 for (x = 0; x < h->w; x++) {
200 dst[0] = cmap[h->row[x]].Red;
201 dst[1] = cmap[h->row[x]].Green;
202 dst[2] = cmap[h->row[x]].Blue;
203 dst += 3;
204 }
205 }
206
207 static void
gif_done(void * data)208 gif_done(void *data)
209 {
210 struct gif_state *h = data;
211
212 if (debug)
213 fprintf(stderr,"gif: done, cleaning up\n");
214 DGifCloseFile(h->gif, NULL);
215 fclose(h->infile);
216 if (h->il)
217 free(h->il);
218 free(h->row);
219 free(h);
220 }
221
222 static struct ida_loader gif_loader = {
223 magic: "GIF",
224 moff: 0,
225 mlen: 3,
226 name: "giflib",
227 init: gif_init,
228 read: gif_read,
229 done: gif_done,
230 };
231
init_rd(void)232 static void __init init_rd(void)
233 {
234 load_register(&gif_loader);
235 }
236