[dia] image: remember mime-type from pixbuf loading to use it when saving



commit fd1677b4c8fd2d8bc2ce868c7f8a9e25933a286c
Author: Hans Breuer <hans breuer org>
Date:   Mon Sep 22 22:47:45 2014 +0200

    image: remember mime-type from pixbuf loading to use it when saving
    
    more efficient storage when working with embedded jpeg, for images in dia
    native files as well as with SVG. Also optimize away a string copy of the
    base64 encoding.

 lib/dia_image.c               |   49 ++++++++++++++++++++++++++++++++++++----
 lib/dia_image.h               |    3 ++
 lib/diasvgrenderer.c          |   10 +++-----
 lib/libdia.def                |    1 +
 lib/prop_pixbuf.c             |   38 ++++++++++++++++++++++++++-----
 lib/prop_pixbuf.h             |    2 +-
 plug-ins/python/pydia-image.c |   10 +++-----
 plug-ins/svg/svg-import.c     |    2 +-
 plug-ins/vdx/vdx-export.c     |    2 +-
 9 files changed, 91 insertions(+), 26 deletions(-)
---
diff --git a/lib/dia_image.c b/lib/dia_image.c
index 88598be..9cbddd0 100644
--- a/lib/dia_image.c
+++ b/lib/dia_image.c
@@ -55,6 +55,7 @@ struct _DiaImage {
   GObject parent_instance;
   GdkPixbuf *image;
   gchar *filename;
+  gchar *mime_type; /* optional */
 #ifdef SCALING_CACHE
   GdkPixbuf *scaled; /* a cache of the last scaled version */
   int scaled_width, scaled_height;
@@ -129,10 +130,10 @@ dia_image_finalize(GObject* object)
   image->image = NULL;
   g_free (image->filename);
   image->filename = NULL;
+  g_free (image->mime_type);
+  image->mime_type = NULL;
 }
 
-gboolean _dia_image_initialized = FALSE;
-
 /*!
  * \brief Constructor of a 'broken' image
  * Get the image to put in place of a image that cannot be read.
@@ -188,6 +189,13 @@ dia_image_load(const gchar *filename)
   dia_img = DIA_IMAGE(g_object_new(DIA_TYPE_IMAGE, NULL));
   dia_img->image = image;
   dia_img->filename = g_strdup(filename);
+  /* the pixbuf does not know anymore where it came from */
+  {
+    GdkPixbufFormat *format = gdk_pixbuf_get_file_info (filename, NULL, NULL);
+    gchar **mime_types = gdk_pixbuf_format_get_mime_types (format);
+    dia_img->mime_type = g_strdup (mime_types[0]);
+    g_strfreev (mime_types);
+  }
 #ifdef SCALING_CACHE
   dia_img->scaled = NULL;
 #endif
@@ -206,9 +214,13 @@ DiaImage *
 dia_image_new_from_pixbuf (GdkPixbuf *pixbuf)
 {
   DiaImage *dia_img;
+  const gchar *mime_type;
 
   dia_img = DIA_IMAGE(g_object_new(DIA_TYPE_IMAGE, NULL));
   dia_img->image = g_object_ref (pixbuf);
+  mime_type = g_object_get_data (G_OBJECT (pixbuf), "mime-type");
+  if (mime_type)
+    dia_img->mime_type = g_strdup (mime_type);
   
   return dia_img;
 }
@@ -301,10 +313,10 @@ _guess_format (const gchar *filename)
       }
       g_strfreev (extensions);
     }
-    g_slist_free (formats);
     if (type)
       break;
   }
+  g_slist_free (formats);
   return type;
 }
 
@@ -323,7 +335,7 @@ dia_image_save(DiaImage *image, const gchar *filename)
     GError *error = NULL;
     gchar *type = _guess_format (filename);
     
-    if (type)
+    if (type) /* XXX: consider image->mime_type */
       saved = gdk_pixbuf_save (image->image, filename, type, &error, NULL);
     if (saved) {
       g_free (image->filename);
@@ -382,7 +394,7 @@ dia_image_rowstride(const DiaImage *image)
   g_return_val_if_fail (image != NULL, 0);
   return gdk_pixbuf_get_rowstride(image->image);
 }
