I've revised my code, adding comments and references. If there is anything
to correct please write it.

Thank you,
Robert Sasu
/* This file is an image processing operation for GEGL
 *
 * GEGL 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 3 of the License, or (at your option) any later version.
 *
 * GEGL 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 GEGL; if not, see <http://www.gnu.org/licenses/>.
 *
 * Algorithm 1997 Eric L. Hernes (er...@rrnet.com)
 * Copyright 2011 Robert Sasu (sasu.rob...@gmail.com)
 */


#include "config.h"
#include <glib/gi18n-lib.h>

#ifdef GEGL_CHANT_PROPERTIES

gegl_chant_double (azimuth, _("Azimuth"), 0.0, 360.0, 30.0,
   _("The value of azimuth"))
gegl_chant_double (elevation, _("Elevation"), 0.0, 180.0, 45.0,
   _("The value of elevation"))
gegl_chant_int    (depth, _("Depth"), 1, 100, 20,
   _("Pixel depth"))
gegl_chant_string (filter, _("Filter"), "emboss",
   _("Optional parameter to override automatic selection of emboss filert. "
     "Choices are emboss, blur-map" ))

#else

#define GEGL_CHANT_TYPE_AREA_FILTER

#define GEGL_CHANT_C_FILE	"emboss.c"
#define RADIUS 3


#include "gegl-chant.h"
#include <math.h>
#include <stdio.h>


/*
 * ANSI C code from the article
 * "Fast Embossing Effects on Raster Image Data"
 * by John Schlag, j...@kerner.com
 * in "Graphics Gems IV", Academic Press, 1994
 *
 *
 * Emboss - shade 24-bit pixels using a single distant light source.
 * Normals are obtained by differentiating a monochrome 'bump' image.
 * The unary case ('texture' == NULL) uses the shading result as output.
 * The binary case multiples the optional 'texture' image by the shade.
 * Images are in row major order with interleaved color components (rgbrgb...).
 * E.g., component c of pixel x,y of 'dst' is dst[3*(y*width + x) + c].
 *
 */


static void 
emboss       (gfloat		  *src_buf,
              const GeglRectangle *src_rect,
              gfloat		  *dst_buf,
              const GeglRectangle *dst_rect,
	      gint		   x,
	      gchar		  *text,
              gint		   floats_per_pixel,
	      gint		   alpha,
	      gdouble		   azimuth,
	      gdouble		   elevation,
	      gint		   depth)
{
  gint	      y;
  gint        offset, verify;
  gint	      bytes;

  gdouble Lx   = cos (azimuth) * cos (elevation);
  gdouble Ly   = sin (azimuth) * cos (elevation);
  gdouble Lz   = sin (elevation) ;
  gdouble Nz2  = 1 / (depth * depth);
  gdouble NzLz = (1 / depth) * Lz;

  bytes = (alpha) ? floats_per_pixel - 1 : floats_per_pixel;

  verify = src_rect->width*src_rect->height*floats_per_pixel;
  offset = x * dst_rect->width * floats_per_pixel;
  for (y = 0; y < dst_rect->width; y++)
	{
	  gint	  i, j, b, count;
	  gfloat  Nx, Ny, NdotL;
          gfloat  shade;
	  gfloat  M[3][3];
          gfloat  a;

	  for (i = 0; i < 3; i++)
            for (j = 0; j < 3; j++)
               M[i][j] = 0.0;	  
          
	  for (b = 0; b < bytes; b++)
           {
           for (i = 0; i < 3; i++)
             for (j = 0; j < 3; j++)
               {
		 count = ((x+i-1)*src_rect->width + (y+j-1))*floats_per_pixel + bytes;

		/*verify each time that we are in the source image*/
                 if (alpha && count >= 0 && count < verify)
                   a = src_buf[count];
                 else
                   a = 1.0;

		/*calculate recalculate the sorrounding pixels by multiplication*/
		/*after we have that we can calculate new value of the pixel*/
		 if ((count - bytes + b) >= 0 && (count - bytes + b) < verify)
                    M[i][j] += a * src_buf[count - bytes + b];	
		}
            }
	
	   Nx = M[0][0] + M[1][0] + M[2][0] - M[0][2] - M[1][2] - M[2][2];
           Ny = M[2][0] + M[2][1] + M[2][2] - M[0][0] - M[0][1] - M[0][2];
	  

	   /*calculating the shading result (same as in gimp)*/
	   if ( Nx == 0 && Ny == 0 )
              shade = Lz;
           else if ( (NdotL = Nx * Lx + Ny * Ly + NzLz) < 0 )
              shade = 0;
           else
              shade = NdotL / sqrt(Nx*Nx + Ny*Ny + Nz2);

	   count = (x*src_rect->width + y)*floats_per_pixel;

	   /*setting the value of the destination buffer*/
  	   if (bytes == 1)
	 	dst_buf[offset++] = shade; 
	   else
	      {
		/*recalculating every byte of a pixel*/
		/*by multiplying with the shading result*/

		for (b = 0; b < bytes; b++)
		   if ((count + b) >= 0 && (count + b) < verify) 
              	      dst_buf[offset++] = (src_buf[count+b] * shade) ;  
		   else
		      dst_buf[offset++] = 1.0;

		/*preserving alpha*/
          	if (alpha && (count + bytes) >= 0 && (count + bytes) < verify) 
            	   dst_buf[offset++] = src_buf[count + bytes];
		else
		   dst_buf[offset++] = 1.0 ; 
              }
	}
}


