1 /* -*- mode: C; c-file-style: "linux" -*- */
2 /* GdkPixbuf library - Wireless Bitmap image loader
4 * Copyright (C) 2000 Red Hat, Inc.
6 * Authors: Elliot Lee <sopwith@redhat.com
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
29 * Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
38 #include "gdk-pixbuf-private.h"
39 #include "gdk-pixbuf-io.h"
43 /* Progressive loading */
45 struct wbmp_progressive_state {
46 GdkPixbufModulePreparedFunc prepared_func;
47 GdkPixbufModuleUpdatedFunc updated_func;
50 gboolean need_type : 1;
51 gboolean need_header : 1;
52 gboolean need_width : 1;
53 gboolean need_height : 1;
54 gboolean needmore : 1;
55 gboolean call_progressive_updates : 1;
57 guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
61 int width, height, curx, cury;
63 GdkPixbuf *pixbuf; /* Our "target" */
67 gdk_pixbuf__wbmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
68 GdkPixbufModulePreparedFunc prepared_func,
69 GdkPixbufModuleUpdatedFunc updated_func,
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 * func - called when we have pixmap created (but no image data)
81 * user_data - passed as arg 1 to func
82 * return context (opaque to user)
86 gdk_pixbuf__wbmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
87 GdkPixbufModulePreparedFunc prepared_func,
88 GdkPixbufModuleUpdatedFunc updated_func,
92 struct wbmp_progressive_state *context;
94 context = g_new0(struct wbmp_progressive_state, 1);
95 context->prepared_func = prepared_func;
96 context->updated_func = updated_func;
97 context->user_data = user_data;
99 context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
100 context->call_progressive_updates = TRUE;
101 context->pixbuf = NULL;
103 return (gpointer) context;
107 * context - returned from image_begin_load
109 * free context, unref gdk_pixbuf
111 static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data,
114 struct wbmp_progressive_state *context =
115 (struct wbmp_progressive_state *) data;
117 /* FIXME this thing needs to report errors if
118 * we have unused image data
121 g_return_val_if_fail(context != NULL, TRUE);
123 g_object_unref(context->pixbuf);
131 getin(struct wbmp_progressive_state *context, const guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
133 int last_num, buf_num;
135 if((context->last_len + *buf_size) < datum_size)
138 /* We know we can pull it out of there */
139 last_num = MIN(datum_size, context->last_len);
140 buf_num = MIN(datum_size-last_num, *buf_size);
141 memcpy(ptr, context->last_buf, last_num);
142 memcpy(ptr+last_num, *buf, buf_num);
144 context->last_len -= last_num;
145 if(context->last_len)
146 memmove(context->last_buf, context->last_buf+last_num, context->last_len);
147 *buf_size -= buf_num;
154 save_rest(struct wbmp_progressive_state *context, const guchar *buf, guint buf_size)
156 if(buf_size > (sizeof(context->last_buf) - context->last_len))
159 memcpy(context->last_buf+context->last_len, buf, buf_size);
160 context->last_len += buf_size;
166 get_mbi(struct wbmp_progressive_state *context, const guchar **buf, guint *buf_size, int *val)
175 rv = getin(context, buf, buf_size, intbuf+n, 1);
179 *val |= intbuf[n] & 0x7F;
181 } while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
184 if(!rv || (intbuf[n-1] & 0x80))
186 rv = save_rest(context, intbuf, n);
189 g_error("Couldn't save_rest of intbuf");
197 * context - from image_begin_load
198 * buf - new image data
199 * size - length of new image data
201 * append image data onto inrecrementally built output image
203 static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
205 guint size, GError **error)
207 struct wbmp_progressive_state *context =
208 (struct wbmp_progressive_state *) data;
213 if(context->need_type)
217 bv = getin(context, &buf, &size, &val, 1);
221 context->need_type = FALSE;
224 else if(context->need_header)
228 bv = getin(context, &buf, &size, &val, 1);
231 /* We skip over the extended header - val is unused */
233 context->need_header = FALSE;
236 else if(context->need_width)
238 bv = get_mbi(context, &buf, &size, &context->width);
240 context->need_width = FALSE;
242 if (context->width <= 0) {
245 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
246 _("Image has zero width"));
253 else if(context->need_height)
255 bv = get_mbi(context, &buf, &size, &context->height);
258 context->need_height = FALSE;
260 if (context->height <= 0) {
263 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
264 _("Image has zero height"));
269 context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
271 if (!context->pixbuf) {
274 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
275 _("Not enough memory to load image"));
280 if(context->prepared_func)
281 context->prepared_func(context->pixbuf, NULL, context->user_data);
284 else if(context->needmore)
287 first_row = context->cury;
288 for( ; context->cury < context->height; context->cury++, context->curx = 0)
290 for( ; context->curx < context->width; context->curx += 8)
295 bv = getin(context, &buf, &size, &byte, 1);
299 ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
300 for(xoff = 7; xoff >= 0; xoff--, ptr += 3)
304 if (context->curx + (7 - xoff) == context->width)
312 ptr[0] = ptr[1] = ptr[2] = pixval;
316 context->needmore = FALSE;
319 if(context->updated_func)
320 context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
324 bv = FALSE; /* Nothing left to do, stop feeding me data! */
329 bv = save_rest(context, buf, size);
333 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
334 _("Couldn't save the rest"));
343 MODULE_ENTRY (wbmp, fill_vtable) (GdkPixbufModule *module)
345 module->begin_load = gdk_pixbuf__wbmp_image_begin_load;
346 module->stop_load = gdk_pixbuf__wbmp_image_stop_load;
347 module->load_increment = gdk_pixbuf__wbmp_image_load_increment;
351 MODULE_ENTRY (wbmp, fill_info) (GdkPixbufFormat *info)
353 static GdkPixbufModulePattern signature[] = {
357 static gchar * mime_types[] = {
358 "image/vnd.wap.wbmp",
361 static gchar * extensions[] = {
367 info->signature = signature;
368 info->description = N_("The WBMP image format");
369 info->mime_types = mime_types;
370 info->extensions = extensions;