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 */