Blame operations/workshop/emboss.c

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