1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
25 GIF image support using giflib.
35 #include "../../config.h"
36 #include "core/GP_Pixel.h"
37 #include "core/GP_GetPutPixel.gen.h"
38 #include "gfx/GP_Fill.h"
39 #include "core/GP_Debug.h"
47 int GP_OpenGIF(const char *src_path
, void **f
)
51 gf
= DGifOpenFileName(src_path
);
54 //TODO: error handling
59 GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp",
60 gf
->SWidth
, gf
->SHeight
, gf
->SColorResolution
,
61 gf
->SColorMap
? gf
->SColorMap
->BitsPerPixel
: -1);
68 static const char *rec_type_name(GifRecordType rec_type
)
71 case UNDEFINED_RECORD_TYPE
:
73 case SCREEN_DESC_RECORD_TYPE
:
75 case IMAGE_DESC_RECORD_TYPE
:
77 case EXTENSION_RECORD_TYPE
:
79 case TERMINATE_RECORD_TYPE
:
86 static const char *gif_err_name(int err
)
89 case E_GIF_ERR_OPEN_FAILED
:
90 return "E_GIF_ERR_OPEN_FAILED";
91 case E_GIF_ERR_WRITE_FAILED
:
92 return "E_GIF_ERR_WRITE_FAILED";
93 case E_GIF_ERR_HAS_SCRN_DSCR
:
94 return "E_GIF_ERR_HAS_SCRN_DSCR";
95 case E_GIF_ERR_HAS_IMAG_DSCR
:
96 return "E_GIF_ERR_HAS_IMAG_DSCR";
97 case E_GIF_ERR_NO_COLOR_MAP
:
98 return "E_GIF_ERR_NO_COLOR_MAP";
99 case E_GIF_ERR_DATA_TOO_BIG
:
100 return "E_GIF_ERR_DATA_TOO_BIG";
101 case E_GIF_ERR_NOT_ENOUGH_MEM
:
102 return "E_GIF_ERR_NOT_ENOUGH_MEM";
103 case E_GIF_ERR_DISK_IS_FULL
:
104 return "E_GIF_ERR_DISK_IS_FULL";
105 case E_GIF_ERR_CLOSE_FAILED
:
106 return "E_GIF_ERR_CLOSE_FAILED";
107 case E_GIF_ERR_NOT_WRITEABLE
:
108 return "E_GIF_ERR_NOT_WRITEABLE";
114 static int read_extensions(GifFileType
*gf
)
116 uint8_t *gif_ext_ptr
;
119 //TODO: Should we free them?
121 if (DGifGetExtension(gf
, &gif_ext_type
, &gif_ext_ptr
) != GIF_OK
) {
122 GP_DEBUG(1, "DGifGetExtension() error %s (%i)",
123 gif_err_name(GifLastError()), GifLastError());
127 GP_DEBUG(2, "Have GIF extension type %i (ignoring)", gif_ext_type
);
130 if (DGifGetExtensionNext(gf
, &gif_ext_ptr
) != GIF_OK
) {
131 GP_DEBUG(1, "DGifGetExtension() error %s (%i)",
132 gif_err_name(GifLastError()), GifLastError());
136 } while (gif_ext_ptr
!= NULL
);
141 static inline GifColorType
*get_color_from_map(ColorMapObject
*map
, int idx
)
143 if (map
->ColorCount
<= idx
) {
144 GP_DEBUG(1, "Invalid colormap index %i (%i max)",
145 map
->ColorCount
, idx
);
149 return &map
->Colors
[idx
];
152 static inline GP_Pixel
get_color(GifFileType
*gf
, uint32_t idx
)
156 //TODO: no color map?
157 if (gf
->SColorMap
== NULL
)
160 color
= get_color_from_map(gf
->SColorMap
, idx
);
162 return GP_Pixel_CREATE_RGB888(color
->Red
, color
->Green
, color
->Blue
);
165 static int get_bg_color(GifFileType
*gf
, GP_Pixel
*pixel
)
169 if (gf
->SColorMap
== NULL
)
172 color
= get_color_from_map(gf
->SColorMap
, gf
->SBackGroundColor
);
174 *pixel
= GP_Pixel_CREATE_RGB888(color
->Red
, color
->Green
, color
->Blue
);
179 GP_Context
*GP_ReadGIF(void *f
, GP_ProgressCallback
*callback
)
182 GifRecordType rec_type
;
183 GP_Context
*res
= NULL
;
189 if (DGifGetRecordType(gf
, &rec_type
) != GIF_OK
) {
190 //TODO: error handling
191 GP_DEBUG(1, "DGifGetRecordType() error %s (%i)",
192 gif_err_name(GifLastError()), GifLastError());
197 GP_DEBUG(2, "Have GIF record type %s",
198 rec_type_name(rec_type
));
201 case EXTENSION_RECORD_TYPE
:
202 if ((err
= read_extensions(gf
)))
205 case IMAGE_DESC_RECORD_TYPE
:
211 if (DGifGetImageDesc(gf
) != GIF_OK
) {
212 //TODO: error handling
213 GP_DEBUG(1, "DGifGetImageDesc() error %s (%i)",
214 gif_err_name(GifLastError()), GifLastError());
219 GP_DEBUG(1, "Have GIF Image left-top %ix%i, width-height %ix%i,"
220 " interlace %i, bpp %i", gf
->Image
.Left
, gf
->Image
.Top
,
221 gf
->Image
.Width
, gf
->Image
.Height
, gf
->Image
.Interlace
,
222 gf
->Image
.ColorMap
? gf
->Image
.ColorMap
->BitsPerPixel
: -1);
224 res
= GP_ContextAlloc(gf
->SWidth
, gf
->SHeight
, GP_PIXEL_RGB888
);
231 /* If background color is defined, use it */
232 if (get_bg_color(gf
, &bg
)) {
233 GP_DEBUG(1, "Filling bg color %x", bg
);
237 /* Now finally read gif image data */
238 for (y
= gf
->Image
.Top
; y
< gf
->Image
.Height
; y
++) {
239 uint8_t line
[gf
->Image
.Width
];
241 DGifGetLine(gf
, line
, gf
->Image
.Width
);
243 //TODO: just now we have only 8BPP
244 for (x
= 0; x
< gf
->Image
.Width
; x
++)
245 GP_PutPixel_Raw_24BPP(res
, x
+ gf
->Image
.Left
, y
, get_color(gf
, line
[x
]));
247 if (GP_ProgressCallbackReport(callback
, y
- gf
->Image
.Top
,
250 GP_DEBUG(1, "Operation aborted");
256 //TODO: now we exit after reading first image
259 } while (rec_type
!= TERMINATE_RECORD_TYPE
);
264 /* No Image record found :( */
277 GP_Context
*GP_LoadGIF(const char *src_path
, GP_ProgressCallback
*callback
)
281 if (GP_OpenGIF(src_path
, &f
))
284 return GP_ReadGIF(f
, callback
);
289 int GP_OpenGIF(const char GP_UNUSED(*src_path
),
296 GP_Context
*GP_ReadGIF(void GP_UNUSED(*f
),
297 GP_ProgressCallback
GP_UNUSED(*callback
))
303 GP_Context
*GP_LoadGIF(const char GP_UNUSED(*src_path
),
304 GP_ProgressCallback
GP_UNUSED(*callback
))
310 #endif /* HAVE_GIFLIB */