[evolution] Prototype an inline image plugin.



commit 6db0e254190a80cf1cccb3629442b78e76c55b36
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Nov 7 22:09:32 2009 -0500

    Prototype an inline image plugin.
    
    Uses GtkImageView to display the image.

 configure.ac                                       |   22 ++
 mail/em-format-html-display.c                      |    2 +
 mail/em-format-html.c                              |    4 +
 plugins/image-inline/Makefile.am                   |   29 +++
 plugins/image-inline/image-inline.c                |  219 ++++++++++++++++++++
 .../image-inline/org-gnome-image-inline.eplug.xml  |  125 +++++++++++
 6 files changed, 401 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 7319281..7115f98 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,6 +62,7 @@ m4_define([hal_minimum_version], [0.5.4])
 m4_define([libnotify_minimum_version], [0.3.0])
 m4_define([gnome_pilot_minimum_version], [2.0.15])
 m4_define([gweather_minimum_version], [2.25.3])
+m4_define([gtkimageview_minimum_version], [1.6])
 
 dnl ******************************
 dnl Compiler Warning Flags
@@ -1542,6 +1543,26 @@ if test "x$enable_weather" = "xyes"; then
 	fi
 fi
 
+dnl *****************************************
+dnl image-inline plugin requires gtkimageview
+dnl *****************************************
+AC_ARG_ENABLE([image-inline],
+	[AS_HELP_STRING([--enable-image-inline],
+	[Enable image-inline plugin @<:@default=yes@:>@])],
+	[enable_image_inline="$enableval"], [enable_image_inline=yes])
+
+if test "x$enable_image_inline" = "xyes"; then
+	PKG_CHECK_MODULES(GTKIMAGEVIEW, gtkimageview >= gtkimageview_minimum_version, have_imageview=yes, have_imageview=no)
+	AC_SUBST(GTKIMAGEVIEW_CFLAGS)
+	AC_SUBST(GTKIMAGEVIEW_LIBS)
+
+	if test "x$have_imageview" = "xyes"; then
+		plugins_standard="$plugins_standard image-inline"
+	else
+		AC_MSG_ERROR([gtkimageview is required for the image-inline plugin.  Use --disable-image-inline to exclude the plugin.])
+	fi
+fi
+
 dnl *********************************
 dnl pst-import plugin requires libpst
 dnl *********************************
@@ -1762,6 +1783,7 @@ plugins/face/Makefile
 plugins/google-account-setup/Makefile
 plugins/groupwise-features/Makefile
 plugins/hula-account-setup/Makefile
+plugins/image-inline/Makefile
 plugins/imap-features/Makefile
 plugins/itip-formatter/Makefile
 plugins/mail-notification/Makefile
diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c
index 6a2f565..de64e2b 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -699,6 +699,7 @@ efhd_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormat
 /* ********************************************************************** */
 
 static EMFormatHandler type_builtin_table[] = {
+#if 0
 	{ (gchar *) "image/gif", (EMFormatFunc)efhd_image },
 	{ (gchar *) "image/jpeg", (EMFormatFunc)efhd_image },
 	{ (gchar *) "image/png", (EMFormatFunc)efhd_image },
@@ -721,6 +722,7 @@ static EMFormatHandler type_builtin_table[] = {
 
 	{ (gchar *) "image/jpg", (EMFormatFunc)efhd_image },
 	{ (gchar *) "image/pjpeg", (EMFormatFunc)efhd_image },
+#endif
 
 	{ (gchar *) "x-evolution/message/prefix", (EMFormatFunc)efhd_message_prefix },
 	{ (gchar *) "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar }
diff --git a/mail/em-format-html.c b/mail/em-format-html.c
index 47213dc..29bb476 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -2105,6 +2105,7 @@ efh_image(EMFormatHTML *efh, CamelStream *stream, CamelMimePart *part, EMFormatH
 }
 
 static EMFormatHandler type_builtin_table[] = {
+#if 0
 	{ (gchar *) "image/gif", (EMFormatFunc)efh_image },
 	{ (gchar *) "image/jpeg", (EMFormatFunc)efh_image },
 	{ (gchar *) "image/png", (EMFormatFunc)efh_image },
@@ -2120,6 +2121,7 @@ static EMFormatHandler type_builtin_table[] = {
 	{ (gchar *) "image/x-portable-graymap", (EMFormatFunc)efh_image },
 	{ (gchar *) "image/x-portable-pixmap", (EMFormatFunc)efh_image },
 	{ (gchar *) "image/x-xpixmap", (EMFormatFunc)efh_image },
+#endif
 	{ (gchar *) "text/enriched", (EMFormatFunc)efh_text_enriched },
 	{ (gchar *) "text/plain", (EMFormatFunc)efh_text_plain },
 	{ (gchar *) "text/html", (EMFormatFunc)efh_text_html },
@@ -2133,8 +2135,10 @@ static EMFormatHandler type_builtin_table[] = {
 	   that some idiot mailer writers out there decide to pull out
 	   of their proverbials at random. */
 
+#if 0
 	{ (gchar *) "image/jpg", (EMFormatFunc)efh_image },
 	{ (gchar *) "image/pjpeg", (EMFormatFunc)efh_image },
+#endif
 
 	/* special internal types */
 
diff --git a/plugins/image-inline/Makefile.am b/plugins/image-inline/Makefile.am
new file mode 100644
index 0000000..5ff7c26
--- /dev/null
+++ b/plugins/image-inline/Makefile.am
@@ -0,0 +1,29 @@
+ EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-image-inline.eplug
+
+plugin_LTLIBRARIES = liborg-gnome-image-inline.la
+
+liborg_gnome_image_inline_la_CPPFLAGS =			\
+	$(AM_CPPFLAGS)					\
+	-I$(top_srcdir)					\
+	$(GNOME_PLATFORM_CFLAGS)			\
+	$(EVOLUTION_MAIL_CFLAGS)			\
+	$(GTKIMAGEVIEW_CFLAGS)
+
+liborg_gnome_image_inline_la_SOURCES = image-inline.c
+
+liborg_gnome_image_inline_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED)
+
+liborg_gnome_image_inline_la_LIBADD =			\
+	$(top_builddir)/mail/libevolution-mail.la	\
+	$(GTKIMAGEVIEW_LIBS)				\
+	$(EVOLUTION_MAIL_LIBS)				\
+	$(GNOME_PLATFORM_LIBS)
+
+EXTRA_DIST = org-gnome-image-inline.eplug.xml
+
+BUILT_SOURCES = $(plugin_DATA)
+CLEANFILES = $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/plugins/image-inline/image-inline.c b/plugins/image-inline/image-inline.c
new file mode 100644
index 0000000..81e5d92
--- /dev/null
+++ b/plugins/image-inline/image-inline.c
@@ -0,0 +1,219 @@
+/*
+ * image-inline.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n-lib.h>
+#include <camel/camel-medium.h>
+#include <camel/camel-mime-part.h>
+#include <camel/camel-stream-mem.h>
+#include <gtkhtml/gtkhtml-embedded.h>
+#include <gtkimageview/gtkimagescrollwin.h>
+
+#include "mail/em-format-hook.h"
+#include "mail/em-format-html.h"
+
+static gint org_gnome_image_inline_classid;
+
+/* Forward Declarations */
+void org_gnome_image_inline_format (gpointer ep, EMFormatHookTarget *target);
+
+typedef struct _ImageInlinePObject ImageInlinePObject;
+
+struct _ImageInlinePObject {
+	EMFormatHTMLPObject object;
+
+	GdkPixbuf *pixbuf;
+	GtkWidget *widget;
+};
+
+static void
+size_allocate_cb (GtkHTMLEmbedded *embedded,
+                  GtkAllocation *event,
+                  ImageInlinePObject *image_object)
+{
+	GtkWidget *widget;
+	gint pixbuf_width;
+	gint pixbuf_height;
+	gint widget_width;
+	gint widget_height;
+	gdouble zoom;
+
+	widget = GTK_WIDGET (image_object->object.format->html);
+	widget_width = widget->allocation.width - 12;
+
+	pixbuf_width = gdk_pixbuf_get_width (image_object->pixbuf);
+	pixbuf_height = gdk_pixbuf_get_height (image_object->pixbuf);
+
+	if (pixbuf_width <= widget_width)
+		zoom = 1.0;
+	else
+		zoom = (gdouble) widget_width / pixbuf_width;
+
+	widget_width = MIN (widget_width, pixbuf_width);
+	widget_height = (gint) (zoom * pixbuf_height);
+
+	gtk_widget_set_size_request (
+		image_object->widget, widget_width, widget_height);
+}
+
+static void
+org_gnome_image_inline_pobject_free (EMFormatHTMLPObject *object)
+{
+	ImageInlinePObject *image_object;
+
+	image_object = (ImageInlinePObject *) object;
+
+	if (image_object->pixbuf != NULL) {
+		g_object_unref (image_object->pixbuf);
+		image_object->pixbuf = NULL;
+	}
+
+	if (image_object->widget != NULL) {
+		g_object_unref (image_object->widget);
+		image_object->widget = NULL;
+	}
+}
+
+static void
+org_gnome_image_inline_decode (ImageInlinePObject *image_object,
+                               CamelMimePart *mime_part)
+{
+	GdkPixbuf *pixbuf;
+	GdkPixbufLoader *loader;
+	CamelContentType *content_type;
+	CamelDataWrapper *data_wrapper;
+	CamelMedium *medium;
+	CamelStream *stream;
+	GByteArray *array;
+	gchar *mime_type;
+	GError *error = NULL;
+
+	array = g_byte_array_new ();
+	medium = CAMEL_MEDIUM (mime_part);
+
+	/* Stream takes ownership of the byte array. */
+	stream = camel_stream_mem_new_with_byte_array (array);
+	data_wrapper = camel_medium_get_content_object (medium);
+	camel_data_wrapper_decode_to_stream (data_wrapper, stream);
+
+	content_type = camel_mime_part_get_content_type (mime_part);
+	mime_type = camel_content_type_simple (content_type);
+	loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error);
+	g_free (mime_type);
+
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+		goto exit;
+	}
+
+	gdk_pixbuf_loader_write (loader, array->data, array->len, &error);
+
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+		goto exit;
+	}
+
+	pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+	if (pixbuf != NULL)
+		image_object->pixbuf = g_object_ref (pixbuf);
+
+	gdk_pixbuf_loader_close (loader, &error);
+
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+		goto exit;
+	}
+
+exit:
+	camel_object_unref (mime_part);
+	camel_object_unref (stream);
+}
+
+static gboolean
+org_gnome_image_inline_embed (EMFormatHTML *format,
+                              GtkHTMLEmbedded *embedded,
+                              EMFormatHTMLPObject *object)
+{
+	ImageInlinePObject *image_object;
+	GtkImageView *image_view;
+	GtkWidget *container;
+	GtkWidget *widget;
+
+	image_object = (ImageInlinePObject *) object;
+
+	if (image_object->pixbuf == NULL)
+		return FALSE;
+
+	container = GTK_WIDGET (embedded);
+
+	widget = gtk_image_view_new ();
+	image_view = GTK_IMAGE_VIEW (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_image_scroll_win_new (image_view);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	image_object->widget = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	gtk_image_view_set_pixbuf (
+		image_view, image_object->pixbuf, TRUE);
+
+	g_signal_connect (
+		embedded, "size-allocate",
+		G_CALLBACK (size_allocate_cb), image_object);
+
+	return TRUE;
+}
+
+void
+org_gnome_image_inline_format (gpointer ep, EMFormatHookTarget *target)
+{
+	ImageInlinePObject *image_object;
+	gchar *classid;
+
+	classid = g_strdup_printf (
+		"org-gnome-image-inline-display-%d",
+		org_gnome_image_inline_classid++);
+
+	image_object = (ImageInlinePObject *)
+		em_format_html_add_pobject (
+			EM_FORMAT_HTML (target->format),
+			sizeof (ImageInlinePObject),
+			classid, target->part,
+			org_gnome_image_inline_embed);
+
+	camel_object_ref (target->part);
+
+	image_object->object.free = org_gnome_image_inline_pobject_free;
+	org_gnome_image_inline_decode (image_object, target->part);
+
+	camel_stream_printf (
+		target->stream, "<object classid=%s></object>", classid);
+
+	g_free (classid);
+}
diff --git a/plugins/image-inline/org-gnome-image-inline.eplug.xml b/plugins/image-inline/org-gnome-image-inline.eplug.xml
new file mode 100644
index 0000000..581d43b
--- /dev/null
+++ b/plugins/image-inline/org-gnome-image-inline.eplug.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+  <e-plugin
+    type="shlib"
+    id="org.gnome.evolution.plugin.imageInline"
+    location="@PLUGINDIR@/liborg-gnome-image-inline SOEXT@"
+    _name="Inline Image">
+
+    <author name="Matthew Barnes" email="mbarnes redhat com"/>
+    <_description>
+      View image attachments directly in mail messages.
+    </_description>
+
+    <!-- Everything GdkPixbuf can handle, we can handle. -->
+
+    <hook class="org.gnome.evolution.mail.format:1.0">
+      <group id="EMFormatHTMLDisplay">
+
+        <!-- Standard Types -->
+
+        <item
+          mime_type="image/bmp"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/gif"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/jp2"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/jpeg"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/jpeg2000"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/jpx"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/png"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/svg"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/tiff"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/vnd.wap.wbmp"
+          format="org_gnome_image_inline_format"/>
+
+        <!-- Experimental Types -->
+
+        <item
+          mime_type="image/x-bmp"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-cmu-raster"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-emf"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-ico"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-icon"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-icns"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-MS-bmp"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-mgx-emf"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-pcx"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-portable-anymap"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-portable-bitmap"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-portable-graymap"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-portable-pixmap"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-sun-raster"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-tga"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-win-bitmap"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-wmf"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-xbitmap"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/x-xpixmap"
+          format="org_gnome_image_inline_format"/>
+
+        <!-- Bogus Types (seen in the wild) -->
+
+        <item
+          mime_type="image/jpg"
+          format="org_gnome_image_inline_format"/>
+        <item
+          mime_type="image/pjpeg"
+          format="org_gnome_image_inline_format"/>
+
+      </group>
+    </hook>
+
+  </e-plugin>
+</e-plugin-list>



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