Commit bc5011e4 authored by Sven Neumann's avatar Sven Neumann Committed by Sven Neumann
Browse files

added some safety checks.

2001-11-13  Sven Neumann  <sven@gimp.org>

	* app/base/temp-buf.c: added some safety checks.

	* app/widgets/Makefile.am
	* app/widgets/widgets-types.h
	* app/widgets/gimpimagefilepreview.[ch]: a new class implementing
	special	GimpPreview methods for GimpImagefile.

	* app/core/gimpimagefile.c: added code to load thumbnails according
	to the proposed Thumbnail Managing Standard
	(see http://triq.net/~pearl/thumbnail-spec/). Pretty much untested.

	* app/widgets/gimpcontainerview-utils.c: plugged a memleak.

	* app/widgets/gimpimagepreview.c: simplified.

	* app/widgets/gimppreview.c: tell it about GimpImagefilePreview.
parent d247c068
2001-11-13 Sven Neumann <sven@gimp.org>
* app/base/temp-buf.c: added some safety checks.
* app/widgets/Makefile.am
* app/widgets/widgets-types.h
* app/widgets/gimpimagefilepreview.[ch]: a new class implementing
special GimpPreview methods for GimpImagefile.
* app/core/gimpimagefile.c: added code to load thumbnails according
to the proposed Thumbnail Managing Standard
(see http://triq.net/~pearl/thumbnail-spec/). Pretty much untested.
* app/widgets/gimpcontainerview-utils.c: plugged a memleak.
* app/widgets/gimpimagepreview.c: simplified.
* app/widgets/gimppreview.c: tell it about GimpImagefilePreview.
2001-11-13 Michael Natterer <mitch@gimp.org> 2001-11-13 Michael Natterer <mitch@gimp.org>
* app/core/Makefile.am: need to spell EXTRA_DIST correctly now * app/core/Makefile.am: need to spell EXTRA_DIST correctly now
......
...@@ -129,6 +129,8 @@ temp_buf_new (gint width, ...@@ -129,6 +129,8 @@ temp_buf_new (gint width,
guchar *data; guchar *data;
TempBuf *temp; TempBuf *temp;
g_return_val_if_fail (width > 0 && height > 0, NULL);
temp = g_new (TempBuf, 1); temp = g_new (TempBuf, 1);
temp->width = width; temp->width = width;
...@@ -200,17 +202,14 @@ temp_buf_new_check (gint width, ...@@ -200,17 +202,14 @@ temp_buf_new_check (gint width,
GimpCheckType check_type, GimpCheckType check_type,
GimpCheckSize check_size) GimpCheckSize check_size)
{ {
TempBuf *newbuf = NULL; TempBuf *newbuf;
guchar *data = 0; guchar *data;
guchar check_shift = 0; guchar check_shift = 0;
guchar fg_color = 0; guchar fg_color = 0;
guchar bg_color = 0; guchar bg_color = 0;
gint j, i = 0; gint i, j;
if (check_type < LIGHT_CHECKS || check_type > BLACK_ONLY) g_return_val_if_fail (width > 0 && height > 0, NULL);
g_error ("invalid check_type argument to temp_buf_check: %d", check_type);
if (check_size < SMALL_CHECKS || check_size > LARGE_CHECKS)
g_error ("invalid check_size argument to temp_buf_check: %d", check_size);
switch (check_size) switch (check_size)
{ {
...@@ -222,6 +221,7 @@ temp_buf_new_check (gint width, ...@@ -222,6 +221,7 @@ temp_buf_new_check (gint width,
break; break;
case LARGE_CHECKS: case LARGE_CHECKS:
check_shift = 6; check_shift = 6;
break;
} }
switch (check_type) switch (check_type)
...@@ -254,7 +254,7 @@ temp_buf_new_check (gint width, ...@@ -254,7 +254,7 @@ temp_buf_new_check (gint width,
newbuf = temp_buf_new (width, height, 3, 0, 0, NULL); newbuf = temp_buf_new (width, height, 3, 0, 0, NULL);
data = temp_buf_data (newbuf); data = temp_buf_data (newbuf);
for (j = 1; i <= height; j++) for (i = 0, j = 1; i <= height; j++)
{ {
for (i = 1; i <= width; i++) for (i = 1; i <= width; i++)
{ {
...@@ -273,11 +273,7 @@ temp_buf_copy (TempBuf *src, ...@@ -273,11 +273,7 @@ temp_buf_copy (TempBuf *src,
TempBuf *new; TempBuf *new;
glong length; glong length;
if (!src) g_return_val_if_fail (src != NULL, NULL);
{
g_message ("trying to copy a temp buf which is NULL.");
return dest;
}
if (!dest) if (!dest)
{ {
...@@ -320,6 +316,9 @@ temp_buf_resize (TempBuf *buf, ...@@ -320,6 +316,9 @@ temp_buf_resize (TempBuf *buf,
{ {
gint size; gint size;
g_return_val_if_fail (buf != NULL, NULL);
g_return_val_if_fail (width > 0 && height > 0, NULL);
/* calculate the requested size */ /* calculate the requested size */
size = width * height * bytes; size = width * height * bytes;
...@@ -363,6 +362,9 @@ temp_buf_scale (TempBuf *src, ...@@ -363,6 +362,9 @@ temp_buf_scale (TempBuf *src,
guchar *dest_data; guchar *dest_data;
TempBuf *dest; TempBuf *dest;
g_return_val_if_fail (src != NULL, NULL);
g_return_val_if_fail (new_width > 0 && new_height > 0, NULL);
dest = temp_buf_new (new_width, dest = temp_buf_new (new_width,
new_height, new_height,
src->bytes, src->bytes,
...@@ -469,6 +471,8 @@ temp_buf_copy_area (TempBuf *src, ...@@ -469,6 +471,8 @@ temp_buf_copy_area (TempBuf *src,
void void
temp_buf_free (TempBuf *temp_buf) temp_buf_free (TempBuf *temp_buf)
{ {
g_return_if_fail (temp_buf != NULL);
if (temp_buf->data) if (temp_buf->data)
g_free (temp_buf->data); g_free (temp_buf->data);
......
...@@ -37,18 +37,44 @@ ...@@ -37,18 +37,44 @@
#include "gimpimagefile.h" #include "gimpimagefile.h"
#include "libgimp/gimpintl.h"
static void gimp_imagefile_class_init (GimpImagefileClass *klass);
static void gimp_imagefile_init (GimpImagefile *imagefile);
static void gimp_imagefile_finalize (GObject *object);
static TempBuf * gimp_imagefile_get_new_preview (GimpViewable *viewable,
gint width,
gint height);
static guchar * readXVThumb (const gchar *filename, typedef struct
gint *width, {
gint *height, const gchar *dirname;
gchar **imginfo); gint size;
} ThumbnailSize;
static const ThumbnailSize thumb_sizes[] =
{
{ "48x48", 48 },
{ "64x64", 64 },
{ "96x96", 96 },
{ "128x128", 128 },
{ "144x144", 144 },
{ "160x160", 160 },
{ "192x192", 192 },
};
static void gimp_imagefile_class_init (GimpImagefileClass *klass);
static void gimp_imagefile_init (GimpImagefile *imagefile);
static TempBuf * gimp_imagefile_get_new_preview (GimpViewable *viewable,
gint width,
gint height);
static TempBuf * gimp_imagefile_read_png_thumb (GimpImagefile *imagefile,
gint size);
static gchar * gimp_imagefile_png_thumb_name (const gchar *dirname,
const gchar *basename,
gint size);
static TempBuf * gimp_imagefile_read_xv_thumb (GimpImagefile *imagefile);
static guchar * readXVThumb (const gchar *filename,
gint *width,
gint *height,
gchar **imginfo);
static GimpViewableClass *parent_class = NULL; static GimpViewableClass *parent_class = NULL;
...@@ -85,38 +111,23 @@ gimp_imagefile_get_type (void) ...@@ -85,38 +111,23 @@ gimp_imagefile_get_type (void)
static void static void
gimp_imagefile_class_init (GimpImagefileClass *klass) gimp_imagefile_class_init (GimpImagefileClass *klass)
{ {
GObjectClass *object_class;
GimpViewableClass *viewable_class; GimpViewableClass *viewable_class;
object_class = G_OBJECT_CLASS (klass);
viewable_class = GIMP_VIEWABLE_CLASS (klass);
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
viewable_class->get_new_preview = gimp_imagefile_get_new_preview; viewable_class = GIMP_VIEWABLE_CLASS (klass);
object_class->finalize = gimp_imagefile_finalize; viewable_class->get_new_preview = gimp_imagefile_get_new_preview;
} }
static void static void
gimp_imagefile_init (GimpImagefile *imagefile) gimp_imagefile_init (GimpImagefile *imagefile)
{ {
imagefile->width = -1; imagefile->width = 0;
imagefile->height = -1; imagefile->height = 0;
imagefile->size = -1; imagefile->size = -1;
} }
static void
gimp_imagefile_finalize (GObject *object)
{
GimpImagefile *imagefile;
imagefile = GIMP_IMAGEFILE (object);
if (G_OBJECT_CLASS (parent_class)->finalize)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
GimpImagefile * GimpImagefile *
gimp_imagefile_new (const gchar *filename) gimp_imagefile_new (const gchar *filename)
{ {
...@@ -131,32 +142,213 @@ gimp_imagefile_new (const gchar *filename) ...@@ -131,32 +142,213 @@ gimp_imagefile_new (const gchar *filename)
return imagefile; return imagefile;
} }
static void
gimp_imagefile_set_info (GimpImagefile *imagefile,
gint width,
gint height,
gint size)
{
gboolean changed;
changed = (imagefile->width != width || imagefile->height != height ||
imagefile->size != size);
imagefile->width = width;
imagefile->height = height;
imagefile->size = size;
/* emit a name changed signal so the container view updates */
if (changed)
gimp_object_name_changed (GIMP_OBJECT (imagefile));
}
static void
gimp_imagefile_set_info_from_pixbuf (GimpImagefile *imagefile,
GdkPixbuf *pixbuf)
{
const gchar *option;
gint img_width;
gint img_height;
gint img_size;
option = gdk_pixbuf_get_option (pixbuf, "tEXt::OriginalWidth");
if (!option || sscanf (option, "%d", &img_width) != 1)
img_width = 0;
option = gdk_pixbuf_get_option (pixbuf, "tEXt::OriginalHeight");
if (!option || sscanf (option, "%d", &img_height) != 1)
img_height = 0;
option = gdk_pixbuf_get_option (pixbuf, "tEXt::OriginalSize");
if (!option || sscanf (option, "%d", &img_size) != 1)
img_size = -1;
gimp_imagefile_set_info (imagefile, img_width, img_height, img_size);
}
static TempBuf * static TempBuf *
gimp_imagefile_get_new_preview (GimpViewable *viewable, gimp_imagefile_get_new_preview (GimpViewable *viewable,
gint width, gint width,
gint height) gint height)
{ {
GimpImagefile *imagefile; GimpImagefile *imagefile;
TempBuf *temp_buf;
imagefile = GIMP_IMAGEFILE (viewable);
g_return_val_if_fail (GIMP_OBJECT (imagefile)->name != NULL, NULL);
temp_buf = gimp_imagefile_read_png_thumb (imagefile, MAX (width, height));
if (!temp_buf)
temp_buf = gimp_imagefile_read_xv_thumb (imagefile);
return temp_buf;
}
/* PNG thumbnail reading routines according to the
Thumbnail Managing Standard http://triq.net/~pearl/thumbnail-spec/ */
static TempBuf *
gimp_imagefile_read_png_thumb (GimpImagefile *imagefile,
gint size)
{
TempBuf *temp_buf;
GdkPixbuf *pixbuf;
gchar *basename;
gchar *dirname;
gchar *fullname;
gchar *thumbname;
gint width;
gint height;
gint bytes;
gint y;
guchar *src;
guchar *dest;
GError *error;
fullname = g_strconcat (GIMP_OBJECT (imagefile)->name, ".png", NULL);
dirname = g_path_get_dirname (GIMP_OBJECT (imagefile)->name);
basename = g_path_get_basename (fullname);
thumbname = gimp_imagefile_png_thumb_name (dirname,
basename,
size);
g_free (dirname);
g_free (basename);
if (!thumbname)
thumbname = gimp_imagefile_png_thumb_name (g_get_home_dir(),
fullname,
size);
g_free (fullname);
if (!thumbname)
return NULL;
pixbuf = gdk_pixbuf_new_from_file (thumbname, &error);
if (!pixbuf)
{
g_message (_("Couldn't open thumbnail file '%s'\n%s"),
thumbname, error->message);
g_free (thumbname);
g_error_free (error);
return NULL;
}
g_free (thumbname);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
bytes = gdk_pixbuf_get_n_channels (pixbuf);
temp_buf = temp_buf_new (width, height, bytes, 0, 0, NULL);
dest = temp_buf_data (temp_buf);
src = gdk_pixbuf_get_pixels (pixbuf);
for (y = 0; y < height; y++)
{
memcpy (dest, src, width * bytes);
dest += width * bytes;
src += gdk_pixbuf_get_rowstride (pixbuf);
}
gimp_imagefile_set_info_from_pixbuf (imagefile, pixbuf);
g_object_unref (pixbuf);
return temp_buf;
}
static gchar *
gimp_imagefile_png_thumb_name (const gchar *dirname,
const gchar *basename,
gint size)
{
gchar *thumbname;
gint i, n;
n = G_N_ELEMENTS (thumb_sizes);
for (i = 0; i < n && thumb_sizes[i].size < size; i++)
/* nothing */;
n = i;
for (i = n; i < G_N_ELEMENTS (thumb_sizes); i++)
{
thumbname = g_build_filename (dirname,
".thumbnails",
thumb_sizes[i].dirname,
basename, NULL);
if (g_file_test (thumbname, G_FILE_TEST_EXISTS))
return thumbname;
g_free (thumbname);
}
for (i = n - 1; i >= 0; i--)
{
thumbname = g_build_filename (dirname,
".thumbnails",
thumb_sizes[i].dirname,
basename, NULL);
if (g_file_test (thumbname, G_FILE_TEST_EXISTS))
return thumbname;
g_free (thumbname);
}
return NULL;
}
/* xvpics thumbnail reading routines for backward compatibility */
static TempBuf *
gimp_imagefile_read_xv_thumb (GimpImagefile *imagefile)
{
gchar *basename; gchar *basename;
gchar *dirname; gchar *dirname;
gchar *thumbname; gchar *thumbname;
struct stat file_stat; struct stat file_stat;
struct stat thumb_stat; struct stat thumb_stat;
gint thumb_width; gint width;
gint thumb_height; gint height;
gint x, y; gint x, y;
gboolean thumb_may_be_outdated = FALSE; gboolean thumb_may_be_outdated = FALSE;
TempBuf *temp_buf; TempBuf *temp_buf;
guchar *raw_thumb; guchar *raw_thumb;
guchar *src; guchar *src;
guchar *dest; guchar *dest;
guchar white[3] = { 0xff, 0xff, 0xff };
gchar *image_info = NULL; gchar *image_info = NULL;
imagefile = GIMP_IMAGEFILE (viewable);
g_return_val_if_fail (GIMP_OBJECT (imagefile)->name != NULL, NULL);
dirname = g_path_get_dirname (GIMP_OBJECT (imagefile)->name); dirname = g_path_get_dirname (GIMP_OBJECT (imagefile)->name);
basename = g_path_get_basename (GIMP_OBJECT (imagefile)->name); basename = g_path_get_basename (GIMP_OBJECT (imagefile)->name);
...@@ -177,41 +369,53 @@ gimp_imagefile_get_new_preview (GimpViewable *viewable, ...@@ -177,41 +369,53 @@ gimp_imagefile_get_new_preview (GimpViewable *viewable,
} }
} }
raw_thumb = readXVThumb (thumbname, raw_thumb = readXVThumb (thumbname, &width, &height, &image_info);
&thumb_width, &thumb_height, &image_info);
g_free (thumbname); g_free (thumbname);
/* FIXME: use image info */
g_free (image_info);
if (!raw_thumb) if (!raw_thumb)
return NULL; return NULL;
/* FIXME: scale if necessary */ if (image_info)
temp_buf = temp_buf_new (width, height, 3, 0, 0, white); {
gint img_width;
gint img_height;
if (sscanf (image_info, "%dx%d", &img_width, &img_height) != 2)
{
img_width = 0;
img_height = 0;
}
gimp_imagefile_set_info (imagefile, img_width, img_height, -1);
g_free (image_info);
}
temp_buf = temp_buf_new (width, height, 3, 0, 0, NULL);
src = raw_thumb; src = raw_thumb;
dest = temp_buf_data (temp_buf); dest = temp_buf_data (temp_buf);
for (y = 0; y < MIN (height, thumb_height); y++) for (y = 0; y < height; y++)
{ {
for (x = 0; x < MIN (width, thumb_width); x++) for (x = 0; x < width; x++)
{ {
dest[x*3] = ((src[x]>>5)*255)/7; dest[x*3] = ((src[x]>>5)*255)/7;
dest[x*3+1] = (((src[x]>>2)&7)*255)/7; dest[x*3+1] = (((src[x]>>2)&7)*255)/7;
dest[x*3+2] = ((src[x]&3)*255)/3; dest[x*3+2] = ((src[x]&3)*255)/3;
} }
src += thumb_width; src += width;
dest += width * 3; dest += width * 3;
} }
g_free (raw_thumb); g_free (raw_thumb);
return temp_buf; return temp_buf;
} }
/* The readXVThumb function source may be re-used under /* The readXVThumb function source may be re-used under
the XFree86-style license. <adam@gimp.org> */ the XFree86-style license. <adam@gimp.org> */
guchar * static guchar *
readXVThumb (const gchar *fnam, readXVThumb (const gchar *fnam,
gint *w, gint *w,
gint *h, gint *h,
......
...@@ -747,7 +747,7 @@ dialogs_document_history_new (GimpDialogFactory *factory, ...@@ -747,7 +747,7 @@ dialogs_document_history_new (GimpDialogFactory *factory,
view = gimp_document_view_new (GIMP_VIEW_TYPE_LIST, view = gimp_document_view_new (GIMP_VIEW_TYPE_LIST,
context->gimp->documents, context->gimp->documents,
context, context,
32, 48,
5, 3, 5, 3,
documents_show_context_menu); documents_show_context_menu);
......
...@@ -747,7 +747,7 @@ dialogs_document_history_new (GimpDialogFactory *factory, ...@@ -747,7 +747,7 @@ dialogs_document_history_new (GimpDialogFactory *factory,
view = gimp_document_view_new (GIMP_VIEW_TYPE_LIST, view = gimp_document_view_new (GIMP_VIEW_TYPE_LIST,
context->gimp->documents, context->gimp->documents,
context, context,
32, 48,