Re: [evolution-patches] Patch to resize images



Hah, I hope i have worked on most of the comments...

- I have reused em-icon-stream
- Using my own puri
- Fixed Object hierarchy issue
- reduced the complexity of the resize function
- Closed most of the memory leaks

-Srini.


On Fri, 2005-06-24 at 12:33 +0800, Not Zed wrote:
> On Thu, 2005-06-23 at 15:47 +0530, Srinivasa Ragavan wrote:
> > +++ em-image-stream.c   2005-06-23 10:18:05.000000000 +0530
> 
> Instead of copying em-icon-stream and making minor changes, can't you
> just re-use em-icon-stream directly?  All you really need to do is add
> an api to say how big you want the image and whether to keep the
> original sized image around as well.
> 
> >         message-list.h                          \
> > -       mail-vfolder.h
> > +       mail-vfolder.h                          \
> > +       em-image-stream.h                       
> 
> It shouldn't be needed anymore, but for future reference add new files
> to these lists in alphabetic order.
> 
> > +{
> > +       struct _attach_puri *info = data;
> > +       GdkPixbuf *tmp;
> > +       
> > +       if (info->image) {
> > +               /* Swap the alt pixbuf and the current pixbuf of the
> > shown GtkImage */
> > +               tmp = g_object_steal_data (info->image, "alt-image");
> > +               g_object_set_data_full (info->image, "alt-image",
> > gtk_image_get_pixbuf (info->image), g_object_unref);
> > +               gtk_image_set_from_pixbuf (info->image, tmp);
> > +               info->size = ~info->size;
> > +               gtk_widget_show (info->image);
> > +       }
> 
> I'm not sure you want to pass all these pixbufs around.  Once you've
> made the image, and you no longer need to manipulate it, you should be
> using pixmaps.  Anyway, if you change emiconstream slightly all this
> messy stealing stuff can be done away with and you can just get the
> normal or resized image from there.
> 
> > +static void
> > +efhd_image_resize_callback (GtkWidget *w, GtkAllocation *event,
> > struct _attach_puri *info)
> > +{
> 
> This function seems awfully complicated.  All you need to do is: work
> out if you need to resize, what the new size is, calculate the new
> image.  It seems to do all this work 2 or 4 times.
> 
> Also, no need to pass all this g_object_set rubbish around - you already
> have an object under your control, the puri, so put stuff you need in
> there.
> 
> > +       GdkPixbuf *original, *reduced, *shrunk;
> > +       int new_width = ((GtkWidget *)((EMFormatHTML
> > *)info->puri.format)->html)->allocation.width;
> > +       int width, height;
> > +       float ratio;
> > +
> > +       new_width = new_width * 95 / 100;
> > +       
> > +       if (g_object_get_data (info->image, "re-sized")) {
> > +               /* It is a resized image */
> > +               width = g_object_get_data (info->image,
> > "original-width");
> > +               height = g_object_get_data (info->image,
> > "original-height");
> > +               ratio = (float)width / (float) new_width;
> > +               
> > +               if (new_width > width) {
> > +                       /* If the window size go beyond the image
> > size, lets not resize any more */
> > +                       if (info->size) {
> > +                               /* Restore the original image */
> > +                               original = gdk_pixbuf_copy
> > (g_object_get_data (info->image, "alt-image"));
> > +                               gtk_image_set_from_pixbuf
> > (info->image, original);
> > +                       }
> > +                       g_object_set_data (info->image, "re-sized",
> > 0);
> > +                       return;
> > +               }
> > +
> > +               width = new_width;
> > +               height = (int) (height/ratio);
> 
> This calculation is more accurately done as:
>  height = height * new_width / width;
> (although you have to be careful of overflows, or cast to floats).
> 
> > +               /* To keep the quality of image, we always resize from
> > the original image */
> > +               if (info->size) {
> > +                       /* Original is the alt image */
> > +                       original = gdk_pixbuf_copy (g_object_get_data
> > (info->image, "alt-image"));
> > +                       reduced = gtk_image_get_pixbuf (info->image);
> > +               } else {
> > +                       /* The original image is only shown */
> > +                       original = gtk_image_get_pixbuf (info->image);
> > +                       reduced = gdk_pixbuf_copy (g_object_get_data
> > (info->image, "alt-image"));
> > +               }
> > +               
> > +               /* Dont resize, if the reduced size is equal to the
> > available width */
> > +               if (gdk_pixbuf_get_width(reduced) == new_width) {
> > +                       return;
> > +               }
> > +
> > +#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
> > +               shrunk = gnome_thumbnail_scale_down_pixbuf (original,
> > width, height);
> > +#else
> > +               shrunk = gdk_pixbuf_scale_simple(original, width,
> > height, GDK_INTERP_BILINEAR);
> > +#endif         
> > +               
> > +               if (info->size) {
> > +                       gtk_image_set_from_pixbuf (info->image,
> > shrunk);
> > +                       if (info->shown)
> > +                               gtk_widget_show (info->image);
> > +                       else
> > +                               gtk_widget_hide (info->image);
> > +               } else {
> > +                       g_object_set_data_full (info->image,
> > "alt-image", shrunk, g_object_unref);
> > +                       g_object_unref (reduced);
> > +               }
> > +               
> > +       } else { 
> > +               /* Time to shrink the image and store it 
> > +                * It is also possible that the image size is smaller
> > than the window size, when the window
> > +                * is expanded too much.
> > +                */
> > +
> > +               original = gtk_image_get_pixbuf (info->image);
> > +               if (!original)
> > +                       return;
> > +               width = gdk_pixbuf_get_width(original);
> > +               height = gdk_pixbuf_get_height(original);
> > +               if (width <= new_width)
> > +                       return;
> > +                       
> > +               g_object_set_data (info->image, "re-sized", 1);
> > +
> > +               /* Check of it is already an altered image */
> > +               if (!g_object_get_data (info->image, "alt-image"))
> > +                       info->size = 1;
> > +
> > +               if (info->size) { /* Ok. We are resizing for the first
> > time */
> > +                       g_object_set_data_full (info->image,
> > "alt-image", original, g_object_unref);
> > +                       g_object_set_data (info->image,
> > "original-width", width);
> > +                       g_object_set_data (info->image,
> > "original-height", height);
> > +                       reduced = gdk_pixbuf_copy
> > (original);                           
> > +                       shrunk = gdk_pixbuf_scale_simple (reduced,
> > width, height, GDK_INTERP_BILINEAR);
> > +                       gtk_image_set_from_pixbuf (info->image,
> > shrunk);
> > +               }
> > +       }       
> > +
> > +}
> > +
> > +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;
> > +
> > +       /* FIXME: Dirty hack to get the part-id */
> > +       info = em_format_find_puri(efh, g_strdup_printf("attachment%
> > s", &(pobject->classid[5])));
> 
> Umm, memory leak?
> 
> You can't steal someone elses 'pobject' and start using it as your own.
> That is the one for the attachment bar, not for your use as an attachee.
> 
> You need to create your own info and use that.  The same way the
> attachment bar does.
> 
> > +       info->image = gtk_image_new();
> > +       job = em_format_html_job_new(efh, efhd_write_icon_job,
> > pobject);        
> > +       job->stream = (CamelStream *)em_image_stream_new((GtkImage
> > *)info->image, pobject->classid, width);
> > +       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);
> > +
> > +       /* By default fit to width*/
> > +       info->size = 1;
> > +
> > +       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 *info)
> > +{
> > +       char *classid;
> > +       
> > +       classid = g_strdup_printf("image%s", ((EMFormat
> > *)efh)->part_id->str);
> > +       em_format_html_add_pobject(efh, sizeof(EMFormatHTMLPObject),
> > classid, part, efhd_attachment_image);     
> 
> 
> As above, you need to create your own puri (which can contain all the
> fields you're currently object get/setting) and reference that.
> 
> And uh, clean up your memory.  There shouldn't be so many obvious memory
> leaks in patches by now, even preliminary ones like this.
> 
> > +       camel_stream_printf(stream, "<td><object classid=\"%s
> > \"></object></td>", classid);
> >  }
> >  
> >  static void
> > Index: em-format-html-display.h
> > ===================================================================
> > RCS file: /cvs/gnome/evolution/mail/em-format-html-display.h,v
> > retrieving revision 1.5
> > diff -u -r1.5 em-format-html-display.h
> > --- em-format-html-display.h    16 May 2005 07:53:53 -0000      1.5
> > +++ em-format-html-display.h    23 Jun 2005 09:19:20 -0000
> > @@ -58,6 +58,8 @@
> >  void em_format_html_display_zoom_out (EMFormatHTMLDisplay *efhd);
> >  void em_format_html_display_zoom_reset (EMFormatHTMLDisplay *efhd);
> >  
> > +void em_format_html_display_handle_image (EMFormatHTML *efh,
> > CamelStream *stream, CamelMimePart *part, EMFormatHandler *info);
> 
> This is internal DO NOT EXPORT IT.  Its use is already provided by the
> object, subclasses already inherit that behaviour, and parent
> classes ... well, ... uh.
> 
> >  gboolean em_format_html_display_popup_menu (EMFormatHTMLDisplay
> > *efhd);
> >  
> >  /* experimental */
> > Index: em-format-html.c
> > ===================================================================
> > RCS file: /cvs/gnome/evolution/mail/em-format-html.c,v
> > retrieving revision 1.78
> > diff -u -r1.78 em-format-html.c
> > --- em-format-html.c    19 May 2005 06:06:35 -0000      1.78
> > +++ em-format-html.c    23 Jun 2005 09:19:20 -0000
> > @@ -65,6 +65,7 @@
> >  #include "mail-mt.h"
> >  
> >  #include "em-format-html.h"
> > +#include "em-format-html-display.h"
> >  #include "em-html-stream.h"
> >  #include "em-utils.h"
> 
> Oh my god!!!!!  NO!!!!!!!
> 
> You CANNOT include em-format-html-display stuff in em-format-html!  This
> is a sub-class relationship and it is STRICTLY forbidden to break this
> abstraction boundary in the wrong direction.
> 
> I shouldn't need to explain why this is so completely and obviously
> wrong - it is *utterly* *basic* object design.
> 
> >  
> > @@ -1075,22 +1076,23 @@
> >         camel_stream_printf(stream, "<img hspace=10 vspace=10 src=\"%s
> > \">", puri->cid);
> >  }
> >  
> > +
> >  static EMFormatHandler type_builtin_table[] = {
> > -       { "image/gif", (EMFormatFunc)efh_image },
> > -       { "image/jpeg", (EMFormatFunc)efh_image },
> > -       { "image/png", (EMFormatFunc)efh_image },
> > -       { "image/x-png", (EMFormatFunc)efh_image },
> > -       { "image/tiff", (EMFormatFunc)efh_image },
> > -       { "image/x-bmp", (EMFormatFunc)efh_image },
> > -       { "image/bmp", (EMFormatFunc)efh_image },
> > -       { "image/svg", (EMFormatFunc)efh_image },
> > -       { "image/x-cmu-raster", (EMFormatFunc)efh_image },
> > -       { "image/x-ico", (EMFormatFunc)efh_image },
> > -       { "image/x-portable-anymap", (EMFormatFunc)efh_image },
> > -       { "image/x-portable-bitmap", (EMFormatFunc)efh_image },
> > -       { "image/x-portable-graymap", (EMFormatFunc)efh_image },
> > -       { "image/x-portable-pixmap", (EMFormatFunc)efh_image },
> > -       { "image/x-xpixmap", (EMFormatFunc)efh_image },
> > +       { "image/gif",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/jpeg",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/png",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-png",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/tiff",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-bmp",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/bmp",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/svg",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-cmu-raster",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-ico",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-portable-anymap",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-portable-bitmap",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-portable-graymap",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-portable-pixmap",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/x-xpixmap",
> > (EMFormatFunc)em_format_html_display_handle_image },
> >         { "text/enriched", (EMFormatFunc)efh_text_enriched },
> >         { "text/plain", (EMFormatFunc)efh_text_plain },
> >         { "text/html", (EMFormatFunc)efh_text_html },
> > @@ -1104,8 +1106,8 @@
> >            that some idiot mailer writers out there decide to pull out
> >            of their proverbials at random. */
> >  
> > -       { "image/jpg", (EMFormatFunc)efh_image },
> > -       { "image/pjpeg", (EMFormatFunc)efh_image },
> > +       { "image/jpg",
> > (EMFormatFunc)em_format_html_display_handle_image },
> > +       { "image/pjpeg",
> > (EMFormatFunc)em_format_html_display_handle_image },
> >  
> >         /* special internal types */
> 
> Yeah, so tried printing yet?  Fix this, it is bad bad BAD BAD.
> 
> 
> 
> 
> _______________________________________________
> 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	27 Jun 2005 09:53:20 -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>
@@ -50,6 +51,10 @@
 #include <libgnomevfs/gnome-vfs-mime-handlers.h>
 #include <libgnome/gnome-i18n.h>
 
+#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
+#include <libgnomeui/gnome-thumbnail.h>
+#endif
+
 #include <bonobo/bonobo-control-frame.h>
 #include <bonobo/bonobo-stream-memory.h>
 #include <bonobo/bonobo-widget.h>
@@ -119,6 +124,9 @@ struct _attach_puri {
 	GtkHTML *frame;
 	CamelStream *output;
 	unsigned int shown:1;
+	int size;
+	GtkWidget *image;
+	char *key;
 };
 
 static void efhd_iframe_created(GtkHTML *html, GtkHTML *iframe, EMFormatHTMLDisplay *efh);
@@ -1059,10 +1067,29 @@ 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;
+	GdkPixbuf *tmp;
+	
+	if (info->image) {
+		/* Swap the alt pixbuf and the current pixbuf of the shown GtkImage */
+		tmp = em_icon_stream_replace_pixbuf (info->key, gtk_image_get_pixbuf ((GtkImage *)info->image));
+		gtk_image_set_from_pixbuf ((GtkImage *)info->image, tmp);
+		
+		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 +1140,13 @@ 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 && g_object_get_data ((GObject *)info->image, "re-sized")) {
+			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 +1161,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);
@@ -1492,6 +1534,168 @@ type_ok:
 }
 
 static void
+efhd_image_resize_callback (GtkWidget *w, GtkAllocation *event, struct _attach_puri *info)
+{
+	GdkPixbuf *original, *reduced = NULL, *shrunk;
+	int new_width = ((GtkWidget *)((EMFormatHTML *)info->puri.format)->html)->allocation.width;
+	int width, height;
+
+	new_width = new_width * 95 / 100;
+
+	if (info->size == -1)
+		return;
+
+	width = (int) g_object_get_data ((GObject *)info->image, "original-width");
+	height = (int) g_object_get_data ((GObject *)info->image, "original-height");
+
+	if (!g_object_get_data ((GObject *)info->image, "re-sized")) {
+	
+		/* Time to shrink the image and store it 
+		 * It is also possible that the image size is smaller than the window size, when the window
+		 * is expanded too much.
+		 */
+		 if (width <= new_width)
+		 	return;
+
+		original = gtk_image_get_pixbuf ((GtkImage *)info->image);
+		
+		g_object_set_data ((GObject *)info->image, "re-sized", (gpointer) 1);
+
+		reduced = gdk_pixbuf_copy(original);
+
+		em_icon_stream_set_pixbuf (info->key, reduced);
+
+	} else {
+		/* It is a resized image */
+
+		/* To keep the quality of image, we always resize from the original image */
+		if (info->size) {
+			/* Original is the alt image */
+			original = gdk_pixbuf_copy (em_icon_stream_find_pixbuf(info->key));
+			reduced = gtk_image_get_pixbuf ((GtkImage *)info->image);
+		} else {
+			/* The original image is only shown */
+			original = gtk_image_get_pixbuf ((GtkImage *)info->image);
+			reduced = gdk_pixbuf_copy (em_icon_stream_find_pixbuf(info->key));
+		}
+	}
+
+	/* Dont resize, if the reduced size is equal to the available width */
+	if (gdk_pixbuf_get_width(reduced) == new_width)
+		return;
+
+	if (new_width > width) {
+		/* If the window size go beyond the image size, lets not resize any more 
+		 * Just have one image copy and free the other
+		 * Also always free the manipulated pixbuf
+		 */
+		
+		if (info->size) {
+			/* Restore the original image */
+			g_object_unref (original);
+			g_object_unref (gtk_image_get_pixbuf ((GtkImage *)info->image));
+			original = em_icon_stream_find_pixbuf (info->key);
+			gtk_image_set_from_pixbuf ((GtkImage *)info->image, original);				
+		} else {
+			g_object_unref (em_icon_stream_find_pixbuf (info->key));
+			g_object_unref (reduced);
+			em_icon_stream_set_pixbuf (info->key, gtk_image_get_pixbuf ((GtkImage *)info->image));
+		}
+		g_object_set_data ((GObject *)info->image, "re-sized", (gpointer)0);
+		return;
+	}
+
+	height = height * new_width / width;
+	width = new_width;
+
+
+#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H
+	shrunk = gnome_thumbnail_scale_down_pixbuf (original, width, height);
+#else
+	shrunk = gdk_pixbuf_scale_simple(original, width, height, GDK_INTERP_BILINEAR);
+#endif		
+		
+	if (info->size) {
+		gtk_image_set_from_pixbuf ((GtkImage *)info->image, shrunk);
+		if (info->shown)
+			gtk_widget_show (info->image);
+		else
+			gtk_widget_hide (info->image);
+	} else {
+		em_icon_stream_set_pixbuf (info->key, shrunk);
+		g_object_unref (reduced);
+	}
+
+}
+
+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;
+
+	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;
+	/*FIXME: How to free this? */
+	info->key = g_strdup(classid);
+
+	/* 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 +1707,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	27 Jun 2005 09:53:20 -0000
@@ -1068,12 +1068,10 @@ 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);
 }
+
+void efhd_handle_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info);
 
 static EMFormatHandler type_builtin_table[] = {
 	{ "image/gif", (EMFormatFunc)efh_image },
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	27 Jun 2005 09:53:20 -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,19 @@ 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;
+				g_object_set_data ((GObject *)emis->image, "re-sized", (gpointer)1);
+				g_object_set_data ((GObject *)emis->image, "original-width", (gpointer)width);
+				g_object_set_data ((GObject *)emis->image, "original-height", (gpointer)height);
+			}		
+			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 +200,26 @@ 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);
+		g_object_set_data ((GObject *)emis->image, "original-width", (gpointer)width);
+		g_object_set_data ((GObject *)emis->image, "original-height", (gpointer)height);		
 	}
 
-	node = (struct _emis_cache_node *)em_cache_node_new(emis_cache, emis->key);
-	node->pixbuf = pixbuf;
-	em_cache_add(emis_cache, (EMCacheNode *)node);
+	if (orig) {
+		pixbuf = orig;
+		g_object_ref (pixbuf);
+	}
+	
+	node = (struct _emis_cache_node *)em_cache_lookup(emis_cache, emis->key);
+
+	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;
@@ -254,6 +268,56 @@ em_icon_stream_get_image(const char *key
 
 	return pb;
 }
+
+GdkPixbuf *
+em_icon_stream_replace_pixbuf (const char *key, GdkPixbuf * src)
+{
+	GdkPixbuf *alt;
+	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) {
+		alt = node->pixbuf;
+		node->pixbuf = src;
+		return alt;
+	}
+	return NULL;
+	
+}
+
+GdkPixbuf *
+em_icon_stream_find_pixbuf (const char *key)
+{
+	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) 
+		return node->pixbuf;
+		
+	return NULL;
+}
+
+void
+em_icon_stream_set_pixbuf (const char *key, GdkPixbuf *pb)
+{
+	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) 
+		node->pixbuf = pb;
+		
+}
+
+
 
 void
 em_icon_stream_clear_cache(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	27 Jun 2005 09:53:20 -0000
@@ -56,6 +56,10 @@ CamelType    em_icon_stream_get_type (vo
 
 CamelStream *em_icon_stream_new(GtkImage *image, const char *key);
 struct _GdkPixbuf *em_icon_stream_get_image(const char *key);
+GdkPixbuf * em_icon_stream_replace_pixbuf (const char *key, GdkPixbuf * src);
+GdkPixbuf * em_icon_stream_find_pixbuf (const char *key);
+void em_icon_stream_set_pixbuf (const char *key, GdkPixbuf *pb);
+
 void em_icon_stream_clear_cache(void);
 
 #ifdef __cplusplus


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]