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 if (unlikely(DGifSlurp(gif) != GIF_OK))
50 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Gif read failed.");
55 if (unlikely(!gif->ImageCount))
57 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "There are no images in gif file.");
62 /* Read image parameters */
63 SavedImage *image = gif->SavedImages;
64 if (unlikely(image->ImageDesc.Width <= 0 || image->ImageDesc.Height <= 0 ||
65 image->ImageDesc.Width > (int)IMAGE_MAX_SIZE || image->ImageDesc.Height > (int)IMAGE_MAX_SIZE))
67 image_thread_err(io->thread, IMAGE_ERR_INVALID_DIMENSIONS, "Invalid gif dimensions.");
71 ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
72 if (unlikely(!color_map))
74 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Missing palette.");
78 io->cols = image->ImageDesc.Width;
79 io->rows = image->ImageDesc.Height;
80 if (unlikely((io->number_of_colors = color_map->ColorCount) > 256))
82 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Too many gif colors.");
86 io->flags = COLOR_SPACE_RGB | IMAGE_IO_HAS_PALETTE;
87 if ((uns)gif->SBackGroundColor < (uns)color_map->ColorCount)
89 io->flags |= IMAGE_ALPHA | IMAGE_IO_HAS_BACKGROUND;
90 GifColorType *background = color_map->Colors + gif->SBackGroundColor;
91 color_make_rgb(&io->background_color, background->Red, background->Green, background->Blue);
95 io->read_cancel = libungif_read_cancel;
100 libungif_read_data(struct image_io *io)
102 DBG("libungif_read_data()");
104 GifFileType *gif = io->read_data;
105 SavedImage *image = gif->SavedImages;
108 struct image_io_read_data_internals rdi;
109 if (unlikely(!image_io_read_data_prepare(&rdi, io, image->ImageDesc.Width, image->ImageDesc.Height, io->flags)))
115 /* Get pixels and palette */
116 byte *pixels = (byte *)image->RasterBits;
117 ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
118 GifColorType *palette = color_map->Colors;
119 uns background = gif->SBackGroundColor;
120 byte *img_end = rdi.image->pixels + rdi.image->image_size;
122 /* Handle deinterlacing */
123 uns dein_step, dein_next;
124 if (image->ImageDesc.Interlace)
125 dein_step = dein_next = rdi.image->row_size << 3;
127 dein_step = dein_next = rdi.image->row_size;
130 switch (rdi.image->pixel_size)
134 byte pal[256], *pal_pos = pal, *pal_end = pal + 256;
135 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos++, palette++)
136 *pal_pos = rgb_to_gray_func(palette->Red, palette->Green, palette->Blue);
137 if (pal_pos != pal_end)
138 bzero(pal_pos, pal_end - pal_pos);
139 if (io->flags & IMAGE_IO_USE_BACKGROUND)
140 color_put_grayscale(pal + background, &io->background_color);
141 # define DO_ROW_END do{ \
142 walk_row_start += dein_step; \
143 if (walk_row_start > img_end) \
144 { uns n = dein_next >> 1; walk_row_start = rdi.image->pixels + n, dein_step = dein_next; dein_next = n; } \
146 # define IMAGE_WALK_PREFIX(x) walk_##x
147 # define IMAGE_WALK_INLINE
148 # define IMAGE_WALK_IMAGE (rdi.image)
149 # define IMAGE_WALK_UNROLL 4
150 # define IMAGE_WALK_COL_STEP 1
151 # define IMAGE_WALK_ROW_STEP 0
152 # define IMAGE_WALK_DO_STEP do{ *walk_pos = pal[*pixels++]; }while(0)
153 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
154 # include "images/image-walk.h"
159 byte pal[256 * 2], *pal_pos = pal, *pal_end = pal + 256 * 2;
160 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 2, palette++)
162 pal_pos[0] = rgb_to_gray_func(palette->Red, palette->Green, palette->Blue);
165 if (pal_pos != pal_end)
166 bzero(pal_pos, pal_end - pal_pos);
167 if (background < 256)
168 pal[background * 2 + 1] = 0;
169 # define IMAGE_WALK_PREFIX(x) walk_##x
170 # define IMAGE_WALK_INLINE
171 # define IMAGE_WALK_IMAGE (rdi.image)
172 # define IMAGE_WALK_UNROLL 4
173 # define IMAGE_WALK_COL_STEP 2
174 # define IMAGE_WALK_ROW_STEP 0
175 # define IMAGE_WALK_DO_STEP do{ *(u16 *)walk_pos = ((u16 *)pal)[*pixels++]; }while(0)
176 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
177 # include "images/image-walk.h"
182 byte pal[256 * 4], *pal_pos = pal, *pal_end = pal + 256 * 4;
183 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 4, palette++)
185 pal_pos[0] = palette->Red;
186 pal_pos[1] = palette->Green;
187 pal_pos[2] = palette->Blue;
189 if (pal_pos != pal_end)
190 bzero(pal_pos, pal_end - pal_pos);
191 if (io->flags & IMAGE_IO_USE_BACKGROUND)
192 color_put_rgb(pal + background, &io->background_color);
193 # define IMAGE_WALK_PREFIX(x) walk_##x
194 # define IMAGE_WALK_INLINE
195 # define IMAGE_WALK_IMAGE (rdi.image)
196 # define IMAGE_WALK_UNROLL 4
197 # define IMAGE_WALK_COL_STEP 3
198 # define IMAGE_WALK_ROW_STEP 0
199 # 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)
200 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
201 # include "images/image-walk.h"
206 byte pal[256 * 4], *pal_pos = pal, *pal_end = pal + 256 * 4;
207 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 4, palette++)
209 pal_pos[0] = palette->Red;
210 pal_pos[1] = palette->Green;
211 pal_pos[2] = palette->Blue;
214 if (pal_pos != pal_end)
215 bzero(pal_pos, pal_end - pal_pos);
216 if (background < 256)
217 pal[background * 4 + 3] = 0;
218 # define IMAGE_WALK_PREFIX(x) walk_##x
219 # define IMAGE_WALK_INLINE
220 # define IMAGE_WALK_IMAGE (rdi.image)
221 # define IMAGE_WALK_UNROLL 4
222 # define IMAGE_WALK_COL_STEP 4
223 # define IMAGE_WALK_ROW_STEP 0
224 # define IMAGE_WALK_DO_STEP do{ *(u32 *)walk_pos = ((u32 *)pal)[*pixels++]; }while(0)
225 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
226 # include "images/image-walk.h"
233 /* Destroy libungif structure */
237 return image_io_read_data_finish(&rdi, io);