[gimp] Bug 722676: Pasting image from clipboard sometimes does not work.



commit 9498cc615d5fd72ce0c7aa881e99209d13ea1e9e
Author: Massimo Valentini <mvalentini src gnome org>
Date:   Thu Feb 20 18:20:17 2014 +0100

    Bug 722676: Pasting image from clipboard sometimes does not work.
    
    Change gimp_pixbuf_create_buffer() to copy the pixels if a linear
    buffer cannot be created. Add functions that convert between
    GimpTempBuf and GdkPixbuf. Fix users of gimp_pixbuf_create_buffer()
    to make the least possible copies. Patch modified by Mitch.

 app/core/gimplayer.c            |   16 +++++--
 app/core/gimppattern-load.c     |   14 +-----
 app/core/gimptempbuf.c          |   96 +++++++++++++++++++++++++++++++++++++++
 app/core/gimptempbuf.h          |    4 ++
 app/core/gimpviewable.c         |   29 +-----------
 app/paint/gimppaintcore-loops.c |    3 +-
 libgimp/gimplayer.c             |    8 ++--
 libgimpcolor/gimppixbuf.c       |   41 +++++++++++++----
 8 files changed, 152 insertions(+), 59 deletions(-)
---
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index ef47e99..6f959a1 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -1290,17 +1290,25 @@ gimp_layer_new_from_pixbuf (GdkPixbuf            *pixbuf,
 {
   GeglBuffer *buffer;
   GimpLayer  *layer;
+  gint        width;
+  gint        height;
 
   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
   g_return_val_if_fail (GIMP_IS_IMAGE (dest_image), NULL);
   g_return_val_if_fail (format != NULL, NULL);
 
-  buffer = gimp_pixbuf_create_buffer (pixbuf);
+  width  = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
 
-  layer = gimp_layer_new_from_buffer (buffer, dest_image, format,
-                                      name, opacity, mode);
+  layer = gimp_layer_new (dest_image, width, height,
+                          format, name, opacity, mode);
 
-  g_object_unref (buffer);
+  buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
+
+  gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
+                   gimp_pixbuf_get_format (pixbuf),
+                   gdk_pixbuf_get_pixels (pixbuf),
+                   gdk_pixbuf_get_rowstride (pixbuf));
 
   return layer;
 }
