|
Packit |
bc1512 |
/* This file is an image processing operation for GEGL
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is free software; you can redistribute it and/or
|
|
Packit |
bc1512 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License as published by the Free Software Foundation; either
|
|
Packit |
bc1512 |
* version 3 of the License, or (at your option) any later version.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit |
bc1512 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
bc1512 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
bc1512 |
* Lesser General Public License for more details.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* Copyright 1997 Eric L. Hernes (erich@rrnet.com)
|
|
Packit |
bc1512 |
* Copyright 2011 Robert Sasu (sasu.robert@gmail.com)
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "config.h"
|
|
Packit |
bc1512 |
#include <glib/gi18n-lib.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_chant_double (azimuth, _("Azimuth"), 0.0, 360.0, 30.0,
|
|
Packit |
bc1512 |
_("The value of azimuth"))
|
|
Packit |
bc1512 |
gegl_chant_double (elevation, _("Elevation"), 0.0, 180.0, 45.0,
|
|
Packit |
bc1512 |
_("The value of elevation"))
|
|
Packit |
bc1512 |
gegl_chant_int (depth, _("Depth"), 1, 100, 20,
|
|
Packit |
bc1512 |
_("Pixel depth"))
|
|
Packit |
bc1512 |
gegl_chant_string (filter, _("Filter"), "emboss",
|
|
Packit |
bc1512 |
_("Optional parameter to override automatic selection "
|
|
Packit |
bc1512 |
"of emboss filter. Choices are emboss, blur-map"))
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#else
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define GEGL_CHANT_TYPE_AREA_FILTER
|
|
Packit |
bc1512 |
#define GEGL_CHANT_C_FILE "emboss.c"
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "gegl-chant.h"
|
|
Packit |
bc1512 |
#include <math.h>
|
|
Packit |
bc1512 |
#include <stdio.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define DEG_TO_RAD(d) (((d) * G_PI) / 180.0)
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*
|
|
Packit |
bc1512 |
* ANSI C code from the article
|
|
Packit |
bc1512 |
* "Fast Embossing Effects on Raster Image Data"
|
|
Packit |
bc1512 |
* by John Schlag, jfs@kerner.com
|
|
Packit |
bc1512 |
* in "Graphics Gems IV", Academic Press, 1994
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* Emboss - shade 24-bit pixels using a single distant light source.
|
|
Packit |
bc1512 |
* Normals are obtained by differentiating a monochrome 'bump' image.
|
|
Packit |
bc1512 |
* The unary case ('texture' == NULL) uses the shading result as output.
|
|
Packit |
bc1512 |
* The binary case multiples the optional 'texture' image by the shade.
|
|
Packit |
bc1512 |
* Images are in row major order with interleaved color components
|
|
Packit |
bc1512 |
* (rgbrgb...). E.g., component c of pixel x,y of 'dst' is
|
|
Packit |
bc1512 |
* dst[3*(y*width + x) + c].
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
emboss (gfloat *src_buf,
|
|
Packit |
bc1512 |
const GeglRectangle *src_rect,
|
|
Packit |
bc1512 |
gfloat *dst_buf,
|
|
Packit |
bc1512 |
const GeglRectangle *dst_rect,
|
|
Packit |
bc1512 |
gint x,
|
|
Packit |
bc1512 |
gchar *text,
|
|
Packit |
bc1512 |
gint floats_per_pixel,
|
|
Packit |
bc1512 |
gint alpha,
|
|
Packit |
bc1512 |
gdouble azimuth,
|
|
Packit |
bc1512 |
gdouble elevation,
|
|
Packit |
bc1512 |
gint width45)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gint y;
|
|
Packit |
bc1512 |
gint offset, verify;
|
|
Packit |
bc1512 |
gint bytes;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gdouble Lx, Ly, Lz;
|
|
Packit |
bc1512 |
gdouble Nz, Nz2, NzLz;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
Lx = cos (azimuth) * cos (elevation);
|
|
Packit |
bc1512 |
Ly = sin (azimuth) * cos (elevation);
|
|
Packit |
bc1512 |
Lz = sin (elevation);
|
|
Packit |
bc1512 |
Nz = 1.0 / width45;
|
|
Packit |
bc1512 |
Nz2 = Nz * Nz;
|
|
Packit |
bc1512 |
NzLz = Nz * Lz;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
bytes = (alpha) ? floats_per_pixel - 1 : floats_per_pixel;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
verify = src_rect->width * src_rect->height * floats_per_pixel;
|
|
Packit |
bc1512 |
offset = x * dst_rect->width * floats_per_pixel;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (y = 0; y < dst_rect->width; y++)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gint i, j, b, count;
|
|
Packit |
bc1512 |
gfloat Nx, Ny, NdotL;
|
|
Packit |
bc1512 |
gfloat shade;
|
|
Packit |
bc1512 |
gfloat M[3][3];
|
|
Packit |
bc1512 |
gfloat a;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (i = 0; i < 3; i++)
|
|
Packit |
bc1512 |
for (j = 0; j < 3; j++)
|
|
Packit |
bc1512 |
M[i][j] = 0.0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (b = 0; b < bytes; b++)
|
|
Packit |
bc1512 |
for (i = 0; i < 3; i++)
|
|
Packit |
bc1512 |
for (j = 0; j < 3; j++)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
count = ((x+i-1)*src_rect->width + (y+j-1))*floats_per_pixel + bytes;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*verify each time that we are in the source image*/
|
|
Packit |
bc1512 |
if (alpha && count >= 0 && count < verify)
|
|
Packit |
bc1512 |
a = src_buf[count];
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
a = 1.0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*calculate recalculate the sorrounding pixels by multiplication*/
|
|
Packit |
bc1512 |
/*after we have that we can calculate new value of the pixel*/
|
|
Packit |
bc1512 |
if ((count - bytes + b) >= 0 && (count - bytes + b) < verify)
|
|
Packit |
bc1512 |
M[i][j] += a * src_buf[count - bytes + b];
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
Nx = M[0][0] + M[1][0] + M[2][0] - M[0][2] - M[1][2] - M[2][2];
|
|
Packit |
bc1512 |
Ny = M[2][0] + M[2][1] + M[2][2] - M[0][0] - M[0][1] - M[0][2];
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*calculating the shading result (same as in gimp)*/
|
|
Packit |
bc1512 |
if ( Nx == 0 && Ny == 0 )
|
|
Packit |
bc1512 |
shade = Lz;
|
|
Packit |
bc1512 |
else if ( (NdotL = Nx * Lx + Ny * Ly + NzLz) < 0 )
|
|
Packit |
bc1512 |
shade = 0;
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
shade = NdotL / sqrt(Nx*Nx + Ny*Ny + Nz2);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
count = (x*src_rect->width + y)*floats_per_pixel;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*setting the value of the destination buffer*/
|
|
Packit |
bc1512 |
if (bytes == 1)
|
|
Packit |
bc1512 |
dst_buf[offset++] = shade;
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/*recalculating every byte of a pixel*/
|
|
Packit |
bc1512 |
/*by multiplying with the shading result*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
for (b = 0; b < bytes; b++)
|
|
Packit |
bc1512 |
if ((count + b) >= 0 && (count + b) < verify)
|
|
Packit |
bc1512 |
dst_buf[offset++] = (src_buf[count+b] * shade) ;
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
dst_buf[offset++] = 1.0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*preserving alpha*/
|
|
Packit |
bc1512 |
if (alpha && (count + bytes) >= 0 && (count + bytes) < verify)
|
|
Packit |
bc1512 |
dst_buf[offset++] = src_buf[count + bytes];
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
dst_buf[offset++] = 1.0 ;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
prepare (GeglOperation *operation)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit |
bc1512 |
GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
op_area->left = op_area->right = op_area->top = op_area->bottom = 3;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (o->filter && !strcmp(o->filter, "blur-map"))
|
|
Packit |
bc1512 |
gegl_operation_set_format (operation, "output",
|
|
Packit |
bc1512 |
babl_format ("RGBA float"));
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
gegl_operation_set_format (operation, "output",
|
|
Packit |
bc1512 |
babl_format ("Y float"));
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static gboolean
|
|
Packit |
bc1512 |
process (GeglOperation *operation,
|
|
Packit |
bc1512 |
GeglBuffer *input,
|
|
Packit |
bc1512 |
GeglBuffer *output,
|
|
Packit |
bc1512 |
const GeglRectangle *result,
|
|
Packit |
bc1512 |
gint level)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit |
bc1512 |
GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
GeglRectangle rect;
|
|
Packit |
bc1512 |
gfloat *src_buf;
|
|
Packit |
bc1512 |
gfloat *dst_buf;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gchar *type;
|
|
Packit |
bc1512 |
gint alpha;
|
|
Packit |
bc1512 |
gint x;
|
|
Packit |
bc1512 |
gint floats_per_pixel;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*blur-map or emboss*/
|
|
Packit |
bc1512 |
if (o->filter && !strcmp (o->filter, "blur-map"))
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
type = "RGBA float";
|
|
Packit |
bc1512 |
floats_per_pixel = 4;
|
|
Packit |
bc1512 |
alpha = 1;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
type = "Y float";
|
|
Packit |
bc1512 |
floats_per_pixel = 1;
|
|
Packit |
bc1512 |
alpha = 0;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
rect.x = result->x - op_area->left;
|
|
Packit |
bc1512 |
rect.width = result->width + op_area->left + op_area->right;
|
|
Packit |
bc1512 |
rect.y = result->y - op_area->top;
|
|
Packit |
bc1512 |
rect.height = result->height + op_area->top + op_area->bottom;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
src_buf = g_new0 (gfloat, rect.width * rect.height * floats_per_pixel);
|
|
Packit |
bc1512 |
dst_buf = g_new0 (gfloat, rect.width * rect.height * floats_per_pixel);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_buffer_get (input, &rect, 1.0, babl_format (type), src_buf,
|
|
Packit |
bc1512 |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/*do for every row*/
|
|
Packit |
bc1512 |
for (x = 0; x < rect.height; x++)
|
|
Packit |
bc1512 |
emboss (src_buf, &rect, dst_buf, &rect, x, type, floats_per_pixel, alpha,
|
|
Packit |
bc1512 |
DEG_TO_RAD (o->azimuth), DEG_TO_RAD (o->elevation), o->depth);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_buffer_set (output, &rect, 0, babl_format (type),
|
|
Packit |
bc1512 |
dst_buf, GEGL_AUTO_ROWSTRIDE);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
g_free (src_buf);
|
|
Packit |
bc1512 |
g_free (dst_buf);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return TRUE;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglOperationClass *operation_class;
|
|
Packit |
bc1512 |
GeglOperationFilterClass *filter_class;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit |
bc1512 |
filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
filter_class->process = process;
|
|
Packit |
bc1512 |
operation_class->prepare = prepare;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_operation_class_set_keys (operation_class,
|
|
Packit |
bc1512 |
"categories" , "distort",
|
|
Packit |
bc1512 |
"name" , "gegl:emboss",
|
|
Packit |
bc1512 |
"description", _("Simulates an image created by embossing"),
|
|
Packit |
bc1512 |
NULL);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#endif
|