1 /* GdkPixbuf library - Wireless Bitmap image loader
3 * Copyright (C) 2000 Red Hat, Inc.
5 * Authors: Elliot Lee <sopwith@redhat.com
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
28 * Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
37 #include "gdk-pixbuf-private.h"
38 #include "gdk-pixbuf-io.h"
42 /* Progressive loading */
44 struct wbmp_progressive_state {
45 ModulePreparedNotifyFunc prepared_func;
46 ModuleUpdatedNotifyFunc updated_func;
49 gboolean need_type : 1;
50 gboolean need_header : 1;
51 gboolean need_width : 1;
52 gboolean need_height : 1;
53 gboolean needmore : 1;
54 gboolean call_progressive_updates : 1;
56 guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
60 int width, height, curx, cury;
62 GdkPixbuf *pixbuf; /* Our "target" */
66 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
67 ModuleUpdatedNotifyFunc updated_func,
68 ModuleFrameDoneNotifyFunc frame_done_func,
69 ModuleAnimationDoneNotifyFunc
70 anim_done_func, gpointer user_data,
73 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
74 static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
80 /* Shared library entry point --> This should be removed when
81 generic_image_load enters gdk-pixbuf-io. */
82 static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
86 struct wbmp_progressive_state *State;
90 State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
96 while (feof(f) == 0) {
97 length = fread(membuf, 1, 4096, f);
99 gdk_pixbuf__wbmp_image_load_increment(State,
105 if (State->pixbuf != NULL)
106 gdk_pixbuf_ref(State->pixbuf);
110 gdk_pixbuf__wbmp_image_stop_load(State, NULL);
115 * func - called when we have pixmap created (but no image data)
116 * user_data - passed as arg 1 to func
117 * return context (opaque to user)
121 gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
122 ModuleUpdatedNotifyFunc updated_func,
123 ModuleFrameDoneNotifyFunc frame_done_func,
124 ModuleAnimationDoneNotifyFunc
125 anim_done_func, gpointer user_data,
128 struct wbmp_progressive_state *context;
130 context = g_new0(struct wbmp_progressive_state, 1);
131 context->prepared_func = prepared_func;
132 context->updated_func = updated_func;
133 context->user_data = user_data;
135 context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
136 context->call_progressive_updates = TRUE;
137 context->pixbuf = NULL;
139 return (gpointer) context;
143 * context - returned from image_begin_load
145 * free context, unref gdk_pixbuf
147 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data,
150 struct wbmp_progressive_state *context =
151 (struct wbmp_progressive_state *) data;
153 /* FIXME this thing needs to report errors if
154 * we have unused image data
157 g_return_val_if_fail(context != NULL, TRUE);
159 gdk_pixbuf_unref(context->pixbuf);
167 getin(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
169 int last_num, buf_num;
171 if((context->last_len + *buf_size) < datum_size)
174 /* We know we can pull it out of there */
175 last_num = MIN(datum_size, context->last_len);
176 buf_num = MIN(datum_size-last_num, *buf_size);
177 memcpy(ptr, context->last_buf, last_num);
178 memcpy(ptr+last_num, *buf, buf_num);
180 context->last_len -= last_num;
181 if(context->last_len)
182 memmove(context->last_buf, context->last_buf+last_num, context->last_len);
183 *buf_size -= buf_num;
190 save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
192 if(buf_size > (sizeof(context->last_buf) - context->last_len))
195 memcpy(context->last_buf+context->last_len, buf, buf_size);
196 context->last_len += buf_size;
202 get_mbi(struct wbmp_progressive_state *context, guchar **buf, guint *buf_size, int *val)
211 rv = getin(context, buf, buf_size, intbuf+n, 1);
215 *val |= intbuf[n] & 0x7F;
217 } while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
220 if(!rv || (intbuf[n-1] & 0x80))
222 rv = save_rest(context, intbuf, n);
225 g_error("Couldn't save_rest of intbuf");
233 * context - from image_begin_load
234 * buf - new image data
235 * size - length of new image data
237 * append image data onto inrecrementally built output image
239 static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
241 guint size, GError **error)
243 struct wbmp_progressive_state *context =
244 (struct wbmp_progressive_state *) data;
249 if(context->need_type)
253 bv = getin(context, &buf, &size, &val, 1);
257 context->need_type = FALSE;
260 else if(context->need_header)
264 bv = getin(context, &buf, &size, &val, 1);
267 /* We skip over the extended header - val is unused */
269 context->need_header = FALSE;
272 else if(context->need_width)
274 bv = get_mbi(context, &buf, &size, &context->width);
276 context->need_width = FALSE;
278 else if(context->need_height)
280 bv = get_mbi(context, &buf, &size, &context->height);
283 context->need_height = FALSE;
284 context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
285 g_assert(context->pixbuf);
287 if(context->prepared_func)
288 context->prepared_func(context->pixbuf, context->user_data);
291 else if(context->needmore)
294 first_row = context->cury;
295 for( ; context->cury < context->height; context->cury++, context->curx = 0)
297 for( ; context->curx < context->width; context->curx += 8)
302 bv = getin(context, &buf, &size, &byte, 1);
306 ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
307 for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
316 ptr[0] = ptr[1] = ptr[2] = pixval;
320 context->needmore = FALSE;
323 context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
327 bv = FALSE; /* Nothing left to do, stop feeding me data! */
332 return save_rest(context, buf, size);
334 return context->needmore;
338 gdk_pixbuf__wbmp_fill_vtable (GdkPixbufModule *module)
340 module->load = gdk_pixbuf__wbmp_image_load;
341 module->begin_load = gdk_pixbuf__wbmp_image_begin_load;
342 module->stop_load = gdk_pixbuf__wbmp_image_stop_load;
343 module->load_increment = gdk_pixbuf__wbmp_image_load_increment;