Commit 34d1da48 authored by Elliot Lee's avatar Elliot Lee Committed by Elliot Lee

Add gdk_pixbuf_loader_new_with_type function, to allow handling image



2000-07-27  Elliot Lee  <sopwith@redhat.com>

	* gtk/gdk-pixbuf-loader.[ch]: Add gdk_pixbuf_loader_new_with_type
	function, to allow handling image formats that cannot be detected
	by looking at content alone.

gdk-pixbuf/
2000-07-27  Elliot Lee  <sopwith@redhat.com>
	* gdk-pixbuf-io.h, gdk-pixbuf-io.c: Add gdk_pixbuf_get_named_module() function to facilitate above change
	* io-bmp.c: Don't malloc a temporary buffer - use stack instead.
	* io-wbmp.c, pixbufloader_wbmp.defs, gdk-pixbuf-io.c, Makefile: Implement loader for WBMP format.

**NOTE: I haven't tested this yet, I need to sync it to another machine, but it if it is broken
I'm already working on fixing it
parent 3fb75672
......@@ -68,6 +68,12 @@ libpixbufloader_bmp_la_SOURCES = io-bmp.c
libpixbufloader_bmp_la_LDFLAGS = -version-info 1:0:0 -module
libpixbufloader_bmp_la_LIBADD =
#
# The WBMP loader
#
libpixbufloader_wbmp_la_SOURCES = io-wbmp.c
libpixbufloader_wbmp_la_LDFLAGS = -version-info 1:0:0 -module
if HAVE_PNG
PNG_LIB = libpixbufloader-png.la
endif
......@@ -92,6 +98,8 @@ PNM_LIB = libpixbufloader-pnm.la
BMP_LIB = libpixbufloader-bmp.la
WBMP_LIB = libpixbufloader-wbmp.la
if BUILD_DYNAMIC_MODULES
loader_LTLIBRARIES = \
......@@ -103,7 +111,8 @@ loader_LTLIBRARIES = \
$(XPM_LIB) \
$(TIFF_LIB) \
$(PNM_LIB) \
$(BMP_LIB)
$(BMP_LIB) \
$(WBMP_LIB)
extra_sources =
......@@ -119,7 +128,8 @@ extra_sources = $(libpixbufloader_png_la_SOURCES) \
$(libpixbufloader_ras_la_SOURCES) \
$(libpixbufloader_tiff_la_SOURCES) \
$(libpixbufloader_pnm_la_SOURCES) \
$(libpixbufloader_bmp_la_SOURCES)
$(libpixbufloader_bmp_la_SOURCES) \
$(libpixbufloader_wbmp_la_SOURCES)
builtin_libraries =
endif
......@@ -180,7 +190,8 @@ EXTRA_DIST = \
pixbuf_ras.def \
pixbuf_gif.def \
pixbuf_png.def \
pixbuf_tiff.def
pixbuf_tiff.def \
pixbuf_wbmp.def
makefile.mingw: $(top_builddir)/config.status $(top_srcdir)/gdk-pixbuf/makefile.mingw.in
cd $(top_builddir) && CONFIG_FILES=gdk-pixbuf/$@ CONFIG_HEADERS= $(SHELL) ./config.status
......@@ -172,6 +172,18 @@ pixbuf_check_bmp (guchar *buffer, int size)
return TRUE;
}
static gboolean
pixbuf_check_wbmp (guchar *buffer, int size)
{
if(size < 10) /* at least */
return FALSE;
if(buffer[0] == '\0' /* We only handle type 0 wbmp's for now */)
return TRUE;
return FALSE;
}
static GdkPixbufModule file_formats [] = {
{ "png", pixbuf_check_png, NULL, NULL, NULL, NULL, NULL, NULL },
{ "jpeg", pixbuf_check_jpeg, NULL, NULL, NULL, NULL, NULL, NULL },
......@@ -183,6 +195,7 @@ static GdkPixbufModule file_formats [] = {
{ "ras", pixbuf_check_sunras, NULL, NULL, NULL, NULL, NULL, NULL },
{ "ico", pixbuf_check_ico, NULL, NULL, NULL, NULL, NULL, NULL },
{ "bmp", pixbuf_check_bmp, NULL, NULL, NULL, NULL, NULL, NULL },
{ "wbmp", pixbuf_check_wbmp, NULL, NULL, NULL, NULL, NULL, NULL }
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};
......@@ -336,39 +349,53 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
#define m_load_increment(type) extern gboolean mname(type,load_increment) (gpointer context, const guchar *buf, guint size);
#define m_load_animation(type) extern GdkPixbufAnimation * mname(type,load_animation) (FILE *f);
/* PNG */
m_load (png);
m_begin_load (png);
m_load_increment (png);
m_stop_load (png);
/* BMP */
m_load (bmp);
m_begin_load (bmp);
m_load_increment (bmp);
m_stop_load (bmp);
/* WBMP */
m_load (wbmp);
m_begin_load (wbmp);
m_load_increment (wbmp);
m_stop_load (wbmp);
/* GIF */
m_load (gif);
m_begin_load (gif);
m_load_increment (gif);
m_stop_load (gif);
m_load_animation (gif);
/* ICO */
m_load (ico);
m_begin_load (ico);
m_load_increment (ico);
m_stop_load (ico);
/* JPEG */
m_load (jpeg);
m_begin_load (jpeg);
m_load_increment (jpeg);
m_stop_load (jpeg);
/* PNM */
m_load (pnm);
m_begin_load (pnm);
m_load_increment (pnm);
m_stop_load (pnm);
/* RAS */
m_load (ras);
m_begin_load (ras);
m_load_increment (ras);
m_stop_load (ras);
/* TIFF */
m_load (tiff);
m_begin_load (tiff);
m_load_increment (tiff);
m_stop_load (tiff);
/* XPM */
m_load (xpm);
m_load_xpm_data (xpm);
......@@ -393,6 +420,14 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
return;
}
if (strcmp (image_module->module_name, "wbmp") == 0){
image_module->load = mname (wbmp,load);
image_module->begin_load = mname (wbmp,begin_load);
image_module->load_increment = mname (wbmp,load_increment);
image_module->stop_load = mname (wbmp,stop_load);
return;
}
if (strcmp (image_module->module_name, "gif") == 0){
image_module->load = mname (gif,load);
image_module->begin_load = mname (gif,begin_load);
......@@ -450,6 +485,19 @@ gdk_pixbuf_load_module (GdkPixbufModule *image_module)
GdkPixbufModule *
gdk_pixbuf_get_named_module (const char *name)
{
int i;
for (i = 0; file_formats [i].module_name; i++) {
if (!strcmp(name, file_formats[i].module_name))
return &(file_formats[i]);
}
return NULL;
}
GdkPixbufModule *
gdk_pixbuf_get_module (guchar *buffer, guint size)
{
......
......@@ -73,6 +73,7 @@ struct _GdkPixbufModule {
GdkPixbufModule *gdk_pixbuf_get_module (guchar *buffer, guint size);
GdkPixbufModule *gdk_pixbuf_get_named_module (const char *name);
void gdk_pixbuf_load_module (GdkPixbufModule *image_module);
......
......@@ -337,25 +337,15 @@ gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf,
gtk_signal_emit (GTK_OBJECT (loader), pixbuf_loader_signals[ANIMATION_DONE]);
}
/**
* gdk_pixbuf_loader_new:
*
* Creates a new pixbuf loader object.
*
* Return value: A newly-created pixbuf loader.
**/
GdkPixbufLoader *
gdk_pixbuf_loader_new (void)
{
return g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
}
static gint
gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader)
gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader, const char *image_type)
{
GdkPixbufLoaderPrivate *priv = loader->private;
priv->image_module = gdk_pixbuf_get_module (priv->header_buf, priv->header_buf_offset);
if(image_type)
priv->image_module = gdk_pixbuf_get_named_module (image_type);
else
priv->image_module = gdk_pixbuf_get_module (priv->header_buf, priv->header_buf_offset);
if (priv->image_module == NULL)
return 0;
......@@ -387,7 +377,8 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader)
return 0;
}
if (priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset))
if (priv->header_buf_offset
&& priv->image_module->load_increment (priv->context, priv->header_buf, priv->header_buf_offset))
return priv->header_buf_offset;
return 0;
......@@ -465,6 +456,38 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
return TRUE;
}
/**
* gdk_pixbuf_loader_new:
*
* Creates a new pixbuf loader object.
*
* Return value: A newly-created pixbuf loader.
**/
GdkPixbufLoader *
gdk_pixbuf_loader_new (void)
{
return g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
}
/**
* gdk_pixbuf_loader_new_with_type:
*
* Creates a new pixbuf loader object.
*
* Return value: A newly-created pixbuf loader.
**/
GdkPixbufLoader *
gdk_pixbuf_loader_new_with_type (const char *image_type)
{
GdkPixbufLoader *retval;
retval = g_object_new (GDK_TYPE_PIXBUF_LOADER, NULL);
gdk_pixbuf_loader_load_module(retval, image_type);
return retval;
}
/**
* gdk_pixbuf_loader_get_pixbuf:
* @loader: A pixbuf loader.
......
......@@ -72,6 +72,7 @@ struct _GdkPixbufLoaderClass
GtkType gdk_pixbuf_loader_get_type (void);
GdkPixbufLoader * gdk_pixbuf_loader_new (void);
GdkPixbufLoader * gdk_pixbuf_loader_new_with_type (const char *image_type);
gboolean gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
const guchar *buf,
gsize count);
......
......@@ -186,7 +186,7 @@ gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, guchar * buf,
generic_image_load enters gdk-pixbuf-io. */
GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f)
{
guchar *membuf;
guchar membuf[4096];
size_t length;
struct bmp_progressive_state *State;
......@@ -194,22 +194,16 @@ GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f)
State =
gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL);
membuf = g_malloc(4096);
g_assert(membuf != NULL);
while (feof(f) == 0) {
length = fread(membuf, 1, 4096, f);
if (length > 0)
(void)
gdk_pixbuf__bmp_image_load_increment(State,
membuf,
length);
}
g_free(membuf);
if (State->pixbuf != NULL)
gdk_pixbuf_ref(State->pixbuf);
......
/* GdkPixbuf library - Wireless Bitmap image loader
*
* Copyright (C) 2000 Red Hat, Inc.
*
* Authors: Elliot Lee <sopwith@redhat.com
*
* Based on io-bmp.c
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
Known bugs:
* Since this is based off the libgd implementation, no extended headers implemented (not required for a WAP client)
*/
#include <config.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h"
/* Progressive loading */
struct wbmp_progressive_state {
ModulePreparedNotifyFunc prepared_func;
ModuleUpdatedNotifyFunc updated_func;
gpointer user_data;
gboolean need_type : 1;
gboolean need_header : 1;
gboolean need_width : 1;
gboolean need_height : 1;
gboolean needmore : 1;
gboolean call_progressive_updates : 1;
guchar last_buf[16]; /* Just needs to be big enough to hold the largest datum requestable via 'getin' */
guint last_len;
int type;
int width, height, curx, cury;
GdkPixbuf *pixbuf; /* Our "target" */
};
gpointer
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc
anim_done_func, gpointer user_data);
void gdk_pixbuf__wbmp_image_stop_load(gpointer data);
gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data, guchar * buf,
guint size);
/* Shared library entry point --> This should be removed when
generic_image_load enters gdk-pixbuf-io. */
GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f)
{
size_t length;
char membuf[4096];
struct bmp_progressive_state *State;
GdkPixbuf *pb;
State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL);
while (feof(f) == 0) {
length = fread(membuf, 1, 4096, f);
if (length > 0)
gdk_pixbuf__wbmp_image_load_increment(State,
membuf,
length);
}
if (State->pixbuf != NULL)
gdk_pixbuf_ref(State->pixbuf);
pb = State->pixbuf;
gdk_pixbuf__bmp_image_stop_load(State);
return pb;
}
/*
* func - called when we have pixmap created (but no image data)
* user_data - passed as arg 1 to func
* return context (opaque to user)
*/
gpointer
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc
anim_done_func, gpointer user_data)
{
struct bmp_progressive_state *context;
context = g_new0(struct bmp_progressive_state, 1);
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
context->needmore = context->need_type = context->need_header = context->need_width = context->need_height = TRUE;
context->call_progressive_updates = TRUE;
context->pixbuf = NULL;
return (gpointer) context;
}
/*
* context - returned from image_begin_load
*
* free context, unref gdk_pixbuf
*/
void gdk_pixbuf__wbmp_image_stop_load(gpointer data)
{
struct bmp_progressive_state *context =
(struct bmp_progressive_state *) data;
g_return_if_fail(context != NULL);
if (context->pixbuf)
gdk_pixbuf_unref(context->pixbuf);
g_free(context);
}
static gboolean
getin(struct bmp_progressive_state *context, const guchar **buf, guint *buf_size, guchar *ptr, int datum_size)
{
int last_num, buf_num;
if((context->last_len + *buf_size) < datum_size)
return FALSE;
/* We know we can pull it out of there */
last_num = MIN(datum_size, context->last_len);
buf_num = MIN(datum_size-last_num, *buf_size);
memcpy(ptr, context->last_buf, last_num);
memcpy(ptr+last_num, *buf, buf_num);
context->last_len -= last_num;
if(context->last_len)
memmove(context->last_buf, context->last_buf+last_num, context->last_len);
*buf_size -= buf_num;
*buf += buf_num;
}
static gboolean
save_rest(struct bmp_progressive_state *context, const guchar *buf, guint buf_size)
{
if(buf_size > (sizeof(context->last_buf) - context->last_len))
return FALSE;
memcpy(context->last_buf+context->last_len, buf, buf_size);
context->last_len += buf_size;
return TRUE;
}
static gboolean
get_mbi(struct bmp_progressive_state *context, const guchar **buf, guint *buf_size, int *val)
{
guchar intbuf[16];
int i, n;
guchar last;
gboolean rv;
*val = 0;
n = i = 0;
do {
rv = getin(context, buf, buf_size, intbuf+n, 1);
if(!rv)
goto out;
*val <<= 7;
*val |= intbuf[n] & 0x7F;
n++;
} while(n < sizeof(intbuf) && (intbuf[n-1] & 0x80));
out:
if(!rv || !(intbuf[n-1] & 0x80))
{
rv = save_rest(context, intbuf, n);
if(!rv)
g_error("Couldn't save_rest of intbuf");
return FALSE;
}
return TRUE;
}
/*
* context - from image_begin_load
* buf - new image data
* size - length of new image data
*
* append image data onto inrecrementally built output image
*/
gboolean gdk_pixbuf__bmp_image_load_increment(gpointer data, guchar * buf,
guint size)
{
struct bmp_progressive_state *context =
(struct bmp_progressive_state *) data;
gboolean bv;
do
{
if(context->need_type)
{
guchar val;
bv = getin(context, &buf, &size, &val, 1);
if(bv)
{
context->type = val;
context->need_type = FALSE;
}
}
else if(context->need_header)
{
guchar val;
bv = getin(context, &buf, &size, &val, 1);
if(bv)
{
/* We skip over the extended header - val is unused */
if(!(val & 0x80))
context->need_header = FALSE;
}
}
else if(context->need_width)
{
bv = get_mbi(context, &buf, &size, &context->width);
if(bv)
context->need_width = FALSE;
}
else if(context->need_height)
{
bv = get_mbi(context, &buf, &size, &context->height);
if(bv)
{
context->need_height = FALSE;
context->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, context->width, context->height);
if(context->prepared_func)
context->prepared_func(context->pixbuf, context->user_data);
}
}
else if(context->needmore)
{
int first_row;
first_row = context->cury;
for( ; context->cury < context->height; context->cury++, context->curx = 0)
{
for( ; context->curx < context->width, context->curx += 8)
{
guchar byte;
guchar *ptr;
int xoff;
bv = getin(context, &buf, &size, &byte, 1);
if(!bv)
goto out;
ptr = context->pixbuf->pixels + context->pixbuf->rowstride * context->cury + context->curx * 3;
for(xoff = 0; xoff < 8; xoff++, ptr += 3)
{
guchar pixval;
if(byte & (1<<xoff))
pixval = 0xFF;
else
pixval = 0x0;
ptr[0] = ptr[1] = ptr[2] = pixval;
}
}
}
context->needmore = FALSE;
out:
context->updated_func(context->pixbuf, 0, first_row, context->width, context->cury - first_row + 1,
context->user_data);
}
else
bv = FALSE; /* Nothing left to do, stop feeding me data! */
} while(bv);
if(size)
return save_rest(context, buf, size);
else
return context->needmore;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment