Implement premultiplication for CoglBitmap

cogl-bitmap.c cogl-bitmap-pixbuf.c cogl-bitmap-fallback.c cogl-bitmap-private.h:
  Add _cogl_bitmap_can_premult(), _cogl_bitmap_premult() and implement
  a reasonably fast implementation in the "fallback" code.

http://bugzilla.openedhand.com/show_bug.cgi?id=1406

Signed-off-by: Robert Bragg <robert@linux.intel.com>
This commit is contained in:
Owen W. Taylor 2009-05-09 14:39:01 -04:00 committed by Robert Bragg
parent 4dcd5f6134
commit 888a261999
4 changed files with 140 additions and 6 deletions

View File

@ -180,6 +180,41 @@ _cogl_unpremult_alpha_first (const guchar *src, guchar *dst)
dst[3] = ((((gulong) src[3] >> 0) & 0xff) * 255 ) / alpha;
}
/* No division form of floor((c*a + 128)/255) (I first encountered
* this in the RENDER implementation in the X server.) Being exact
* is important for a == 255 - we want to get exactly c.
*/
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 128; d = ((t >> 8) + t) >> 8; } G_STMT_END
inline static void
_cogl_premult_alpha_last (const guchar *src, guchar *dst)
{
guchar alpha = src[3];
/* Using a separate temporary per component has given slightly better
* code generation with GCC in the past; it shouldn't do any worse in
* any case.
*/
guint t1, t2, t3;
MULT(dst[0], src[0], alpha, t1);
MULT(dst[1], src[1], alpha, t2);
MULT(dst[2], src[2], alpha, t3);
dst[3] = alpha;
}
inline static void
_cogl_premult_alpha_first (const guchar *src, guchar *dst)
{
guchar alpha = src[0];
guint t1, t2, t3;
dst[0] = alpha;
MULT(dst[1], src[1], alpha, t1);
MULT(dst[2], src[2], alpha, t2);
MULT(dst[3], src[3], alpha, t3);
}
#undef MULT
gboolean
_cogl_bitmap_fallback_can_convert (CoglPixelFormat src, CoglPixelFormat dst)
{
@ -211,6 +246,12 @@ _cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format)
return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32);
}
gboolean
_cogl_bitmap_fallback_can_premult (CoglPixelFormat format)
{
return ((format & COGL_UNORDERED_MASK) == COGL_PIXEL_FORMAT_32);
}
gboolean
_cogl_bitmap_fallback_convert (const CoglBitmap *bmp,
CoglBitmap *dst_bmp,
@ -358,6 +399,58 @@ _cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp,
return TRUE;
}
gboolean
_cogl_bitmap_fallback_premult (const CoglBitmap *bmp,
CoglBitmap *dst_bmp)
{
guchar *src;
guchar *dst;
gint bpp;
gint x,y;
/* Make sure format supported for un-premultiplication */
if (!_cogl_bitmap_fallback_can_premult (bmp->format))
return FALSE;
bpp = _cogl_get_format_bpp (bmp->format);
/* Initialize destination bitmap */
*dst_bmp = *bmp;
dst_bmp->format = (bmp->format & COGL_UNPREMULT_MASK);
/* Allocate a new buffer to hold converted data */
dst_bmp->data = g_malloc (sizeof(guchar)
* dst_bmp->height
* dst_bmp->rowstride);
for (y = 0; y < bmp->height; y++)
{
src = (guchar*)bmp->data + y * bmp->rowstride;
dst = (guchar*)dst_bmp->data + y * dst_bmp->rowstride;
if (bmp->format & COGL_AFIRST_BIT)
{
for (x = 0; x < bmp->width; x++)
{
_cogl_premult_alpha_first (src, dst);
src += bpp;
dst += bpp;
}
}
else
{
for (x = 0; x < bmp->width; x++)
{
_cogl_premult_alpha_last (src, dst);
src += bpp;
dst += bpp;
}
}
}
return TRUE;
}
gboolean
_cogl_bitmap_fallback_from_file (CoglBitmap *bmp,
const gchar *filename)

View File

@ -49,6 +49,12 @@ _cogl_bitmap_can_unpremult (CoglPixelFormat format)
return FALSE;
}
gboolean
_cogl_bitmap_can_premult (CoglPixelFormat format)
{
return FALSE;
}
gboolean
_cogl_bitmap_convert (const CoglBitmap *bmp,
CoglBitmap *dst_bmp,
@ -64,6 +70,13 @@ _cogl_bitmap_unpremult (const CoglBitmap *bmp,
return FALSE;
}
gboolean
_cogl_bitmap_premult (const CoglBitmap *bmp,
CoglBitmap *dst_bmp)
{
return FALSE;
}
#ifdef USE_QUARTZ
/* lacking GdkPixbuf and other useful GError domains, define one of our own */

View File

@ -52,6 +52,12 @@ _cogl_bitmap_can_unpremult (CoglPixelFormat format);
gboolean
_cogl_bitmap_fallback_can_unpremult (CoglPixelFormat format);
gboolean
_cogl_bitmap_can_premult (CoglPixelFormat format);
gboolean
_cogl_bitmap_fallback_can_premult (CoglPixelFormat format);
gboolean
_cogl_bitmap_convert (const CoglBitmap *bmp,
CoglBitmap *dst_bmp,
@ -69,6 +75,14 @@ gboolean
_cogl_bitmap_fallback_unpremult (const CoglBitmap *bmp,
CoglBitmap *dst_bmp);
gboolean
_cogl_bitmap_premult (const CoglBitmap *bmp,
CoglBitmap *dst_bmp);
gboolean
_cogl_bitmap_fallback_premult (const CoglBitmap *bmp,
CoglBitmap *dst_bmp);
gboolean
_cogl_bitmap_from_file (CoglBitmap *bmp,
const gchar *filename,

View File

@ -87,8 +87,8 @@ _cogl_bitmap_convert_and_premult (const CoglBitmap *bmp,
}
/* Do we need to unpremultiply */
if ((bmp->format & COGL_PREMULT_BIT) == 0 &&
(dst_format & COGL_PREMULT_BIT) > 0)
if ((bmp->format & COGL_PREMULT_BIT) > 0 &&
(dst_format & COGL_PREMULT_BIT) == 0)
{
/* Try unpremultiplying using imaging library */
if (!_cogl_bitmap_unpremult (&new_bmp, &tmp_bmp))
@ -112,14 +112,28 @@ _cogl_bitmap_convert_and_premult (const CoglBitmap *bmp,
}
/* Do we need to premultiply */
if ((bmp->format & COGL_PREMULT_BIT) > 0 &&
(dst_format & COGL_PREMULT_BIT) == 0)
if ((bmp->format & COGL_PREMULT_BIT) == 0 &&
(dst_format & COGL_PREMULT_BIT) > 0)
{
/* FIXME: implement premultiplication */
/* Try premultiplying using imaging library */
if (!_cogl_bitmap_premult (&new_bmp, &tmp_bmp))
{
/* ... or try fallback */
if (!_cogl_bitmap_fallback_premult (&new_bmp, &tmp_bmp))
{
if (new_bmp_owner)
g_free (new_bmp.data);
return FALSE;
}
}
/* Update bitmap with new data */
if (new_bmp_owner)
g_free (new_bmp.data);
return FALSE;
new_bmp = tmp_bmp;
new_bmp_owner = TRUE;
}
/* Output new bitmap info */