-/*! 
+/*!
  * \brief Direct const access to the underlying GdkPixbuf
  * @param image An image object
  * @return The pixbuf
@@ -397,6 +409,33 @@ dia_image_pixbuf (const DiaImage *image)
 }
 
 /*!
+ * \brief Get the mime-type of the image
+ * @param image An image object
+ * @return The mime type from creation or "image/png" as fallback
+ * \memberof _DiaImage
+ */
+const gchar *
+dia_image_get_mime_type (const DiaImage *image)
+{
+  if (image->mime_type)
+    return image->mime_type;
+  return "image/png";
+}
+/*!
+ * \brief Set the mime-type for the image
+ * @param image An image object
+ * @param mime_type A string like "image/jpeg"
+ * @return The mime type from creation or "image/png" as fallback
+ * \memberof _DiaImage
+ */
+void
+dia_image_set_mime_type (DiaImage *image, const gchar *mime_type)
+{
+  g_free (image->mime_type);
+  image->mime_type = g_strdup (mime_type);
+}
+
+/*!
  * \brief Get the raw RGB data from an image.
  * @param image An image object.
  * @return An array of bytes (height*rowstride) containing the RGB data
diff --git a/lib/dia_image.h b/lib/dia_image.h
index b8b06fc..756ed79 100644
--- a/lib/dia_image.h
+++ b/lib/dia_image.h
@@ -54,6 +54,9 @@ guint8 *dia_image_mask_data(const DiaImage *image);
 const guint8 *dia_image_rgba_data(const DiaImage *image);
 const char *dia_image_filename(const DiaImage *image);
 const GdkPixbuf *dia_image_pixbuf (const DiaImage *image);
+const gchar *dia_image_get_mime_type (const DiaImage *image);
+void dia_image_set_mime_type (DiaImage *image, const gchar *mime_type);
+
 GdkPixbuf *dia_image_get_scaled_pixbuf (DiaImage *image, int width, int height);
 
 G_END_DECLS
diff --git a/lib/diasvgrenderer.c b/lib/diasvgrenderer.c
index 920f405..e5c6e07 100644
--- a/lib/diasvgrenderer.c
+++ b/lib/diasvgrenderer.c
@@ -884,15 +884,13 @@ draw_image(DiaRenderer *self,
   /* if the image file location is relative to the SVG file's store 
    * a relative path - if it does not have a path: inline it */
   if (strcmp (dia_image_filename(image), "(null)") == 0) {
-    gchar *b64 = pixbuf_encode_base64 (dia_image_pixbuf (image));
-    gchar *uri;
+    gchar *prefix = g_strdup_printf ("data:%s;base64,", dia_image_get_mime_type (image));
 
-    if (b64)
-      uri = g_strdup_printf ("data:image/png;base64,%s", b64);
-    else
+    uri = pixbuf_encode_base64 (dia_image_pixbuf (image), prefix);
+    if (!uri)
       uri = g_strdup ("(null)");
     xmlSetProp(node, (const xmlChar *)"xlink:href", (xmlChar *) uri);
-    g_free (b64);    
+    g_free (prefix);
   } else if ((uri = dia_relativize_filename (renderer->filename, dia_image_filename(image))) != NULL)
     xmlSetProp(node, (const xmlChar *)"xlink:href", (xmlChar *) uri);
   else if ((uri = g_filename_to_uri(dia_image_filename(image), NULL, NULL)) != NULL)
diff --git a/lib/libdia.def b/lib/libdia.def
index eed7dcd..e56ed53 100644
--- a/lib/libdia.def
+++ b/lib/libdia.def
@@ -280,6 +280,7 @@ EXPORTS
  dia_image_add_ref
  dia_image_filename
  dia_image_get_broken
+ dia_image_get_mime_type
  dia_image_height
  dia_image_load
  dia_image_save
