summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2011-03-24 15:37:41 +0100
committerBenjamin Otte <otte@redhat.com>2011-03-24 17:32:36 +0100
commit1722cff86cbc6a2f93696ac9c5331d731e9f91f4 (patch)
tree852a9483ec61bedeb3b20c5e79b6d92605f90aa1
parent61d4dd6223e9249197c16f92413563116ea6be5a (diff)
Split out pixbuf-to-surface conversion code
It will be needed by both the pixbuf loader and the pixbuf library, so we need to be able to inline-include it to avoid cyclic dependencies between the two libs.
-rw-r--r--pig/Makefile.am3
-rw-r--r--pig/pig-pixbuf-picture.c78
-rw-r--r--pig/pig-pixbuf-shared-private.h107
3 files changed, 115 insertions, 73 deletions
diff --git a/pig/Makefile.am b/pig/Makefile.am
index 0ea4843..8027355 100644
--- a/pig/Makefile.am
+++ b/pig/Makefile.am
@@ -62,7 +62,8 @@ nodist_libpig_@PIG_MAJORMINOR@include_HEADERS = \
noinst_HEADERS = \
pig-loader-private.h \
- pig-marshal-private.h
+ pig-marshal-private.h \
+ pig-pixbuf-shared-private.h
EXTRA_DIST = \
pig-marshal.list \
diff --git a/pig/pig-pixbuf-picture.c b/pig/pig-pixbuf-picture.c
index d00bb76..afa6a95 100644
--- a/pig/pig-pixbuf-picture.c
+++ b/pig/pig-pixbuf-picture.c
@@ -24,6 +24,8 @@
#include <cairo-gobject.h>
#include <glib/gi18n.h>
+#include "pig-pixbuf-shared-private.h"
+
struct _PigPixbufPicturePrivate {
GdkPixbuf *pixbuf;
cairo_surface_t *surface;
@@ -235,90 +237,22 @@ cairo_surface_t *
pig_pixbuf_create_surface (const GdkPixbuf *pixbuf)
{
gint width, height;
- guchar *gdk_pixels;
- int gdk_rowstride, n_channels, cairo_stride;
- guchar *cairo_pixels;
cairo_format_t format;
cairo_surface_t *surface;
- static const cairo_user_data_key_t key;
- int j;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
- gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
- gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- n_channels = gdk_pixbuf_get_n_channels (pixbuf);
- if (n_channels == 3)
+ if (gdk_pixbuf_get_n_channels (pixbuf) == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
- cairo_stride = cairo_format_stride_for_width (format, width);
- cairo_pixels = g_malloc (height * cairo_stride);
- surface = cairo_image_surface_create_for_data ((unsigned char *)cairo_pixels,
- format,
- width, height, cairo_stride);
-
- cairo_surface_set_user_data (surface, &key,
- cairo_pixels, (cairo_destroy_func_t)g_free);
+ surface = cairo_image_surface_create (format, width, height);
- for (j = height; j; j--)
- {
- guchar *p = gdk_pixels;
- guchar *q = cairo_pixels;
-
- if (n_channels == 3)
- {
- guchar *end = p + 3 * width;
-
- while (p < end)
- {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- q[0] = p[2];
- q[1] = p[1];
- q[2] = p[0];
-#else
- q[1] = p[0];
- q[2] = p[1];
- q[3] = p[2];
-#endif
- p += 3;
- q += 4;
- }
- }
- else
- {
- guchar *end = p + 4 * width;
- guint t1,t2,t3;
-
-#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
-
- while (p < end)
- {
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- MULT(q[0], p[2], p[3], t1);
- MULT(q[1], p[1], p[3], t2);
- MULT(q[2], p[0], p[3], t3);
- q[3] = p[3];
-#else
- q[0] = p[3];
- MULT(q[1], p[0], p[3], t1);
- MULT(q[2], p[1], p[3], t2);
- MULT(q[3], p[2], p[3], t3);
-#endif
-
- p += 4;
- q += 4;
- }
-
-#undef MULT
- }
-
- gdk_pixels += gdk_rowstride;
- cairo_pixels += cairo_stride;
- }
+ _pig_pixbuf_copy_to_surface (surface, pixbuf,
+ 0, 0, width, height);
return surface;
}
diff --git a/pig/pig-pixbuf-shared-private.h b/pig/pig-pixbuf-shared-private.h
new file mode 100644
index 0000000..6011356
--- /dev/null
+++ b/pig/pig-pixbuf-shared-private.h
@@ -0,0 +1,107 @@
+/* Pig
+ * Copyright (C) 2011 Benjamin Otte <otte@gnome.org>
+ *
+ * This library 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) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PIG_PIXBUF_SHARED_PRIVATE_H__
+#define __PIG_PIXBUF_SHARED_PRIVATE_H__
+
+#include <pig/pig.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+/* This header contains code as inline functions that is used by both
+ * libpig-pixbuf and libpig (in particular: The pixbuf loader).
+ */
+
+G_BEGIN_DECLS
+
+static inline guint8
+_pig_multiply_alpha (guint8 color,
+ guint8 alpha)
+{
+ guint temp = (alpha * color) + 0x80;
+ return (temp + (temp >> 8)) >> 8;
+}
+
+static inline void
+_pig_pixbuf_copy_to_surface (cairo_surface_t *surface,
+ const GdkPixbuf *pixbuf,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ guchar *gdk_pixels, *cairo_pixels;
+ int gdk_stride, n_channels, cairo_stride;
+ int i, j;
+
+ /* spell out the invariants that must hold for this code to work */
+ g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 || cairo_image_surface_get_format (surface) == CAIRO_FORMAT_RGB24);
+ g_assert (cairo_image_surface_get_width (surface) == gdk_pixbuf_get_width (pixbuf));
+ g_assert (cairo_image_surface_get_height (surface) == gdk_pixbuf_get_height (pixbuf));
+ g_assert (x >= 0 && y >= 0);
+ g_assert (x + width <= cairo_image_surface_get_width (surface));
+ g_assert (y + height <= cairo_image_surface_get_height (surface));
+
+ gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
+ gdk_stride = gdk_pixbuf_get_rowstride (pixbuf);
+ n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+ gdk_pixels += x * n_channels + y * gdk_stride;
+
+ cairo_pixels = cairo_image_surface_get_data (surface);
+ cairo_stride = cairo_image_surface_get_stride (surface);
+ cairo_pixels += x * 4 + y * cairo_stride;
+
+ for (j = 0; j < height; j++)
+ {
+ guchar *p = gdk_pixels;
+ guint32 *q = (guint32 *) cairo_pixels;
+
+ if (n_channels == 3)
+ {
+ for (i = 0; i < width; i++)
+ {
+ q[i] = (0xFF << 24) |
+ (p[0] << 16) |
+ (p[1] << 8 ) |
+ p[2];
+
+ p += 3;
+ }
+ }
+ else
+ {
+ for (i = 0; i < width; i++)
+ {
+ q[i] = (p[3] << 24) |
+ (_pig_multiply_alpha (p[0], p[3]) << 16) |
+ (_pig_multiply_alpha (p[1], p[3]) << 8) |
+ _pig_multiply_alpha (p[2], p[3]);
+
+ p += 4;
+ }
+ }
+
+ gdk_pixels += gdk_stride;
+ cairo_pixels += cairo_stride;
+ }
+}
+
+G_END_DECLS
+
+#endif /* __PIG_PIXBUF_SHARED_PRIVATE_H__ */