Re: [evolution-patches] Patch to resize images
- From: Srinivasa Ragavan <sragavan novell com>
- To: Not Zed <notzed novell com>
- Cc: evolution-patches lists ximian com
- Subject: Re: [evolution-patches] Patch to resize images
- Date: Mon, 04 Jul 2005 16:58:04 +0530
I have attached a patch.
On Fri, 2005-07-01 at 13:21 +0800, Not Zed wrote:
> On Mon, 2005-06-27 at 15:27 +0530, Srinivasa Ragavan wrote:
> > Hah, I hope i have worked on most of the comments...
> >
> > - I have reused em-icon-stream
>
> "em_icon_stream_find_pixbuf"?? Its just an exact copy of
> em_icon_stream_get_image, only it doesn't ref things properly? Proper
> refcounting here is extremely critical because of the size of the
> objects, and adding redundant extra api's is pointless.
>
> Instead of both set_pixbuf and replace_pixbuf, you only need one, they
> do the same thing - actually I think you dont need any of them.
>
> The whole replace/set stuff just complicates all the logic too much.
> You always need to keep the original around, you just need to be able to
> get it scaled sometimes.
>
i have got rid of these, but added one to know whether a image is
resized or not if so whatz the size. I call this for the first time. I
guess it was needed badly for the first time.
> I think it would be easier just either expand em_icon_stream_get_image()
> to add a 'scale' argument. It can then produce a scaled image if it
> doesn't have one in the cache, etc. Then all you need to do is store a
> scale factor on the puri and remove ALL the scaling code in
> format-html-display.
>
> It would be nice if get_image returned a pixmap too, more efficient
> (internally it would still have to store the original as a pixbuf, for
> scaling).
Im dont know much about pixmap stuff. Probably will do that later, once
i have this in.
>
> > - Using my own puri
>
> But you're still using the gobject_set_data stuff. As a pretty shitty
> means to communicate across abstraction boundaries at that.
Im not using gobject_set any more.
>
> > - Fixed Object hierarchy issue
> > - reduced the complexity of the resize function
>
> It looks pretty inefficient. Copying stuff around, etc. Its not really
> that hard. You have the original, if it doesn't fit then make a scaled
> one. Anyway the outline above removes the need for all of this.
>
i guess i have followed what you said.
> > - Closed most of the memory leaks
>
> Most isn't even close to good enough. There are several obvious ones
> still left.
>
> The 'key' one is particularly baffling, you're just copying something
> you have access to anyway.
>
>
got rid of key stuff. I feel bad how i missed what i have in my hand and
added a fixme for that.
> _______________________________________________
> evolution-patches mailing list
> evolution-patches lists ximian com
> http://lists.ximian.com/mailman/listinfo/evolution-patches
Index: em-format-html-display.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format-html-display.c,v
retrieving revision 1.68
diff -u -p -r1.68 em-format-html-display.c
--- em-format-html-display.c 17 Jun 2005 15:20:29 -0000 1.68
+++ em-format-html-display.c 4 Jul 2005 11:16:07 -0000
@@ -30,6 +30,7 @@
#include <gtkhtml/gtkhtml-embedded.h>
#include <gtkhtml/gtkhtml-search.h>
+#include <gtk/gtk.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkbutton.h>
@@ -119,8 +120,13 @@ struct _attach_puri {
GtkHTML *frame;
CamelStream *output;
unsigned int shown:1;
+ int size;
+ int resized;
+ int resize_width;
+ GtkWidget *image;
};
+
static void efhd_iframe_created(GtkHTML *html, GtkHTML *iframe, EMFormatHTMLDisplay *efh);
/*static void efhd_url_requested(GtkHTML *html, const char *url, GtkHTMLStream *handle, EMFormatHTMLDisplay *efh);
static gboolean efhd_object_requested(GtkHTML *html, GtkHTMLEmbedded *eb, EMFormatHTMLDisplay *efh);*/
@@ -1059,10 +1065,35 @@ efhd_attachment_button_show(GtkWidget *w
efhd_attachment_show(NULL, NULL, data);
}
+static void
+efhd_image_resize (EPopup *ep, EPopupItem *item, void *data)
+{
+ struct _attach_puri *info = data;
+
+ if (info->size == -1)
+ return;
+
+ if (info->image) {
+ g_object_unref (gtk_image_get_pixbuf((GtkImage *)info->image));
+
+ if (info->size) {
+ gtk_image_set_from_pixbuf((GtkImage *)info->image, em_icon_stream_get_image(info->puri.cid, -1));
+ } else {
+ gtk_image_set_from_pixbuf((GtkImage *)info->image, em_icon_stream_get_image(info->puri.cid, info->resize_width));
+ }
+
+ info->size = (info->size == 0);
+ gtk_widget_show (info->image);
+ }
+}
+
static EPopupItem efhd_menu_items[] = {
{ E_POPUP_BAR, "05.display", },
{ E_POPUP_ITEM, "05.display.00", N_("_View Inline"), efhd_attachment_show },
{ E_POPUP_ITEM, "05.display.00", N_("_Hide"), efhd_attachment_show },
+ { E_POPUP_ITEM, "05.display.01", N_("_Fit to Width"), efhd_image_resize, NULL, NULL, EM_POPUP_PART_IMAGE },
+ { E_POPUP_ITEM, "05.display.01", N_("Show _Original Size"), efhd_image_resize, NULL, NULL, EM_POPUP_PART_IMAGE },
+
};
static void
@@ -1113,8 +1144,17 @@ efhd_attachment_popup(GtkWidget *w, GdkE
if (info->handle) {
/* show/hide menus, only if we have an inline handler */
menus = g_slist_prepend(menus, &efhd_menu_items[0]);
- item = &efhd_menu_items[info->shown?2:1];
- menus = g_slist_prepend(menus, item);
+ if (info->size == -1) {
+ item = &efhd_menu_items[info->shown?2:1];
+ menus = g_slist_prepend(menus, item);
+ } else if ( info->shown && info->image) {
+ if (info->resized == -1)
+ info->resized = em_icon_stream_is_resized (info->puri.cid, &info->resize_width);
+ if (info->resized) {
+ item = &efhd_menu_items[info->size?4:3];
+ menus = g_slist_prepend(menus, item);
+ }
+ }
}
e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, info);
@@ -1129,6 +1169,16 @@ efhd_attachment_popup(GtkWidget *w, GdkE
}
static gboolean
+efhd_image_popup(GtkWidget *w, GdkEventButton *event, struct _attach_puri *info)
+{
+ if (event && event->button != 3) {
+ return FALSE;
+ }
+ return efhd_attachment_popup(w, event, info);
+
+}
+
+static gboolean
efhd_attachment_popup_menu(GtkWidget *w, struct _attach_puri *info)
{
return efhd_attachment_popup(w, NULL, info);
@@ -1272,7 +1322,7 @@ efhd_attachment_button(EMFormatHTML *efh
char *key;
key = pobject->classid;
- mini = em_icon_stream_get_image(key);
+ mini = em_icon_stream_get_image(key, -1);
if (mini) {
d(printf("got image from cache '%s'\n", key));
gtk_image_set_from_pixbuf((GtkImage *)w, mini);
@@ -1492,6 +1542,119 @@ type_ok:
}
static void
+efhd_image_resize_callback (GtkWidget *w, GtkAllocation *event, struct _attach_puri *info)
+{
+ GdkPixbuf *reduced = NULL;
+ int new_width = ((GtkWidget *)((EMFormatHTML *)info->puri.format)->html)->allocation.width;
+
+ new_width = new_width * 95 / 100;
+
+ /* When fit to screen is selected. Decide whether to show the menu item decided by the width*/
+ if (info->size != 1 ) {
+
+ /* if the available width is > original width, dont show the menu */
+ if (new_width >= gdk_pixbuf_get_width (gtk_image_get_pixbuf((GtkImage *)info->image))) {
+ info->resized = 0;
+ } else {
+ /* Save the width for resizing */
+ info->resized = 1;
+ info->resize_width = new_width;
+ }
+ return;
+ }
+
+ if (info->resized == 1 && new_width == info->resize_width)
+ return;
+
+ reduced = em_icon_stream_get_image (info->puri.cid, new_width);
+
+ if ( reduced ) {
+ if (info->resized == 1)
+ g_object_unref (gtk_image_get_pixbuf ((GtkImage *)info->image));
+ else
+ info->resized = 1;
+ info->resize_width = new_width;
+ gtk_image_set_from_pixbuf ((GtkImage *)info->image, reduced);
+ gtk_widget_show (info->image);
+ } else {
+ /* The availabe size is more than the original image size (shown)*/
+ info->resized = 0;
+ }
+}
+
+static gboolean
+efhd_attachment_image (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject)
+{
+ GtkWidget *box;
+ EMFormatHTMLJob *job;
+ struct _attach_puri *info;
+ GtkTargetEntry drag_types[] = {
+ { NULL, 0, 0 },
+ { "text/uri-list", 0, 1 },
+ };
+ char *simple_type;
+ int width = ((GtkWidget *)efh->html)->allocation.width * 95 / 100;
+
+ info = (struct _attach_puri *) em_format_find_puri((EMFormat *)efh, pobject->classid);
+
+ info->image = gtk_image_new();
+ job = em_format_html_job_new(efh, efhd_write_icon_job, pobject);
+ job->stream = (CamelStream *)em_icon_stream_new((GtkImage *)info->image, pobject->classid);
+ ((EMIconStream *) job->stream)->width = width;
+ ((EMIconStream *) job->stream)->height = -1;
+ info->resize_width=width;
+
+ /*
+ * We dont know, whether the image will be resized or not, till its formed completely
+ * Lets try get it in the next time we deal with the image
+ */
+ info->resized = -1;
+
+ em_format_html_job_queue(efh, job);
+
+ box = gtk_event_box_new ();
+ gtk_container_add ((GtkContainer *) box, info->image);
+ gtk_widget_show_all (box);
+ gtk_container_add ((GtkContainer *) eb, box);
+
+ g_signal_connect (eb, "size_allocate", G_CALLBACK(efhd_image_resize_callback), info);
+
+ simple_type = camel_content_type_simple (((CamelDataWrapper *)pobject->part)->mime_type);
+ camel_strdown(simple_type);
+
+ drag_types[0].target = simple_type;
+ gtk_drag_source_set(box, GDK_BUTTON1_MASK, drag_types, sizeof(drag_types)/sizeof(drag_types[0]), GDK_ACTION_COPY);
+
+ g_signal_connect(box, "drag-data-get", G_CALLBACK(efhd_drag_data_get), pobject);
+ g_signal_connect (box, "drag-data-delete", G_CALLBACK(efhd_drag_data_delete), pobject);
+
+ g_signal_connect(box, "button_press_event", G_CALLBACK(efhd_image_popup), info);
+ g_signal_connect(box, "popup_menu", G_CALLBACK(efhd_attachment_popup_menu), info);
+ return TRUE;
+}
+
+void
+em_format_html_display_handle_image (EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *handle)
+{
+ char *classid;
+ struct _attach_puri *info;
+
+ classid = g_strdup_printf("image%s", ((EMFormat *)efh)->part_id->str);
+ info = (struct _attach_puri *) em_format_add_puri ((EMFormat *)efh, sizeof(*info), classid, part, efhd_attachment_frame);
+ em_format_html_add_pobject(efh, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_image);
+
+ info->handle = handle;
+ info->shown = TRUE;
+ info->snoop_mime_type = ((EMFormat *) efh)->snoop_mime_type;
+
+ /* By default fit to width*/
+ info->size = 1;
+
+ camel_stream_printf(stream, "<td><object classid=\"%s\"></object></td>", classid);
+ g_free (classid);
+}
+
+static void
efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle)
{
char *classid, *text, *html;
@@ -1503,6 +1666,7 @@ efhd_format_attachment(EMFormat *emf, Ca
info->handle = handle;
info->shown = em_format_is_inline(emf, info->puri.part_id, info->puri.part, handle);
info->snoop_mime_type = emf->snoop_mime_type;
+ info->size = -1;
camel_stream_write_string(stream,
EM_FORMAT_HTML_VPAD
Index: em-format-html.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-format-html.c,v
retrieving revision 1.78
diff -u -p -r1.78 em-format-html.c
--- em-format-html.c 19 May 2005 06:06:35 -0000 1.78
+++ em-format-html.c 4 Jul 2005 11:16:08 -0000
@@ -1068,11 +1068,7 @@ efh_write_image(EMFormat *emf, CamelStre
static void
efh_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
{
- EMFormatPURI *puri;
-
- puri = em_format_add_puri((EMFormat *)efh, sizeof(EMFormatPURI), NULL, part, efh_write_image);
- d(printf("adding image '%s'\n", puri->cid));
- camel_stream_printf(stream, "<img hspace=10 vspace=10 src=\"%s\">", puri->cid);
+ em_format_html_display_handle_image (efh, stream, part, info);
}
static EMFormatHandler type_builtin_table[] = {
Index: em-icon-stream.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-icon-stream.c,v
retrieving revision 1.6
diff -u -p -r1.6 em-icon-stream.c
--- em-icon-stream.c 2 Mar 2005 05:23:45 -0000 1.6
+++ em-icon-stream.c 4 Jul 2005 11:16:08 -0000
@@ -157,8 +157,8 @@ static int
emis_sync_close(CamelStream *stream)
{
EMIconStream *emis = (EMIconStream *)stream;
- int width, height, ratio;
- GdkPixbuf *pixbuf, *mini;
+ int width, height;
+ GdkPixbuf *pixbuf, *mini, *orig = NULL;
struct _emis_cache_node *node;
if (emis->loader == NULL)
@@ -176,19 +176,15 @@ emis_sync_close(CamelStream *stream)
width = gdk_pixbuf_get_width(pixbuf);
height = gdk_pixbuf_get_height(pixbuf);
- if (width != emis->width || height != emis->height) {
- if (width >= height) {
- if (width > emis->width) {
- ratio = width / emis->width;
- width = emis->width;
- height /= ratio;
- }
+ if (width > emis->width || (height > emis->height && emis->height != -1)) {
+ if (width >= height || emis->height == -1) {
+ if (emis->height == -1)
+ orig = pixbuf;
+ height = height * emis->width / width;
+ width = emis->width;
} else {
- if (height > emis->height) {
- ratio = height / emis->height;
- height = emis->height;
- width /= ratio;
- }
+ width = width * emis->height / height;
+ height = emis->height;
}
#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
@@ -200,12 +196,24 @@ emis_sync_close(CamelStream *stream)
pixbuf = mini;
} else {
g_object_ref(pixbuf);
- gtk_image_set_from_pixbuf(emis->image, pixbuf);
+ gtk_image_set_from_pixbuf((GtkImage *)emis->image, pixbuf);
+ }
+
+ if (orig) {
+ pixbuf = orig;
+ g_object_ref (pixbuf);
}
+
+ node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, emis->key);
- node = (struct _emis_cache_node *)em_cache_node_new(emis_cache, emis->key);
- node->pixbuf = pixbuf;
- em_cache_add(emis_cache, (EMCacheNode *)node);
+ if (node) {
+ g_object_unref (node->pixbuf);
+ node->pixbuf = pixbuf;
+ } else {
+ node = (struct _emis_cache_node *)em_cache_node_new(emis_cache, emis->key);
+ node->pixbuf = pixbuf;
+ em_cache_add(emis_cache, (EMCacheNode *)node);
+ }
g_object_unref(emis->loader);
emis->loader = NULL;
@@ -237,22 +245,67 @@ em_icon_stream_new(GtkImage *image, cons
}
GdkPixbuf *
-em_icon_stream_get_image(const char *key)
+em_icon_stream_get_image(const char *key, int scale_width)
{
struct _emis_cache_node *node;
GdkPixbuf *pb = NULL;
/* forces the cache to be setup if not */
- em_icon_stream_get_type();
+ em_icon_stream_get_type();
node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, key);
if (node) {
pb = node->pixbuf;
- g_object_ref(pb);
- em_cache_node_unref(emis_cache, (EMCacheNode *)node);
+ if (scale_width == -1) {
+ g_object_ref (pb);
+ } else {
+ int width, height;
+ GdkPixbuf *mini;
+ width = gdk_pixbuf_get_width(pb);
+ height = gdk_pixbuf_get_height(pb);
+
+ if (width > scale_width) {
+ height = height * scale_width / width;
+ width = scale_width;
+#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
+ mini = gnome_thumbnail_scale_down_pixbuf (pb, width, height);
+#else
+ mini = gdk_pixbuf_scale_simple(pb, width, height, GDK_INTERP_BILINEAR);
+#endif
+ pb = mini;
+ } else {
+ /* What is displayed is equivalent to original size */
+ pb = NULL;
+ }
+
+
+ }
}
return pb;
+}
+
+int
+em_icon_stream_is_resized (const char *key, int *scale)
+{
+ struct _emis_cache_node *node;
+
+ /* forces the cache to be setup if not */
+ em_icon_stream_get_type();
+
+ node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, key);
+ if (node) {
+ int width = gdk_pixbuf_get_width (node->pixbuf);
+
+ if (width > *scale) {
+ *scale = width;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return -1;
+
}
void
Index: em-icon-stream.h
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-icon-stream.h,v
retrieving revision 1.4
diff -u -p -r1.4 em-icon-stream.h
--- em-icon-stream.h 16 May 2005 07:53:53 -0000 1.4
+++ em-icon-stream.h 4 Jul 2005 11:16:08 -0000
@@ -55,7 +55,9 @@ typedef struct {
CamelType em_icon_stream_get_type (void);
CamelStream *em_icon_stream_new(GtkImage *image, const char *key);
-struct _GdkPixbuf *em_icon_stream_get_image(const char *key);
+struct _GdkPixbuf *em_icon_stream_get_image(const char *key, int width);
+int em_icon_stream_is_resized(const char *key, int *size);
+
void em_icon_stream_clear_cache(void);
#ifdef __cplusplus
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]