Re: [evolution-patches] Patch to resize images



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]