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.
This commit is contained in:
Massimo Valentini 2014-02-20 18:20:17 +01:00 committed by Michael Natterer
parent ee772d398f
commit 9498cc615d
8 changed files with 152 additions and 59 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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"
@ -61,6 +64,53 @@ gimp_temp_buf_new (gint width,
return temp;
}
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)
{
@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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

View File

@ -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;
}
}