You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
6.8 KiB
289 lines
6.8 KiB
12 years ago
|
/* The TdeGtk Theming Engine for Gtk+.
|
||
|
* Copyright (C) 2009 Canonical Ltd
|
||
|
*
|
||
|
* 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., 51 Franklin St, Fifth Floor, Boston,
|
||
|
* MA 02110-1301, USA.
|
||
|
*
|
||
|
* Authored by Mirco "MacSlow" Mueller <mirco.mueller@canonical.com>
|
||
|
*
|
||
|
* Notes:
|
||
|
* based on exponential-blur algorithm by Jani Huhtanen
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/* FIXME: not working yet, unfinished */
|
||
|
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "exponential-blur.h"
|
||
|
|
||
|
static inline void
|
||
|
_blurinner (guchar* pixel,
|
||
|
gint *zR,
|
||
|
gint *zG,
|
||
|
gint *zB,
|
||
|
gint *zA,
|
||
|
gint alpha,
|
||
|
gint aprec,
|
||
|
gint zprec);
|
||
|
|
||
|
static inline void
|
||
|
_blurrow (guchar* pixels,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gint channels,
|
||
|
gint line,
|
||
|
gint alpha,
|
||
|
gint aprec,
|
||
|
gint zprec);
|
||
|
|
||
|
static inline void
|
||
|
_blurcol (guchar* pixels,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gint channels,
|
||
|
gint col,
|
||
|
gint alpha,
|
||
|
gint aprec,
|
||
|
gint zprec);
|
||
|
|
||
|
void
|
||
|
_expblur (guchar* pixels,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gint channels,
|
||
|
gint radius,
|
||
|
gint aprec,
|
||
|
gint zprec);
|
||
|
|
||
|
void
|
||
|
surface_exponential_blur (cairo_surface_t* surface,
|
||
|
guint radius)
|
||
|
{
|
||
|
guchar* pixels;
|
||
|
guint width;
|
||
|
guint height;
|
||
|
cairo_format_t format;
|
||
|
|
||
|
/* sanity checks are done in raico-blur.c */
|
||
|
|
||
|
/* before we mess with the surface execute any pending drawing */
|
||
|
cairo_surface_flush (surface);
|
||
|
|
||
|
pixels = cairo_image_surface_get_data (surface);
|
||
|
width = cairo_image_surface_get_width (surface);
|
||
|
height = cairo_image_surface_get_height (surface);
|
||
|
format = cairo_image_surface_get_format (surface);
|
||
|
|
||
|
switch (format)
|
||
|
{
|
||
|
case CAIRO_FORMAT_ARGB32:
|
||
|
_expblur (pixels, width, height, 4, radius, 16, 7);
|
||
|
break;
|
||
|
case CAIRO_FORMAT_RGB24:
|
||
|
_expblur (pixels, width, height, 3, radius, 16, 7);
|
||
|
break;
|
||
|
case CAIRO_FORMAT_A8:
|
||
|
_expblur (pixels, width, height, 1, radius, 16, 7);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* inform cairo we altered the surfaces contents */
|
||
|
cairo_surface_mark_dirty (surface);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* pixels image-data
|
||
|
* width image-width
|
||
|
* height image-height
|
||
|
* channels image-channels
|
||
|
*
|
||
|
* in-place blur of image 'img' with kernel of approximate radius 'radius'
|
||
|
*
|
||
|
* blurs with two sided exponential impulse response
|
||
|
*
|
||
|
* aprec = precision of alpha parameter in fixed-point format 0.aprec
|
||
|
*
|
||
|
* zprec = precision of state parameters zR,zG,zB and zA in fp format 8.zprec
|
||
|
*/
|
||
|
void
|
||
|
_expblur (guchar* pixels,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gint channels,
|
||
|
gint radius,
|
||
|
gint aprec,
|
||
|
gint zprec)
|
||
|
{
|
||
|
gint alpha;
|
||
|
gint row = 0;
|
||
|
gint col = 0;
|
||
|
|
||
|
if (radius < 1)
|
||
|
return;
|
||
|
|
||
|
/* calculate the alpha such that 90% of
|
||
|
* the kernel is within the radius.
|
||
|
* (Kernel extends to infinity) */
|
||
|
alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
|
||
|
|
||
|
for (; row < height; row++)
|
||
|
_blurrow (pixels,
|
||
|
width,
|
||
|
height,
|
||
|
channels,
|
||
|
row,
|
||
|
alpha,
|
||
|
aprec,
|
||
|
zprec);
|
||
|
|
||
|
for(; col < width; col++)
|
||
|
_blurcol (pixels,
|
||
|
width,
|
||
|
height,
|
||
|
channels,
|
||
|
col,
|
||
|
alpha,
|
||
|
aprec,
|
||
|
zprec);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
_blurinner (guchar* pixel,
|
||
|
gint *zR,
|
||
|
gint *zG,
|
||
|
gint *zB,
|
||
|
gint *zA,
|
||
|
gint alpha,
|
||
|
gint aprec,
|
||
|
gint zprec)
|
||
|
{
|
||
|
gint R;
|
||
|
gint G;
|
||
|
gint B;
|
||
|
guchar A;
|
||
|
|
||
|
R = *pixel;
|
||
|
G = *(pixel + 1);
|
||
|
B = *(pixel + 2);
|
||
|
A = *(pixel + 3);
|
||
|
|
||
|
*zR += (alpha * ((R << zprec) - *zR)) >> aprec;
|
||
|
*zG += (alpha * ((G << zprec) - *zG)) >> aprec;
|
||
|
*zB += (alpha * ((B << zprec) - *zB)) >> aprec;
|
||
|
*zA += (alpha * ((A << zprec) - *zA)) >> aprec;
|
||
|
|
||
|
*pixel = *zR >> zprec;
|
||
|
*(pixel + 1) = *zG >> zprec;
|
||
|
*(pixel + 2) = *zB >> zprec;
|
||
|
*(pixel + 3) = *zA >> zprec;
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
_blurrow (guchar* pixels,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gint channels,
|
||
|
gint line,
|
||
|
gint alpha,
|
||
|
gint aprec,
|
||
|
gint zprec)
|
||
|
{
|
||
|
gint zR;
|
||
|
gint zG;
|
||
|
gint zB;
|
||
|
gint zA;
|
||
|
gint index;
|
||
|
guchar* scanline;
|
||
|
|
||
|
scanline = &(pixels[line * width * channels]);
|
||
|
|
||
|
zR = *scanline << zprec;
|
||
|
zG = *(scanline + 1) << zprec;
|
||
|
zB = *(scanline + 2) << zprec;
|
||
|
zA = *(scanline + 3) << zprec;
|
||
|
|
||
|
for (index = 0; index < width; index ++)
|
||
|
_blurinner (&scanline[index * channels],
|
||
|
&zR,
|
||
|
&zG,
|
||
|
&zB,
|
||
|
&zA,
|
||
|
alpha,
|
||
|
aprec,
|
||
|
zprec);
|
||
|
|
||
|
for (index = width - 2; index >= 0; index--)
|
||
|
_blurinner (&scanline[index * channels],
|
||
|
&zR,
|
||
|
&zG,
|
||
|
&zB,
|
||
|
&zA,
|
||
|
alpha,
|
||
|
aprec,
|
||
|
zprec);
|
||
|
}
|
||
|
|
||
|
static inline void
|
||
|
_blurcol (guchar* pixels,
|
||
|
gint width,
|
||
|
gint height,
|
||
|
gint channels,
|
||
|
gint x,
|
||
|
gint alpha,
|
||
|
gint aprec,
|
||
|
gint zprec)
|
||
|
{
|
||
|
gint zR;
|
||
|
gint zG;
|
||
|
gint zB;
|
||
|
gint zA;
|
||
|
gint index;
|
||
|
guchar* ptr;
|
||
|
|
||
|
ptr = pixels;
|
||
|
|
||
|
ptr += x * channels;
|
||
|
|
||
|
zR = *((guchar*) ptr ) << zprec;
|
||
|
zG = *((guchar*) ptr + 1) << zprec;
|
||
|
zB = *((guchar*) ptr + 2) << zprec;
|
||
|
zA = *((guchar*) ptr + 3) << zprec;
|
||
|
|
||
|
for (index = width; index < (height - 1) * width; index += width)
|
||
|
_blurinner ((guchar*) &ptr[index * channels],
|
||
|
&zR,
|
||
|
&zG,
|
||
|
&zB,
|
||
|
&zA,
|
||
|
alpha,
|
||
|
aprec,
|
||
|
zprec);
|
||
|
|
||
|
for (index = (height - 2) * width; index >= 0; index -= width)
|
||
|
_blurinner ((guchar*) &ptr[index * channels],
|
||
|
&zR,
|
||
|
&zG,
|
||
|
&zB,
|
||
|
&zA,
|
||
|
alpha,
|
||
|
aprec,
|
||
|
zprec);
|
||
|
}
|