static void prepare (GeglOperation *operation)
{
  GeglChantO              *o       = GEGL_CHANT_PROPERTIES (operation);
  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
  gchar 		  *type;
  gboolean      	   filter_blurmap;

  op_area->left=op_area->right=op_area->top=op_area->bottom=3;
  
  filter_blurmap = o->filter && !strcmp(o->filter, "blur-map");
  
  type = (filter_blurmap) ? "RGBA float" : "Y float";
  
  gegl_operation_set_format (operation, "output", babl_format (type));
}

static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *result)
{
  GeglChantO              *o       = GEGL_CHANT_PROPERTIES (operation);
  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);

  GeglRectangle  rect;
  gfloat        *src_buf;
  gfloat        *dst_buf;

  gboolean      filter_blurmap;
  gchar	       *type;
  gint          x;
  gint          floats_per_pixel;

  /*blur-map or emboss*/
  filter_blurmap = o->filter && !strcmp(o->filter, "blur-map");
  type = (filter_blurmap) ? "RGBA float" : "Y float";
  floats_per_pixel = (filter_blurmap) ? 4 : 1;

  rect.x      = result->x - op_area->left;
  rect.width  = result->width + op_area->left + op_area->right;
  rect.y      = result->y - op_area->top;
  rect.height = result->height + op_area->top + op_area->bottom;

  src_buf = g_new0 (gfloat, rect.width * rect.height * floats_per_pixel);
  dst_buf = g_new0 (gfloat, rect.width * rect.height * floats_per_pixel);
  
  gegl_buffer_get (input, 1.0, &rect, babl_format (type),
                   src_buf, GEGL_AUTO_ROWSTRIDE);

  /*do for every row*/
  for (x = 0; x < rect.height; x++)
  emboss(src_buf, &rect, dst_buf, &rect, x, type, floats_per_pixel,
	 (filter_blurmap) ? 1 : 0, o->azimuth, o->elevation, o->depth);

  gegl_buffer_set (output, &rect, babl_format (type),
                   dst_buf, GEGL_AUTO_ROWSTRIDE);

  g_free (src_buf);
  g_free (dst_buf);

  return TRUE;
}

static void
gegl_chant_class_init (GeglChantClass *klass)
{
  GeglOperationClass       *operation_class;
  GeglOperationFilterClass *filter_class;

  operation_class = GEGL_OPERATION_CLASS (klass);
  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);


  filter_class->process	   = process;
  operation_class->prepare = prepare;

  operation_class->categories  = "distort";
  operation_class->name        = "gegl:emboss";
  operation_class->description =
        _("Performs embossing on the image.");
}

#endif
_______________________________________________
Gimp-developer mailing list
Gimp-developer@lists.XCF.Berkeley.EDU
https://lists.XCF.Berkeley.EDU/mailman/listinfo/gimp-developer

Reply via email to