diff --git a/app/core/gimppattern-load.c b/app/core/gimppattern-load.c
index 45b2be1..f3d8a8a 100644
--- a/app/core/gimppattern-load.c
+++ b/app/core/gimppattern-load.c
@@ -198,8 +198,6 @@ gimp_pattern_load_pixbuf (GimpContext  *context,
 {
   GimpPattern *pattern;
   GdkPixbuf   *pixbuf;
-  GeglBuffer  *src_buffer;
-  GeglBuffer  *dest_buffer;
   gchar       *name;
 
   g_return_val_if_fail (filename != NULL, NULL);
@@ -225,17 +223,7 @@ gimp_pattern_load_pixbuf (GimpContext  *context,
                           NULL);
   g_free (name);
 
-  pattern->mask = gimp_temp_buf_new (gdk_pixbuf_get_width (pixbuf),
-                                     gdk_pixbuf_get_height (pixbuf),
-                                     gimp_pixbuf_get_format (pixbuf));
-
-  src_buffer  = gimp_pixbuf_create_buffer (pixbuf);
-  dest_buffer = gimp_temp_buf_create_buffer (pattern->mask);
-
-  gegl_buffer_copy (src_buffer, NULL, dest_buffer, NULL);
-
-  g_object_unref (src_buffer);
-  g_object_unref (dest_buffer);
+  pattern->mask = gimp_temp_buf_new_from_pixbuf (pixbuf, NULL);
 
   g_object_unref (pixbuf);
 
diff --git a/app/core/gimptempbuf.c b/app/core/gimptempbuf.c
index dfd8c1f..42bae76 100644
--- a/app/core/gimptempbuf.c
+++ b/app/core/gimptempbuf.c
@@ -23,9 +23,12 @@
 #include <gegl.h>
 #include <gegl-utils.h>
 #include <glib/gstdio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include "core-types.h"
 
+#include "libgimpcolor/gimpcolor.h"
+
 #include "gimptempbuf.h"
 
 
@@ -62,6 +65,53 @@ gimp_temp_buf_new (gint        width,
 }
 
 GimpTempBuf *
+gimp_temp_buf_new_from_pixbuf (GdkPixbuf  *pixbuf,
+                               const Babl *f_or_null)
+{
+  const Babl   *format = f_or_null;
+  const Babl   *fish   = NULL;
+  GimpTempBuf  *temp_buf;
+  const guchar *pixels;
+  gint          width;
+  gint          height;
+  gint          rowstride;
+  gint          bpp;
+  guchar       *data;
+  gint          i;
+
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+  if (! format)
+    format = gimp_pixbuf_get_format (pixbuf);
+
+  pixels    = gdk_pixbuf_get_pixels (pixbuf);
+  width     = gdk_pixbuf_get_width (pixbuf);
+  height    = gdk_pixbuf_get_height (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+  temp_buf  = gimp_temp_buf_new (width, height, format);
+  data      = gimp_temp_buf_get_data (temp_buf);
+
+  bpp       = babl_format_get_bytes_per_pixel (format);
+
+  if (gimp_pixbuf_get_format (pixbuf) != format)
+    fish = babl_fish (gimp_pixbuf_get_format (pixbuf), format);
+
+  for (i = 0; i < height; ++i)
+    {
+      if (fish)
+        babl_process (fish, pixels, data, width);
+      else
+        memcpy (data, pixels, width * bpp);
+
+      data   += width * bpp;
+      pixels += rowstride;
+    }
+
+  return temp_buf;
+}
+
+GimpTempBuf *
 gimp_temp_buf_copy (const GimpTempBuf *src)
 {
   GimpTempBuf *dest;
@@ -238,6 +288,52 @@ gimp_temp_buf_create_buffer (GimpTempBuf *temp_buf)
   return buffer;
 }
 
+GdkPixbuf *
+gimp_temp_buf_create_pixbuf (GimpTempBuf *temp_buf)
+{
+  GdkPixbuf    *pixbuf;
+  const Babl   *format;
+  const Babl   *fish = NULL;
+  const guchar *data;
+  gint          width;
+  gint          height;
+  gint          bpp;
+  guchar       *pixels;
+  gint          rowstride;
+  gint          i;
+
+  g_return_val_if_fail (temp_buf != NULL, NULL);
+
+  data      = gimp_temp_buf_get_data (temp_buf);
+  format    = gimp_temp_buf_get_format (temp_buf);
+  width     = gimp_temp_buf_get_width (temp_buf);
+  height    = gimp_temp_buf_get_height (temp_buf);
+  bpp       = babl_format_get_bytes_per_pixel (format);
+
+  pixbuf    = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                              babl_format_has_alpha (format),
+                              8, width, height);
+
+  pixels    = gdk_pixbuf_get_pixels (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+
+  if (format != gimp_pixbuf_get_format (pixbuf))
+    fish = babl_fish (format, gimp_pixbuf_get_format (pixbuf));
+
+  for (i = 0; i <= height; ++i)
+    {
+      if (fish)
+        babl_process (fish, data, pixels, width);
+      else
+        memcpy (pixels, data, width * bpp);
+
+      data   += width * bpp;
+      pixels += rowstride;
+    }
+
+  return pixbuf;
+}
+
 GimpTempBuf *
 gimp_gegl_buffer_get_temp_buf (GeglBuffer *buffer)
 {
diff --git a/app/core/gimptempbuf.h b/app/core/gimptempbuf.h
index 2a6033a..5eb7daa 100644
--- a/app/core/gimptempbuf.h
+++ b/app/core/gimptempbuf.h
@@ -22,6 +22,8 @@
 GimpTempBuf * gimp_temp_buf_new             (gint               width,
                                              gint               height,
                                              const Babl        *fomat) G_GNUC_WARN_UNUSED_RESULT;
+GimpTempBuf * gimp_temp_buf_new_from_pixbuf (GdkPixbuf         *pixbuf,
+                                             const Babl        *f_or_null) G_GNUC_WARN_UNUSED_RESULT;
 GimpTempBuf * gimp_temp_buf_copy            (const GimpTempBuf *src) G_GNUC_WARN_UNUSED_RESULT;
 
 GimpTempBuf * gimp_temp_buf_ref             (GimpTempBuf       *buf);
@@ -46,6 +48,8 @@ guchar      * gimp_temp_buf_data_clear      (GimpTempBuf       *buf);
 gsize         gimp_temp_buf_get_memsize     (const GimpTempBuf *buf);
 
 GeglBuffer  * gimp_temp_buf_create_buffer   (GimpTempBuf       *temp_buf) G_GNUC_WARN_UNUSED_RESULT;
+GdkPixbuf   * gimp_temp_buf_create_pixbuf   (GimpTempBuf       *temp_buf) G_GNUC_WARN_UNUSED_RESULT;
+
 GimpTempBuf * gimp_gegl_buffer_get_temp_buf (GeglBuffer        *buffer);
 
 
diff --git a/app/core/gimpviewable.c b/app/core/gimpviewable.c
index d55271f..edf0f14 100644
--- a/app/core/gimpviewable.c
+++ b/app/core/gimpviewable.c
@@ -388,22 +388,7 @@ gimp_viewable_real_get_new_pixbuf (GimpViewable *viewable,
 
   if (temp_buf)
     {
-      GeglBuffer *src_buffer;
-      GeglBuffer *dest_buffer;
-
-      pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                               babl_format_has_alpha (gimp_temp_buf_get_format (temp_buf)),
-                               8,
-                               gimp_temp_buf_get_width  (temp_buf),
-                               gimp_temp_buf_get_height (temp_buf));
-
-      src_buffer  = gimp_temp_buf_create_buffer (temp_buf);
-      dest_buffer = gimp_pixbuf_create_buffer (pixbuf);
-
-      gegl_buffer_copy (src_buffer, NULL, dest_buffer, NULL);
-
-      g_object_unref (src_buffer);
-      g_object_unref (dest_buffer);
+      pixbuf = gimp_temp_buf_create_pixbuf (temp_buf);
     }
   else if (private->icon_pixbuf)
     {
@@ -930,8 +915,6 @@ gimp_viewable_get_dummy_preview (GimpViewable *viewable,
 {
   GdkPixbuf   *pixbuf;
   GimpTempBuf *buf;
-  GeglBuffer  *src_buffer;
-  GeglBuffer  *dest_buffer;
 
   g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL);
   g_return_val_if_fail (width  > 0, NULL);
@@ -941,15 +924,7 @@ gimp_viewable_get_dummy_preview (GimpViewable *viewable,
   pixbuf = gimp_viewable_get_dummy_pixbuf (viewable, width, height,
                                            babl_format_has_alpha (format));
 
-  buf = gimp_temp_buf_new (width, height, format);
-
-  src_buffer  = gimp_pixbuf_create_buffer (pixbuf);
-  dest_buffer = gimp_temp_buf_create_buffer (buf);
-
-  gegl_buffer_copy (src_buffer, NULL, dest_buffer, NULL);
-
-  g_object_unref (src_buffer);
-  g_object_unref (dest_buffer);
+  buf = gimp_temp_buf_new_from_pixbuf (pixbuf, format);
 
   g_object_unref (pixbuf);
 
diff --git a/app/paint/gimppaintcore-loops.c b/app/paint/gimppaintcore-loops.c
index 816d16d..a270e52 100644
--- a/app/paint/gimppaintcore-loops.c
+++ b/app/paint/gimppaintcore-loops.c
@@ -14,10 +14,11 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
- 
+
 #include "config.h"
 
 #include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include "paint-types.h"
 
diff --git a/libgimp/gimplayer.c b/libgimp/gimplayer.c
index 43c9b8f..e087d0e 100644
--- a/libgimp/gimplayer.c
+++ b/libgimp/gimplayer.c
@@ -150,15 +150,15 @@ gimp_layer_new_from_pixbuf (gint32                image_ID,
 
   if (gimp_plugin_precision_enabled ())
     {
-      GeglBuffer *src_buffer;
       GeglBuffer *dest_buffer;
 
-      src_buffer = gimp_pixbuf_create_buffer (pixbuf);
       dest_buffer = gimp_drawable_get_buffer (layer);
 
-      gegl_buffer_copy (src_buffer, NULL, dest_buffer, NULL);
+      gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
+                       gimp_pixbuf_get_format (pixbuf),
+                       gdk_pixbuf_get_pixels (pixbuf),
+                       gdk_pixbuf_get_rowstride (pixbuf));
 
-      g_object_unref (src_buffer);
       g_object_unref (dest_buffer);
     }
   else
diff --git a/libgimpcolor/gimppixbuf.c b/libgimpcolor/gimppixbuf.c
index 9f5977f..ded08bd 100644
--- a/libgimpcolor/gimppixbuf.c
+++ b/libgimpcolor/gimppixbuf.c
@@ -57,11 +57,14 @@ gimp_pixbuf_get_format (GdkPixbuf *pixbuf)
  * gimp_pixbuf_create_buffer:
  * @pixbuf: a #GdkPixbuf
  *
- * Returns a #GeglBuffer that's backed by the @pixbuf's pixels, without
- * copying them. This function refs the pixbuf, so it will be kept
- * around for as long as te buffer exists.
+ * Returns a #GeglBuffer that's either backed by the @pixbuf's pixels,
+ * or a copy of them. This function tries to not copy the @pixbuf's
+ * pixels. If the pixbuf's rowstride is a multiple of its bpp, a
+ * simple reference to the @pixbuf's pixels is made and @pixbuf will
+ * be kept around for as long as the buffer exists; otherwise the
+ * pixels are copied.
  *
- * Return value: a new #GeglBuffer as a wrapper around @pixbuf.
+ * Return value: a new #GeglBuffer.
  *
  * Since: GIMP 2.10
  **/
@@ -71,17 +74,35 @@ gimp_pixbuf_create_buffer (GdkPixbuf *pixbuf)
   gint width;
   gint height;
   gint rowstride;
+  gint bpp;
 
   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
 
   width     = gdk_pixbuf_get_width (pixbuf);
   height    = gdk_pixbuf_get_height (pixbuf);
   rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  bpp       = gdk_pixbuf_get_n_channels (pixbuf);
 
-  return gegl_buffer_linear_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
-                                           gimp_pixbuf_get_format (pixbuf),
-                                           GEGL_RECTANGLE (0, 0, width, height),
-                                           rowstride,
-                                           (GDestroyNotify) g_object_unref,
-                                           g_object_ref (pixbuf));
+  if ((rowstride % bpp) == 0)
+    {
+      return gegl_buffer_linear_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
+                                               gimp_pixbuf_get_format (pixbuf),
+                                               GEGL_RECTANGLE (0, 0,
+                                                               width, height),
+                                               rowstride,
+                                               (GDestroyNotify) g_object_unref,
+                                               g_object_ref (pixbuf));
+    }
+  else
+    {
+      GeglBuffer *buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                                            width, height),
+                                            gimp_pixbuf_get_format (pixbuf));
+
+      gegl_buffer_set (buffer, NULL, 0, NULL,
+                       gdk_pixbuf_get_pixels (pixbuf),
+                       gdk_pixbuf_get_rowstride (pixbuf));
+
+      return buffer;
+    }
 }


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