Commit 8b6950ae authored by Matthias Clasen's avatar Matthias Clasen Committed by Matthias Clasen

Make it possible to call gdk_pixbuf_loader_set_size (loader, 0, 0) by

Wed Jan  7 01:17:36 2004  Matthias Clasen  <maclas@gmx.de>

	* gdk-pixbuf-loader.c (gdk_pixbuf_loader_size_func):
	* gdk-pixbuf-loader.c (gdk_pixbuf_loader_set_size):
	* gdk-pixbuf-loader.c (gdk_pixbuf_loader_init): Make it possible
	to call gdk_pixbuf_loader_set_size (loader, 0, 0) by changing
	the initial values of priv->width/height to -1.

	* io-tiff.c (tiff_image_parse):
	* io-ras.c (RAS2State):
	* io-pnm.c (gdk_pixbuf__pnm_image_load_increment):
	* io-pcx.c (gdk_pixbuf__pcx_load_increment):
	* io-jpeg.c (gdk_pixbuf__jpeg_image_load_increment):
	* io-png.c (png_info_callback):
	* io-ico.c (DecodeHeader):
	* io-bmp.c (DecodeHeader): Call size_func once the size is known,
	even if the module can't make use of the scaling information. If
	size_func returns 0, don't allocate a pixbuf and return, if
	necessary with an error.

	* gdk-pixbuf.h:
	* gdk-pixbuf-io.c (gdk_pixbuf_get_file_info): A new function
	to determine the type and size of an image file without loading
	it completely.  (#53725)
parent 46a71302
......@@ -57,6 +57,7 @@ GdkPixbufDestroyNotify
<FILE>file-loading</FILE>
gdk_pixbuf_new_from_file
gdk_pixbuf_new_from_file_at_size
gdk_pixbuf_get_file_info
</SECTION>
<SECTION>
......
......@@ -910,6 +910,93 @@ gdk_pixbuf_new_from_file_at_size (const char *filename,
return pixbuf;
}
static void
info_cb (GdkPixbufLoader *loader,
int width,
int height,
gpointer data)
{
struct {
GdkPixbufFormat *format;
int width;
int height;
} *info = data;
g_return_if_fail (width > 0 && height > 0);
info->format = gdk_pixbuf_loader_get_format (loader);
info->width = width;
info->height = height;
gdk_pixbuf_loader_set_size (loader, 0, 0);
}
/**
* gdk_pixbuf_get_file_info:
* @filename: The name of the file to identify.
* @width: Return location for the width of the image, or %NULL
* @height: Return location for the height of the image, or %NULL
*
* Parses an image file far enough to determine its format and size.
*
* Returns: A #GdkPixbufFormat describing the image format of the file
* or %NULL if the image format wasn't recognized. The return value
* is owned by GdkPixbuf and should not be freed.
*
* Since: 2.4
**/
GdkPixbufFormat *
gdk_pixbuf_get_file_info (const gchar *filename,
gint *width,
gint *height)
{
GdkPixbufLoader *loader;
GError *temp = NULL;
guchar buffer [4096];
int length;
FILE *f;
struct {
GdkPixbufFormat *format;
gint width;
gint height;
} info;
g_return_val_if_fail (filename != NULL, NULL);
f = fopen (filename, "rb");
if (!f)
return NULL;
loader = gdk_pixbuf_loader_new ();
info.format = NULL;
info.width = -1;
info.height = -1;
g_signal_connect (loader, "size-prepared", G_CALLBACK (info_cb), &info);
while (!feof (f)) {
length = fread (buffer, 1, sizeof (buffer), f);
if (length > 0) {
if (!gdk_pixbuf_loader_write (loader, buffer, length, NULL))
break;
}
if (info.format != NULL)
break;
}
fclose (f);
gdk_pixbuf_loader_close (loader, NULL);
g_object_unref (G_OBJECT (loader));
if (width)
*width = info.width;
if (height)
*height = info.height;
return info.format;
}
/**
* gdk_pixbuf_new_from_xpm_data:
* @data: Pointer to inline XPM data.
......
......@@ -208,6 +208,9 @@ gdk_pixbuf_loader_init (GdkPixbufLoader *loader)
GdkPixbufLoaderPrivate *priv;
priv = g_new0 (GdkPixbufLoaderPrivate, 1);
priv->width = -1;
priv->height = -1;
loader->priv = priv;
}
......@@ -253,7 +256,7 @@ gdk_pixbuf_loader_set_size (GdkPixbufLoader *loader,
gint height)
{
GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
g_return_if_fail (width > 0 && height > 0);
g_return_if_fail (width >= 0 && height >= 0);
if (!priv->size_fixed)
{
......@@ -268,7 +271,7 @@ gdk_pixbuf_loader_size_func (gint *width, gint *height, gpointer loader)
GdkPixbufLoaderPrivate *priv = GDK_PIXBUF_LOADER (loader)->priv;
/* allow calling gdk_pixbuf_loader_set_size() before the signal */
if (priv->width == 0 && priv->height == 0)
if (priv->width == -1 && priv->height == -1)
{
priv->width = *width;
priv->height = *height;
......
......@@ -302,6 +302,10 @@ gchar **gdk_pixbuf_format_get_mime_types (GdkPixbufFormat *format);
gchar **gdk_pixbuf_format_get_extensions (GdkPixbufFormat *format);
gboolean gdk_pixbuf_format_is_writable (GdkPixbufFormat *format);
GdkPixbufFormat *gdk_pixbuf_get_file_info (const gchar *filename,
gint *width,
gint *height);
G_END_DECLS
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
......
......@@ -144,6 +144,7 @@ struct bmp_compression_state {
/* Progressive loading */
struct bmp_progressive_state {
GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
......@@ -319,41 +320,52 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
State->LineWidth = (State->LineWidth / 4) * 4 + 4;
if (State->pixbuf == NULL) {
if (State->size_func) {
gint width = State->Header.width;
gint height = State->Header.height;
(*State->size_func) (&width, &height, State->user_data);
if (width == 0 || height == 0) {
State->read_state = READ_STATE_DONE;
State->BufferSize = 0;
return TRUE;
}
}
if (State->Type == 32 ||
State->Compressed == BI_RLE4 ||
State->Compressed == BI_RLE8)
State->pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
else
State->pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
if (State->pixbuf == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load bitmap image"));
gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
(gint) State->Header.width,
(gint) State->Header.height);
if (State->pixbuf == NULL) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
_("Not enough memory to load bitmap image"));
State->read_state = READ_STATE_ERROR;
return FALSE;
}
return FALSE;
}
if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf, NULL, State->user_data);
/* make all pixels initially transparent */
if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
State->compr.p = State->pixbuf->pixels
+ State->pixbuf->rowstride * (State->Header.height- 1);
}
}
/* make all pixels initially transparent */
if (State->Compressed == BI_RLE4 || State->Compressed == BI_RLE8) {
memset (State->pixbuf->pixels, 0, State->pixbuf->rowstride * State->Header.height);
State->compr.p = State->pixbuf->pixels
+ State->pixbuf->rowstride * (State->Header.height- 1);
}
State->BufferDone = 0;
if (State->Type <= 8) {
State->read_state = READ_STATE_PALETTE;
......@@ -485,6 +497,7 @@ gdk_pixbuf__bmp_image_begin_load(GdkPixbufModuleSizeFunc size_func,
struct bmp_progressive_state *context;
context = g_new0(struct bmp_progressive_state, 1);
context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
......@@ -1036,6 +1049,9 @@ gdk_pixbuf__bmp_image_load_increment(gpointer data,
return FALSE;
break;
case READ_STATE_DONE:
return TRUE;
break;
default:
g_assert_not_reached ();
......
......@@ -126,6 +126,7 @@ struct headerpair {
};
struct ico_progressive_state {
GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
......@@ -400,6 +401,19 @@ static void DecodeHeader(guchar *Data, gint Bytes,
if (State->pixbuf == NULL) {
#if 1
if (State->size_func) {
gint width = State->Header.width;
gint height = State->Header.height;
(*State->size_func) (&width, &height, State->user_data);
if (width == 0 || height == 0) {
State->LineWidth = 0;
return;
}
}
#endif
State->pixbuf =
gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
State->Header.width,
......@@ -445,6 +459,7 @@ gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
struct ico_progressive_state *context;
context = g_new0(struct ico_progressive_state, 1);
context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
......@@ -828,6 +843,9 @@ gdk_pixbuf__ico_image_load_increment(gpointer data,
GError *decode_err = NULL;
DecodeHeader(context->HeaderBuf,
context->HeaderDone, context, &decode_err);
if (context->LineBuf != NULL && context->LineWidth == 0)
return TRUE;
if (decode_err) {
g_propagate_error (error, decode_err);
return FALSE;
......
......@@ -650,7 +650,12 @@ gdk_pixbuf__jpeg_image_load_increment (gpointer data,
width = cinfo->image_width;
height = cinfo->image_height;
(* context->size_func) (&width, &height, context->user_data);
if (context->size_func) {
(* context->size_func) (&width, &height, context->user_data);
if (width == 0 || height == 0)
return FALSE;
}
for (cinfo->scale_denom = 2; cinfo->scale_denom <= 8; cinfo->scale_denom *= 2) {
jpeg_calc_output_dimensions (cinfo);
if (cinfo->output_width < width || cinfo->output_height < height) {
......
......@@ -606,8 +606,12 @@ gdk_pixbuf__pcx_load_increment(gpointer data, const guchar *buf, guint size,
g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, _("Image has invalid width and/or height"));
return FALSE;
}
if(context->size_func)
context->size_func(&width, &height, context->user_data);
if (context->size_func)
{
(*context->size_func) (&width, &height, context->user_data);
if (width == 0 || height == 0)
return TRUE;
}
switch(context->bpp) {
default:
......
......@@ -358,6 +358,7 @@ struct _LoadContext {
png_structp png_read_ptr;
png_infop png_info_ptr;
GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepare_func;
GdkPixbufModuleUpdatedFunc update_func;
gpointer notify_user_data;
......@@ -398,6 +399,7 @@ gdk_pixbuf__png_image_begin_load (GdkPixbufModuleSizeFunc size_func,
lc->fatal_error_occurred = FALSE;
lc->size_func = size_func;
lc->prepare_func = prepare_func;
lc->update_func = update_func;
lc->notify_user_data = user_data;
......@@ -593,7 +595,18 @@ png_info_callback (png_structp png_read_ptr,
if (color_type & PNG_COLOR_MASK_ALPHA)
have_alpha = TRUE;
lc->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, have_alpha, 8, width, height);
if (lc->size_func) {
gint w = width;
gint h = height;
(* lc->size_func) (&w, &h, lc->notify_user_data);
if (w == 0 || h == 0) {
lc->fatal_error_occurred = TRUE;
return;
}
}
lc->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, have_alpha, 8, width, height);
if (lc->pixbuf == NULL) {
/* Failed to allocate memory */
......
......@@ -55,6 +55,7 @@ typedef struct {
typedef struct {
GdkPixbufModuleUpdatedFunc updated_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleSizeFunc size_func;
gpointer user_data;
GdkPixbuf *pixbuf;
......@@ -820,6 +821,7 @@ gdk_pixbuf__pnm_image_begin_load (GdkPixbufModuleSizeFunc size_func,
return NULL;
}
memset (context, 0, sizeof (PnmLoaderContext));
context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
......@@ -944,6 +946,16 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
context->got_header = TRUE;
}
if (context->size_func) {
gint w = context->width;
gint h = context->height;
(*context->size_func) (&w, &h, context->user_data);
if (w == 0 || h == 0)
return FALSE;
}
/* scan until we hit image data */
if (!context->did_prescan) {
......
......@@ -68,6 +68,7 @@ struct rasterfile {
/* Progressive loading */
struct ras_progressive_state {
GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepared_func;
GdkPixbufModuleUpdatedFunc updated_func;
gpointer user_data;
......@@ -174,6 +175,15 @@ static gboolean RAS2State(struct rasterfile *RAS,
if (!State->pixbuf) {
if (State->size_func) {
gint width = State->Header.width;
gint height = State->Header.height;
(*State->size_func) (&width, &height, State->user_data);
if (width == 0 || height == 0)
return FALSE;
}
if (State->RasType == 32)
State->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
(gint) State->Header.width,
......@@ -227,6 +237,7 @@ gdk_pixbuf__ras_image_begin_load(GdkPixbufModuleSizeFunc size_func,
struct ras_progressive_state *context;
context = g_new0(struct ras_progressive_state, 1);
context->size_func = size_func;
context->prepared_func = prepared_func;
context->updated_func = updated_func;
context->user_data = user_data;
......
......@@ -137,6 +137,7 @@ struct _TGAContext {
gboolean prepared;
gboolean done;
GdkPixbufModuleSizeFunc sfunc;
GdkPixbufModulePreparedFunc pfunc;
GdkPixbufModuleUpdatedFunc ufunc;
gpointer udata;
......@@ -334,6 +335,16 @@ static gboolean fill_in_context(TGAContext *ctx, GError **err)
w = LE16(ctx->hdr->width);
h = LE16(ctx->hdr->height);
if (ctx->sfunc) {
gint wi = w;
gint hi = h;
(*ctx->sfunc) (&wi, &hi, ctx->udata);
if (wi == 0 || hi == 0)
return FALSE;
}
ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
if (!ctx->pbuf) {
......@@ -872,6 +883,7 @@ static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
ctx->prepared = FALSE;
ctx->done = FALSE;
ctx->sfunc = f0;
ctx->pfunc = f1;
ctx->ufunc = f2;
ctx->udata = udata;
......
......@@ -47,6 +47,7 @@
typedef struct _TiffContext TiffContext;
struct _TiffContext
{
GdkPixbufModuleSizeFunc size_func;
GdkPixbufModulePreparedFunc prepare_func;
GdkPixbufModuleUpdatedFunc update_func;
gpointer user_data;
......@@ -225,6 +226,15 @@ tiff_image_parse (TIFF *tiff, TiffContext *context, GError **error)
return NULL;
}
if (context && context->size_func) {
gint w = width;
gint h = height;
(* context->size_func) (&w, &h, context->user_data);
if (w == 0 || h == 0)
return NULL;
}
pixels = g_try_malloc (bytes);
if (!pixels) {
......@@ -370,6 +380,7 @@ gdk_pixbuf__tiff_image_begin_load (GdkPixbufModuleSizeFunc size_func,
TiffContext *context;
context = g_new0 (TiffContext, 1);
context->size_func = size_func;
context->prepare_func = prepare_func;
context->update_func = update_func;
context->user_data = user_data;
......
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