2 * Image Library -- libungif
4 * (c) 2006 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
13 #include "lib/mempool.h"
14 #include "lib/fastbuf.h"
15 #include "images/images.h"
16 #include "images/color.h"
17 #include "images/io-main.h"
21 libungif_read_func(GifFileType *gif, GifByteType *ptr, int len)
23 DBG("libungif_read_func(len=%d)", len);
24 return bread((struct fastbuf *)gif->UserData, (byte *)ptr, len);
28 libungif_read_cancel(struct image_io *io)
30 DBG("libungif_read_cancel()");
32 DGifCloseFile(io->read_data);
36 libungif_read_header(struct image_io *io)
38 DBG("libungif_read_header()");
40 /* Create libungif structure */
42 if (unlikely(!(gif = io->read_data = DGifOpen(io->fastbuf, libungif_read_func))))
44 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libungif structure.");
48 DBG("executing DGifSlurp()");
49 if (unlikely(DGifSlurp(gif) != GIF_OK))
51 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Gif read failed.");
56 DBG("ImageCount=%d ColorResolution=%d SBackGroundColor=%d SColorMap=%p", gif->ImageCount, gif->SColorResolution, gif->SBackGroundColor, gif->SColorMap);
57 if (unlikely(!gif->ImageCount))
59 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "There are no images in gif file.");
64 /* Read image parameters */
65 SavedImage *image = gif->SavedImages;
66 if (unlikely(image->ImageDesc.Width <= 0 || image->ImageDesc.Height <= 0 ||
67 image->ImageDesc.Width > (int)IMAGE_MAX_SIZE || image->ImageDesc.Height > (int)IMAGE_MAX_SIZE))
69 image_thread_err(io->thread, IMAGE_ERR_INVALID_DIMENSIONS, "Invalid gif dimensions.");
73 ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
74 if (unlikely(!color_map))
76 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Missing palette.");
80 io->cols = image->ImageDesc.Width;
81 io->rows = image->ImageDesc.Height;
82 if (unlikely((io->number_of_colors = color_map->ColorCount) > 256))
84 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Too many gif colors.");
88 io->flags = COLOR_SPACE_RGB | IMAGE_IO_HAS_PALETTE;
89 /* FIXME transparent GIFs disabled */
91 if (gif->SColorMap && !image->ImageDesc.ColorMap && (uns)gif->SBackGroundColor < (uns)color_map->ColorCount)
93 io->flags |= IMAGE_ALPHA | IMAGE_IO_HAS_BACKGROUND;
94 GifColorType *background = color_map->Colors + gif->SBackGroundColor;
95 color_make_rgb(&io->background_color, background->Red, background->Green, background->Blue);
100 io->read_cancel = libungif_read_cancel;
105 libungif_read_data(struct image_io *io)
107 DBG("libungif_read_data()");
109 GifFileType *gif = io->read_data;
110 SavedImage *image = gif->SavedImages;
113 struct image_io_read_data_internals rdi;
114 if (unlikely(!image_io_read_data_prepare(&rdi, io, image->ImageDesc.Width, image->ImageDesc.Height, io->flags)))
120 /* Get pixels and palette */
121 byte *pixels = (byte *)image->RasterBits;
122 ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
123 GifColorType *palette = color_map->Colors;
125 /* FIXME: transparent GIFs disabled */
129 gif->SColorMap && !image->ImageDesc.ColorMap) ? gif->SBackGroundColor : 256;
130 byte *img_end = rdi.image->pixels + rdi.image->image_size;
132 /* Handle deinterlacing */
133 uns dein_step, dein_next;
134 if (image->ImageDesc.Interlace)
135 dein_step = dein_next = rdi.image->row_size << 3;
137 dein_step = dein_next = rdi.image->row_size;
140 switch (rdi.image->pixel_size)
144 byte pal[256], *pal_pos = pal, *pal_end = pal + 256;
145 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos++, palette++)
146 *pal_pos = rgb_to_gray_func(palette->Red, palette->Green, palette->Blue);
147 if (pal_pos != pal_end)
148 bzero(pal_pos, pal_end - pal_pos);
149 if (io->flags & IMAGE_IO_USE_BACKGROUND)
150 color_put_grayscale(pal + background, &io->background_color);
151 # define DO_ROW_END do{ \
152 walk_row_start += dein_step; \
153 if (walk_row_start > img_end) \
154 { uns n = dein_next >> 1; walk_row_start = rdi.image->pixels + n, dein_step = dein_next; dein_next = n; } \
156 # define IMAGE_WALK_PREFIX(x) walk_##x
157 # define IMAGE_WALK_INLINE
158 # define IMAGE_WALK_IMAGE (rdi.image)
159 # define IMAGE_WALK_UNROLL 4
160 # define IMAGE_WALK_COL_STEP 1
161 # define IMAGE_WALK_ROW_STEP 0
162 # define IMAGE_WALK_DO_STEP do{ *walk_pos = pal[*pixels++]; }while(0)
163 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
164 # include "images/image-walk.h"
169 byte pal[256 * 2], *pal_pos = pal, *pal_end = pal + 256 * 2;
170 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 2, palette++)
172 pal_pos[0] = rgb_to_gray_func(palette->Red, palette->Green, palette->Blue);
175 if (pal_pos != pal_end)
176 bzero(pal_pos, pal_end - pal_pos);
177 if (background < 256)
178 pal[background * 2 + 1] = 0;
179 # define IMAGE_WALK_PREFIX(x) walk_##x
180 # define IMAGE_WALK_INLINE
181 # define IMAGE_WALK_IMAGE (rdi.image)
182 # define IMAGE_WALK_UNROLL 4
183 # define IMAGE_WALK_COL_STEP 2
184 # define IMAGE_WALK_ROW_STEP 0
185 # define IMAGE_WALK_DO_STEP do{ *(u16 *)walk_pos = ((u16 *)pal)[*pixels++]; }while(0)
186 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
187 # include "images/image-walk.h"
192 byte pal[256 * 4], *pal_pos = pal, *pal_end = pal + 256 * 4;
193 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 4, palette++)
195 pal_pos[0] = palette->Red;
196 pal_pos[1] = palette->Green;
197 pal_pos[2] = palette->Blue;
199 if (pal_pos != pal_end)
200 bzero(pal_pos, pal_end - pal_pos);
201 if (io->flags & IMAGE_IO_USE_BACKGROUND)
202 color_put_rgb(pal + background, &io->background_color);
203 # define IMAGE_WALK_PREFIX(x) walk_##x
204 # define IMAGE_WALK_INLINE
205 # define IMAGE_WALK_IMAGE (rdi.image)
206 # define IMAGE_WALK_UNROLL 4
207 # define IMAGE_WALK_COL_STEP 3
208 # define IMAGE_WALK_ROW_STEP 0
209 # define IMAGE_WALK_DO_STEP do{ byte *p = pal + 4 * (*pixels++); walk_pos[0] = p[0]; walk_pos[1] = p[1]; walk_pos[2] = p[2]; }while(0)
210 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
211 # include "images/image-walk.h"
216 byte pal[256 * 4], *pal_pos = pal, *pal_end = pal + 256 * 4;
217 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 4, palette++)
219 pal_pos[0] = palette->Red;
220 pal_pos[1] = palette->Green;
221 pal_pos[2] = palette->Blue;
224 if (pal_pos != pal_end)
225 bzero(pal_pos, pal_end - pal_pos);
226 if (background < 256)
227 pal[background * 4 + 3] = 0;
228 # define IMAGE_WALK_PREFIX(x) walk_##x
229 # define IMAGE_WALK_INLINE
230 # define IMAGE_WALK_IMAGE (rdi.image)
231 # define IMAGE_WALK_UNROLL 4
232 # define IMAGE_WALK_COL_STEP 4
233 # define IMAGE_WALK_ROW_STEP 0
234 # define IMAGE_WALK_DO_STEP do{ *(u32 *)walk_pos = ((u32 *)pal)[*pixels++]; }while(0)
235 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
236 # include "images/image-walk.h"
243 /* Destroy libungif structure */
247 return image_io_read_data_finish(&rdi, io);