diff options
author | Benjamin Otte <otte@redhat.com> | 2011-03-24 15:37:41 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2011-03-24 17:32:36 +0100 |
commit | 1722cff86cbc6a2f93696ac9c5331d731e9f91f4 (patch) | |
tree | 852a9483ec61bedeb3b20c5e79b6d92605f90aa1 | |
parent | 61d4dd6223e9249197c16f92413563116ea6be5a (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.am | 3 | ||||
-rw-r--r-- | pig/pig-pixbuf-picture.c | 78 | ||||
-rw-r--r-- | pig/pig-pixbuf-shared-private.h | 107 |
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__ */ |