Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / gif.c
1 /* gif.c - load GIF image from file
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1998-2003 Alfredo K. Kojima
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <config.h>
23
24 #ifdef USE_GIF
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <gif_lib.h>
31
32 #include "wraster.h"
33
34 static int InterlacedOffset[] = { 0, 4, 2, 1 };
35 static int InterlacedJumps[] = { 8, 8, 4, 2 };
36
37 /*
38 * Partially based on code in gif2rgb from giflib, by Gershon Elber.
39 */
40 RImage *RLoadGIF(RContext * context, char *file, int index)
41 {
42 RImage *image = NULL;
43 unsigned char *cptr;
44 GifFileType *gif = NULL;
45 GifPixelType *buffer = NULL;
46 int i, j, k;
47 int width, height;
48 GifRecordType recType;
49 ColorMapObject *colormap;
50 unsigned char rmap[256];
51 unsigned char gmap[256];
52 unsigned char bmap[256];
53
54 if (index < 0)
55 index = 0;
56
57 /* default error message */
58 RErrorCode = RERR_BADINDEX;
59
60 gif = DGifOpenFileName(file);
61
62 if (!gif) {
63 switch (GifLastError()) {
64 case D_GIF_ERR_OPEN_FAILED:
65 RErrorCode = RERR_OPEN;
66 break;
67 case D_GIF_ERR_READ_FAILED:
68 RErrorCode = RERR_READ;
69 break;
70 default:
71 RErrorCode = RERR_BADIMAGEFILE;
72 break;
73 }
74 return NULL;
75 }
76
77 if (gif->SWidth < 1 || gif->SHeight < 1) {
78 DGifCloseFile(gif);
79 RErrorCode = RERR_BADIMAGEFILE;
80 return NULL;
81 }
82
83 colormap = gif->SColorMap;
84
85 i = 0;
86
87 do {
88 int extCode;
89 GifByteType *extension;
90
91 if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
92 goto giferr;
93 }
94 switch (recType) {
95 case IMAGE_DESC_RECORD_TYPE:
96 if (i++ != index)
97 break;
98
99 if (DGifGetImageDesc(gif) == GIF_ERROR) {
100 goto giferr;
101 }
102
103 width = gif->Image.Width;
104 height = gif->Image.Height;
105
106 if (gif->Image.ColorMap)
107 colormap = gif->Image.ColorMap;
108
109 /* the gif specs talk about a default colormap, but it
110 * doesnt say what the heck is this default colormap */
111 if (!colormap) {
112 /*
113 * Well, since the spec says the colormap can be anything,
114 * lets just render it with whatever garbage the stack
115 * has :)
116 *
117
118 goto bye;
119 */
120 } else {
121 for (j = 0; j < colormap->ColorCount; j++) {
122 rmap[j] = colormap->Colors[j].Red;
123 gmap[j] = colormap->Colors[j].Green;
124 bmap[j] = colormap->Colors[j].Blue;
125 }
126 }
127
128 buffer = malloc(width * sizeof(GifColorType));
129 if (!buffer) {
130 RErrorCode = RERR_NOMEMORY;
131 goto bye;
132 }
133
134 image = RCreateImage(width, height, False);
135 if (!image) {
136 goto bye;
137 }
138
139 if (gif->Image.Interlace) {
140 int l;
141 int pelsPerLine;
142
143 if (RRGBAFormat == image->format)
144 pelsPerLine = width * 4;
145 else
146 pelsPerLine = width * 3;
147
148 for (j = 0; j < 4; j++) {
149 for (k = InterlacedOffset[j]; k < height; k += InterlacedJumps[j]) {
150 if (DGifGetLine(gif, buffer, width) == GIF_ERROR) {
151 goto giferr;
152 }
153 cptr = image->data + (k * pelsPerLine);
154 for (l = 0; l < width; l++) {
155 int pixel = buffer[l];
156 *cptr++ = rmap[pixel];
157 *cptr++ = gmap[pixel];
158 *cptr++ = bmap[pixel];
159 }
160 }
161 }
162 } else {
163 cptr = image->data;
164 for (j = 0; j < height; j++) {
165 if (DGifGetLine(gif, buffer, width) == GIF_ERROR) {
166 goto giferr;
167 }
168 for (k = 0; k < width; k++) {
169 int pixel = buffer[k];
170 *cptr++ = rmap[pixel];
171 *cptr++ = gmap[pixel];
172 *cptr++ = bmap[pixel];
173 if (RRGBAFormat == image->format)
174 cptr++;
175 }
176 }
177 }
178 break;
179
180 case EXTENSION_RECORD_TYPE:
181 /* skip all extension blocks */
182 if (DGifGetExtension(gif, &extCode, &extension) == GIF_ERROR) {
183 goto giferr;
184 }
185 while (extension) {
186 if (DGifGetExtensionNext(gif, &extension) == GIF_ERROR) {
187 goto giferr;
188 }
189 }
190 break;
191
192 default:
193 break;
194 }
195 } while (recType != TERMINATE_RECORD_TYPE && i <= index);
196
197 /* yuck! */
198 goto did_not_get_any_errors;
199 giferr:
200 switch (GifLastError()) {
201 case D_GIF_ERR_OPEN_FAILED:
202 RErrorCode = RERR_OPEN;
203 break;
204 case D_GIF_ERR_READ_FAILED:
205 RErrorCode = RERR_READ;
206 break;
207 default:
208 RErrorCode = RERR_BADIMAGEFILE;
209 break;
210 }
211 bye:
212 if (image)
213 RReleaseImage(image);
214 image = NULL;
215 did_not_get_any_errors:
216
217 if (buffer)
218 free(buffer);
219
220 if (gif)
221 DGifCloseFile(gif);
222
223 return image;
224 }
225
226 #endif /* USE_GIF */