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/io-main.h"
20 libungif_read_func(GifFileType *gif, GifByteType *ptr, int len)
22 DBG("libungif_read_func(len=%d)", len);
23 return bread((struct fastbuf *)gif->UserData, (byte *)ptr, len);
27 libungif_read_cancel(struct image_io *io)
29 DBG("libungif_read_cancel()");
31 DGifCloseFile(io->read_data);
35 libungif_read_header(struct image_io *io)
37 DBG("libungif_read_header()");
39 /* Create libungif structure */
41 if (unlikely(!(gif = io->read_data = DGifOpen(io->fastbuf, libungif_read_func))))
43 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Cannot create libungif structure.");
47 if (unlikely(DGifSlurp(gif) != GIF_OK))
49 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Gif read failed.");
54 if (unlikely(!gif->ImageCount))
56 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "There are no images in gif file.");
61 /* Read image parameters */
62 SavedImage *image = gif->SavedImages;
63 if (unlikely(image->ImageDesc.Width <= 0 || image->ImageDesc.Height <= 0 ||
64 image->ImageDesc.Width > (int)IMAGE_MAX_SIZE || image->ImageDesc.Height > (int)IMAGE_MAX_SIZE))
66 image_thread_err(io->thread, IMAGE_ERR_INVALID_DIMENSIONS, "Invalid gif dimensions.");
70 ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
71 if (unlikely(!color_map))
73 image_thread_err(io->thread, IMAGE_ERR_READ_FAILED, "Missing palette.");
77 io->cols = image->ImageDesc.Width;
78 io->rows = image->ImageDesc.Height;
79 io->number_of_colors = color_map->ColorCount;
80 io->flags = COLOR_SPACE_RGB | IMAGE_IO_HAS_PALETTE;
81 if ((uns)gif->SBackGroundColor < (uns)color_map->ColorCount)
82 io->flags |= IMAGE_ALPHA;
85 io->read_cancel = libungif_read_cancel;
90 libungif_pixel_to_gray(GifColorType *pixel)
92 return ((uns)pixel->Red * 19660 + (uns)pixel->Green * 38666 + (uns)pixel->Blue * 7210) >> 16;
96 libungif_read_data(struct image_io *io)
98 DBG("libungif_read_data()");
100 GifFileType *gif = io->read_data;
101 SavedImage *image = gif->SavedImages;
104 struct image_io_read_data_internals rdi;
105 if (unlikely(!image_io_read_data_prepare(&rdi, io, image->ImageDesc.Width, image->ImageDesc.Height)))
111 /* Get pixels and palette */
112 byte *pixels = (byte *)image->RasterBits;
113 ColorMapObject *color_map = image->ImageDesc.ColorMap ? : gif->SColorMap;
114 GifColorType *palette = color_map->Colors;
115 uns background = gif->SBackGroundColor;
116 byte *img_end = rdi.image->pixels + rdi.image->image_size;
118 /* Handle deinterlacing */
119 uns dein_step, dein_next;
120 if (image->ImageDesc.Interlace)
121 dein_step = dein_next = rdi.image->row_size << 3;
123 dein_step = dein_next = rdi.image->row_size;
126 switch (rdi.image->pixel_size)
130 byte pal[256], *pal_pos = pal, *pal_end = pal + 256;
131 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos++, palette++)
132 *pal_pos = libungif_pixel_to_gray(palette);
133 if (pal_pos != pal_end)
134 bzero(pal_pos, pal_end - pal_pos);
135 # define DO_ROW_END do{ \
136 walk_row_start += dein_step; \
137 if (walk_row_start > img_end) \
138 { uns n = dein_next >> 1; walk_row_start = rdi.image->pixels + n, dein_step = dein_next; dein_next = n; } \
140 # define IMAGE_WALK_PREFIX(x) walk_##x
141 # define IMAGE_WALK_INLINE
142 # define IMAGE_WALK_IMAGE (rdi.image)
143 # define IMAGE_WALK_UNROLL 4
144 # define IMAGE_WALK_COL_STEP 1
145 # define IMAGE_WALK_ROW_STEP 0
146 # define IMAGE_WALK_DO_STEP do{ *walk_pos = pal[*pixels++]; }while(0)
147 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
148 # include "images/image-walk.h"
153 byte pal[256 * 2], *pal_pos = pal, *pal_end = pal + 256 * 2;
154 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 2, palette++)
156 pal_pos[0] = libungif_pixel_to_gray(palette);
159 if (pal_pos != pal_end)
160 bzero(pal_pos, pal_end - pal_pos);
161 if (background < 256)
162 pal[background * 2 + 1] = 0;
163 # define IMAGE_WALK_PREFIX(x) walk_##x
164 # define IMAGE_WALK_INLINE
165 # define IMAGE_WALK_IMAGE (rdi.image)
166 # define IMAGE_WALK_UNROLL 4
167 # define IMAGE_WALK_COL_STEP 2
168 # define IMAGE_WALK_ROW_STEP 0
169 # define IMAGE_WALK_DO_STEP do{ *(u16 *)walk_pos = ((u16 *)pal)[*pixels++]; }while(0)
170 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
171 # include "images/image-walk.h"
176 byte pal[256 * 4], *pal_pos = pal, *pal_end = pal + 256 * 4;
177 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 4, palette++)
179 pal_pos[0] = palette->Red;
180 pal_pos[1] = palette->Green;
181 pal_pos[2] = palette->Blue;
183 if (pal_pos != pal_end)
184 bzero(pal_pos, pal_end - pal_pos);
185 # define IMAGE_WALK_PREFIX(x) walk_##x
186 # define IMAGE_WALK_INLINE
187 # define IMAGE_WALK_IMAGE (rdi.image)
188 # define IMAGE_WALK_UNROLL 4
189 # define IMAGE_WALK_COL_STEP 3
190 # define IMAGE_WALK_ROW_STEP 0
191 # 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)
192 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
193 # include "images/image-walk.h"
198 byte pal[256 * 4], *pal_pos = pal, *pal_end = pal + 256 * 4;
199 for (uns i = 0; i < (uns)color_map->ColorCount; i++, pal_pos += 4, palette++)
201 pal_pos[0] = palette->Red;
202 pal_pos[1] = palette->Green;
203 pal_pos[2] = palette->Blue;
206 if (pal_pos != pal_end)
207 bzero(pal_pos, pal_end - pal_pos);
208 if (background < 256)
209 pal[background * 4 + 3] = 0;
210 # define IMAGE_WALK_PREFIX(x) walk_##x
211 # define IMAGE_WALK_INLINE
212 # define IMAGE_WALK_IMAGE (rdi.image)
213 # define IMAGE_WALK_UNROLL 4
214 # define IMAGE_WALK_COL_STEP 4
215 # define IMAGE_WALK_ROW_STEP 0
216 # define IMAGE_WALK_DO_STEP do{ *(u32 *)walk_pos = ((u32 *)pal)[*pixels++]; }while(0)
217 # define IMAGE_WALK_DO_ROW_END DO_ROW_END
218 # include "images/image-walk.h"
225 /* Destroy libungif structure */
229 return image_io_read_data_finish(&rdi, io);