diff --git a/lib/prop_pixbuf.c b/lib/prop_pixbuf.c
index a52d251..6ba29c5 100644
--- a/lib/prop_pixbuf.c
+++ b/lib/prop_pixbuf.c
@@ -69,7 +69,7 @@ pixbufprop_copy(PixbufProperty *src)
 GdkPixbuf *
 pixbuf_decode_base64 (const gchar *b64)
 {
-  /* see lib/prop_pixbuf.c(data_pixbuf) for a very similiar implementation */
+  /* see lib/prop_pixbuf.c(data_pixbuf) for a very similar implementation */
   GdkPixbuf *pixbuf = NULL;
   GdkPixbufLoader *loader;
   GError *error = NULL;
@@ -94,7 +94,18 @@ pixbuf_decode_base64 (const gchar *b64)
       len -= BUF_SIZE;
     } while (len > 0);
     if (gdk_pixbuf_loader_close (loader, error ? NULL : &error)) {
+      GdkPixbufFormat *format = gdk_pixbuf_loader_get_format (loader);
+      gchar  *format_name = gdk_pixbuf_format_get_name (format);
+      gchar **mime_types = gdk_pixbuf_format_get_mime_types (format);
+
+      dia_log_message ("Loaded pixbuf from '%s' with '%s'\n", format_name, mime_types[0]);
       pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
+      /* attach the mime-type to the pixbuf */
+      g_object_set_data_full (G_OBJECT (pixbuf), "mime-type",
+                             g_strdup (mime_types[0]),
+                             (GDestroyNotify)g_free);
+      g_strfreev (mime_types);
+      g_free (format_name);
     } else {
       message_warning (_("Failed to load image form diagram:\n%s"), error->message);
       g_error_free (error);
@@ -184,17 +195,32 @@ _pixbuf_encode (const gchar *buf,
 
   return TRUE;
 }
+
+const gchar *
+_make_pixbuf_type_name (const char *p)
+{
+  if (p && strstr (p, "image/jpeg"))
+    return "jpeg";
+  if (p && strstr (p, "image/jp2"))
+    return "jpeg2000";
+  return "png";
+}
+
 /** Reusable variant of pixbuf to base64 string conversion
  */
 gchar *
-pixbuf_encode_base64 (const GdkPixbuf *pixbuf)
+pixbuf_encode_base64 (const GdkPixbuf *pixbuf, const char *prefix)
 {
   GError *error = NULL;
   EncodeData ed = { 0, };
-
+  const gchar *type = _make_pixbuf_type_name (prefix);
   ed.array = g_byte_array_new ();
 
-  if (!gdk_pixbuf_save_to_callback ((GdkPixbuf *)pixbuf, _pixbuf_encode, &ed, "png", &error, NULL)) {
+  if (prefix) {
+    ed.size = strlen (prefix);
+    g_byte_array_append (ed.array, (guint8 *)prefix, ed.size);
+  }
+  if (!gdk_pixbuf_save_to_callback ((GdkPixbuf *)pixbuf, _pixbuf_encode, &ed, type, &error, NULL)) {
     message_error (_("Saving inline pixbuf failed:\n%s"), error->message);
     g_error_free (error);
     return NULL;
@@ -215,7 +241,7 @@ data_add_pixbuf (AttributeNode attr, GdkPixbuf *pixbuf, DiaContext *ctx)
   AttributeNode comp_attr = composite_add_attribute (composite, "data");
   gchar *b64;
 
-  b64 = pixbuf_encode_base64 (pixbuf);
+  b64 = pixbuf_encode_base64 (pixbuf, NULL);
 
   if (b64)
     (void)xmlNewChild (comp_attr, NULL, (const xmlChar *)"data", (xmlChar *)b64);
@@ -235,7 +261,7 @@ static void
 pixbufprop_get_from_offset(PixbufProperty *prop,
                          void *base, guint offset, guint offset2) 
 {
-  /* before we start editing a simple refernce should be enough */
+  /* before we start editing a simple reference should be enough */
   GdkPixbuf *pixbuf = struct_member(base,offset,GdkPixbuf *);
 
   if (pixbuf)
diff --git a/lib/prop_pixbuf.h b/lib/prop_pixbuf.h
index 242c3cd..37b3e88 100644
--- a/lib/prop_pixbuf.h
+++ b/lib/prop_pixbuf.h
@@ -42,7 +42,7 @@ typedef struct {
 
 void prop_pixbuftypes_register(void);
 
-gchar *pixbuf_encode_base64 (const GdkPixbuf *);
+gchar *pixbuf_encode_base64 (const GdkPixbuf *, const char *prefix);
 GdkPixbuf *pixbuf_decode_base64 (const gchar *b64);
 
 #endif /* PROP_PIXBUF_H */
diff --git a/plug-ins/python/pydia-image.c b/plug-ins/python/pydia-image.c
index 3f77e3a..2f37016 100644
--- a/plug-ins/python/pydia-image.c
+++ b/plug-ins/python/pydia-image.c
@@ -94,12 +94,10 @@ PyDiaImage_GetAttr(PyDiaImage *self, gchar *attr)
     if (g_path_is_absolute(fname)) {
       s = g_filename_to_uri(fname, NULL, &error);
     } else {
-      gchar *b64 = pixbuf_encode_base64 (dia_image_pixbuf (self->image));
-      if (b64)
-       s = g_strdup_printf ("data:image/png;base64,%s", b64);
-      else
-       s = NULL;
-      g_free (b64);
+      gchar *prefix = g_strdup_printf ("data:%s;base64,", dia_image_get_mime_type (self->image));
+
+      s = pixbuf_encode_base64 (dia_image_pixbuf (self->image), prefix);
+      g_free (prefix);
     }
     if (s) {
       PyObject* py_s = PyString_FromString(s);
diff --git a/plug-ins/svg/svg-import.c b/plug-ins/svg/svg-import.c
index dc0cc89..ff2edad 100644
--- a/plug-ins/svg/svg-import.c
+++ b/plug-ins/svg/svg-import.c
@@ -1220,7 +1220,7 @@ read_image_svg(xmlNodePtr node, DiaSvgStyle *parent_style,
 
          new_obj = create_standard_image(x, y, width, height, NULL);
          change = dia_object_set_pixbuf (new_obj, pixbuf);
-         if (change) { /* throw it away, noone needs it here  */
+         if (change) { /* throw it away, no one needs it here  */
            change->free (change);
             g_free (change);
           }
diff --git a/plug-ins/vdx/vdx-export.c b/plug-ins/vdx/vdx-export.c
index 97b64c5..c173ed8 100644
--- a/plug-ins/vdx/vdx-export.c
+++ b/plug-ins/vdx/vdx-export.c
@@ -1382,7 +1382,7 @@ static void draw_image(DiaRenderer *self,
     /* And the data itself */
     memset(&text, 0, sizeof(text));
     text.any.type = vdx_types_text;
-    text.text = pixbuf_encode_base64 (dia_image_pixbuf (image));
+    text.text = pixbuf_encode_base64 (dia_image_pixbuf (image), NULL);
     if (!text.text) return;     /* Problem reading file */
 
     /* Setup children */


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