Logo Search packages:      
Sourcecode: gandalf version File versions

convolve1D.c

/**
 * File:          $RCSfile: convolve1D.c,v $
 * Module:        Image 1D convolution routines
 * Part of:       Gandalf Library
 *
 * Revision:      $Revision: 1.26 $
 * Last edited:   $Date: 2003/03/11 13:08:33 $
 * Author:        $Author: pm $
 * Copyright:     (c) 2000 Imagineer Software Limited
 */

/* 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.1 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <math.h>
#include <gandalf/vision/convolve1D.h>
#include <gandalf/common/misc_error.h>
#include <gandalf/image/image_gl_uchar.h>
#include <gandalf/image/image_gl_ushort.h>
#include <gandalf/image/image_gl_int.h>
#include <gandalf/image/image_gl_uint.h>
#include <gandalf/image/image_gl_float.h>
#include <gandalf/image/image_gl_double.h>
#include <gandalf/image/image_rgb_uchar.h>
#include <gandalf/image/image_rgb_ushort.h>
#include <gandalf/image/image_rgb_int.h>
#include <gandalf/image/image_rgb_uint.h>
#include <gandalf/image/image_rgb_float.h>
#include <gandalf/image/image_rgb_double.h>
#include <gandalf/image/image_rgba_uchar.h>
#include <gandalf/image/image_rgba_ushort.h>
#include <gandalf/image/image_rgba_int.h>
#include <gandalf/image/image_rgba_uint.h>
#include <gandalf/image/image_rgba_float.h>
#include <gandalf/image/image_rgba_double.h>
#include <gandalf/image/image_vfield3D_float.h>
#include <gandalf/image/image_vfield3D_double.h>
#include <gandalf/image/image_vfield3D_int.h>

/**
 * \addtogroup Vision
 * \{
 */

/**
 * \defgroup Convolution Convolution Operations
 * \{
 */

/**
 * \brief 1D convolution function for float arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array in units of floats
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array in units of floats
 * \param mask The convolution mask
 * \param dsize The number of output elements to compute
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c float.
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve1D_i().
 */
Gan_Bool
00077  gan_convolve1D_f ( float *source, int sstride,
                    float *dest,   int dstride,
                    Gan_Mask1D *mask, unsigned int dsize )
{
   int i, j;
   float total;

   gan_err_test_bool ( mask->type == GAN_FLOAT, "gan_convolve1D_d",
                       GAN_ERROR_INCOMPATIBLE, "" );
   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = mask->data.f[0]*source[0];
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j]
                        *(source[j*sstride] + source[-j*sstride]);

            *dest = total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0.0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j-1]
                        *(source[j*sstride] - source[-j*sstride]);

            *dest = total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         source += (mask->size-1)*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0.0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total += mask->data.f[j]*source[-j*sstride];

            *dest = total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_f", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief 1D convolution function for double arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array in units of doubles
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array in units of doubles
 * \param mask The convolution mask
 * \param dsize The number of output elements to compute
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c double.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve1D_i().
 */
Gan_Bool
00165  gan_convolve1D_d ( double *source, int sstride,
                    double *dest,   int dstride,
                    Gan_Mask1D *mask, unsigned int dsize )
{
   int i, j;
   double total;

   gan_err_test_bool ( mask->type == GAN_DOUBLE, "gan_convolve1D_d",
                       GAN_ERROR_INCOMPATIBLE, "" );
   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = mask->data.d[0]*source[0];
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.d[j]
                        *(source[j*sstride] + source[-j*sstride]);

            *dest = total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0.0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.d[j-1]
                        *(source[j*sstride] - source[-j*sstride]);

            *dest = total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         source += (mask->size-1)*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0.0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total += mask->data.d[j]*source[-j*sstride];

            *dest = total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_d", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief 1D convolution function for integer arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array
 * \param mask The convolution mask
 * \param dsize The number of output elements to compute
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c int. There is no checking
 * for overflow.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve1D_i().
 */
Gan_Bool
00254  gan_convolve1D_i ( int *source, int sstride,
                    int *dest,   int dstride,
                    Gan_Mask1D *mask, unsigned int dsize )
{
   int i, j;
   int total;

   gan_err_test_bool ( mask->type == GAN_INT, "gan_convolve1D_i",
                       GAN_ERROR_INCOMPATIBLE, "" );
   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = mask->data.i[0]*source[0];
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.i[j]
                        *(source[j*sstride] + source[-j*sstride]);

            *dest = total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.i[j-1]
                        *(source[j*sstride] - source[-j*sstride]);

            *dest = total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         source += mask->size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total += mask->data.i[j]*source[-j*sstride];

            *dest = total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_i", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief 1D convolution function for integer arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array
 * \param mask The convolution mask
 * \param dsize The number of output elements to compute
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c unsigned \c char.
 * There is no checking for overflow.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve1D_uc().
 */
Gan_Bool
00343  gan_convolve1D_uc ( unsigned char *source, int sstride,
                     unsigned char *dest,   int dstride,
                     Gan_Mask1D *mask, unsigned int dsize )
{
   int i, j;
   float total;

   gan_err_test_bool ( mask->type == GAN_FLOAT, "gan_convolve1D_uc",
                       GAN_ERROR_INCOMPATIBLE, "" );
   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = (mask->data.f[0]*(float)source[0]);
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j]*((float)source[j*sstride] +
                                         (float)source[-j*sstride]);

            *dest = (unsigned char) total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j-1]*((float)source[j*sstride] -
                                           (float)source[-j*sstride]);

            *dest = (unsigned char) total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         source += mask->size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total +=  (mask->data.f[j]*(float)source[-j*sstride]);

            *dest = (unsigned char) total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_uc", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief 1D convolution function for integer arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array
 * \param mask The convolution mask
 * \param dsize The number of output elements to compute
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c unsigned \c short.
 * There is no checking for overflow.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve1D_uc().
 */
Gan_Bool
00432  gan_convolve1D_us ( unsigned short *source, int sstride,
                     unsigned short *dest,   int dstride,
                     Gan_Mask1D *mask, unsigned int dsize )
{
   int i, j;
   float total;

   gan_err_test_bool ( mask->type == GAN_FLOAT, "gan_convolve1D_us",
                       GAN_ERROR_INCOMPATIBLE, "" );
   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = (mask->data.f[0]*(float)source[0]);
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j]*((float)source[j*sstride] +
                                         (float)source[-j*sstride]);

            *dest = (unsigned short) total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j-1]*((float)source[j*sstride] -
                                           (float)source[-j*sstride]);

            *dest = (unsigned short) total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         source += mask->size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total +=  (mask->data.f[j]*(float)source[-j*sstride]);

            *dest = (unsigned short) total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_us", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief 1D convolution function for unsigned integer arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array
 * \param mask The convolution mask
 * \param dsize The number of output elements to compute
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c unsigned \c int.
 * There is no checking for overflow.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve1D_uc().
 */
Gan_Bool
00521  gan_convolve1D_ui ( unsigned int *source, int sstride,
                     unsigned int *dest,   int dstride,
                     Gan_Mask1D *mask, unsigned int dsize )
{
   int i, j;
   double total;

   gan_err_test_bool ( mask->type == GAN_FLOAT, "gan_convolve1D_ui",
                       GAN_ERROR_INCOMPATIBLE, "" );
   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         unsigned half_size = mask->size/2;
         
         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = ((double)mask->data.f[0]*(double)source[0]);
            for ( j = (int)half_size; j > 0; j-- )
               total += (double)mask->data.f[j]*((double)source[j*sstride] +
                                                 (double)source[-j*sstride]);

            *dest = (unsigned int) total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         unsigned half_size = mask->size/2;

         source += half_size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0.0;
            for ( j = (int)half_size; j > 0; j-- )
               total += (double)mask->data.f[j-1]*((double)source[j*sstride] -
                                                   (double)source[-j*sstride]);

            *dest = (unsigned int) total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         source += mask->size*sstride;
         for ( i = (int)dsize-1; i >= 0;
               i--, dest += dstride, source += sstride )
         {
            total = 0.0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total +=  ((double)mask->data.f[j]*(double)source[-j*sstride]);

            *dest = (unsigned int) total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_ui", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/* shift up/down into range 0,..,s-1 */
#define SHIFT_DOWN(v,s) ((v) < (s) ? (v) : ((v)-(s)))
#define SHIFT_UP(v,s) ((v) < 0 ? ((v)+(s)) : (v))

/**
 * \brief Circular 1D convolution function for float arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array in units of floats
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array in units of floats
 * \param mask The convolution mask
 * \param size The number of input/output elements
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c float. The input \a source array
 * is treated as circular, so that no values are lost at the ends.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve_circular1D_i().
 */
Gan_Bool
00614  gan_convolve_circular1D_f ( float *source, int sstride,
                             float *dest,   int dstride,
                             Gan_Mask1D *mask, unsigned int size )
{
   int i, j, isize=(int)size;
   float total;

   gan_err_test_bool ( mask->type == GAN_FLOAT, "gan_convolve1D_d",
                       GAN_ERROR_INCOMPATIBLE, "" );
   if ( size < mask->size )
   {
      gan_err_flush_trace();
      gan_err_register ( "gan_convolve_circular1D_f", GAN_ERROR_INCOMPATIBLE,
                         "" );
      return GAN_FALSE;
   }

   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         int half_size = (int)mask->size/2;

         for ( i = isize-1; i >= 0; i-- )
         {
            total = mask->data.f[0]*source[i*sstride];
            for ( j = half_size; j > 0; j-- )
               total += mask->data.f[j]
                        *(source[SHIFT_DOWN(i+j,isize)*sstride] +
                          source[SHIFT_UP(i-j,isize)*sstride]);

            dest[i*dstride] = total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         int half_size = (int)mask->size/2;

         for ( i = isize-1; i >= 0; i-- )
         {
            total = 0.0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.f[j-1]
                        *(source[SHIFT_DOWN(i+j,isize)*sstride] +
                          source[SHIFT_UP(i-j,isize)*sstride]);

            dest[i*dstride] = total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         for ( i = isize-1; i >= 0; i-- )
         {
            total = 0.0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total += mask->data.f[j]*source[SHIFT_UP(i-j,isize)*sstride];

            dest[i*dstride] = total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_f", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief Circular 1D convolution function for double arrays.
 * \param source The input array to be convolved
 * \param sstride The stride of the source array in units of doubles
 * \param dest The destination array for the convolution
 * \param dstride The stride of the dest array in units of doubles
 * \param mask The convolution mask
 * \param size The number of input/output elements
 *
 * Applies a one-dimensional convolution operation to the given \a source
 * array. Both arrays must be of type \c double. The input \a source array
 * is treated as circular, so that no values are lost at the ends.
 *
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 * \sa gan_convolve_circular1D_i().
 */
Gan_Bool
00707  gan_convolve_circular1D_d ( double *source, int sstride,
                             double *dest,   int dstride,
                             Gan_Mask1D *mask, unsigned int size )
{
   int i, j, isize=(int)size;
   double total;

   gan_err_test_bool ( mask->type == GAN_DOUBLE, "gan_convolve1D_d",
                       GAN_ERROR_INCOMPATIBLE, "" );
   if ( size < mask->size )
   {
      gan_err_flush_trace();
      gan_err_register ( "gan_convolve_circular1D_d", GAN_ERROR_INCOMPATIBLE,
                         "" );
      return GAN_FALSE;
   }

   switch ( mask->format )
   {
      case GAN_MASK1D_SYMMETRIC:
      {
         int half_size = (int)mask->size/2;

         for ( i = isize-1; i >= 0; i-- )
         {
            total = mask->data.d[0]*source[i*sstride];
            for ( j = half_size; j > 0; j-- )
               total += mask->data.d[j]
                        *(source[SHIFT_DOWN(i+j,isize)*sstride] +
                          source[SHIFT_UP(i-j,isize)*sstride]);

            dest[i*dstride] = total;
         }
      }
      break;

      case GAN_MASK1D_ANTISYMMETRIC:
      {
         int half_size = (int)mask->size/2;

         for ( i = isize-1; i >= 0; i-- )
         {
            total = 0.0;
            for ( j = (int)half_size; j > 0; j-- )
               total += mask->data.d[j-1]
                        *(source[SHIFT_DOWN(i+j,isize)*sstride] +
                          source[SHIFT_UP(i-j,isize)*sstride]);

            dest[i*dstride] = total;
         }
      }
      break;
            
      case GAN_MASK1D_GENERIC:
      {
         for ( i = isize-1; i >= 0; i-- )
         {
            total = 0.0;
            for ( j = (int)mask->size-1; j >= 0; j-- )
               total += mask->data.d[j]*source[SHIFT_UP(i-j,isize)*sstride];

            dest[i*dstride] = total;
         }
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_convolve1D_d", GAN_ERROR_ILLEGAL_TYPE, "" );
        break;
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Image *
 image_convolve1Dx_gl_gl ( Gan_Image *image, Gan_Mask1D *mask,
                           Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_GREY_LEVEL_IMAGE,
                      "image_convolve1Dx_gl_gl", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_gl_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "");

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_gl_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_f ( gan_image_get_pixptr_gl_f(image,i,0), 1,
                                    gan_image_get_pixptr_gl_f(dest,i,0),  1,
                                    mask, dest->width ) )
           {
              gan_err_register ( "image_convolve1Dx_gl_gl", GAN_ERROR_FAILURE,
                                 "" );
              return NULL;
           }
                        
        break;

      case GAN_DOUBLE:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_d ( gan_image_get_pixptr_gl_d(image,i,0), 1,
                                    gan_image_get_pixptr_gl_d(dest,i,0),  1,
                                    mask, dest->width ) )
           {
              gan_err_register ( "image_convolve1Dx_gl_gl", GAN_ERROR_FAILURE,
                                 "" );
              return NULL;
           }
                        
        break;

      case GAN_INT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_i ( gan_image_get_pixptr_gl_i(image,i,0), 1,
                                    gan_image_get_pixptr_gl_i(dest,i,0),  1,
                                    mask, dest->width ) )
           {
              gan_err_register ( "image_convolve1Dx_gl_gl", GAN_ERROR_FAILURE,
                                 "" );
              return NULL;
           }

        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_gl_gl", GAN_ERROR_ILLEGAL_TYPE,
                           "" );
        return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dx_v3D_gl ( Gan_Image *image, Gan_ImageChannelType channel,
                            Gan_Mask1D *mask, Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_VECTOR_FIELD_3D,
                      "image_convolve1Dx_v3D_gl", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_v3D_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_v3D_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_INT:
      switch ( channel )
      {
         case GAN_X_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_vfield3D_i(image,i,0)->x, 3,
                       gan_image_get_pixptr_gl_i(dest,i,0),            1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_Y_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_vfield3D_i(image,i,0)->y, 3,
                       gan_image_get_pixptr_gl_i(dest,i,0),            1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_Z_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_vfield3D_i(image,i,0)->z, 3,
                       gan_image_get_pixptr_gl_i(dest,i,0),            1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_v3D_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_FLOAT:
      switch ( channel )
      {
         case GAN_X_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_vfield3D_f(image,i,0)->x, 3,
                       gan_image_get_pixptr_gl_f(dest,i,0),            1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Y_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_vfield3D_f(image,i,0)->y, 3,
                       gan_image_get_pixptr_gl_f(dest,i,0),            1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Z_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_vfield3D_f(image,i,0)->z, 3,
                       gan_image_get_pixptr_gl_f(dest,i,0),            1,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_v3D_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_DOUBLE:
      switch ( channel )
      {
         case GAN_X_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_vfield3D_d(image,i,0)->x, 3,
                       gan_image_get_pixptr_gl_d(dest,i,0),            1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Y_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_vfield3D_d(image,i,0)->y, 3,
                       gan_image_get_pixptr_gl_d(dest,i,0),            1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Z_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_vfield3D_d(image,i,0)->z, 3,
                       gan_image_get_pixptr_gl_d(dest,i,0),            1,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_v3D_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_v3D_gl",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_v3D_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dx_rgb_gl ( Gan_Image *image, Gan_ImageChannelType channel,
                            Gan_Mask1D *mask, Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_IMAGE,
                      "image_convolve1Dx_rgb_gl", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_rgb_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_rgb_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_INT:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_rgb_i(image,i,0)->R, 3,
                       gan_image_get_pixptr_gl_i(dest,i,0),       1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_rgb_i(image,i,0)->G, 3,
                       gan_image_get_pixptr_gl_i(dest,i,0),       1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_BLUE_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_rgb_i(image,i,0)->B, 3,
                       gan_image_get_pixptr_gl_i(dest,i,0),       1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_UINT:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_ui (
                       &gan_image_get_pixptr_rgb_ui(image,i,0)->R, 3,
                       gan_image_get_pixptr_gl_ui(dest,i,0),       1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_ui (
                       &gan_image_get_pixptr_rgb_ui(image,i,0)->G, 3,
                       gan_image_get_pixptr_gl_ui(dest,i,0),       1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_BLUE_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_ui (
                       &gan_image_get_pixptr_rgb_ui(image,i,0)->B, 3,
                       gan_image_get_pixptr_gl_ui(dest,i,0),       1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;
      
      case GAN_FLOAT:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_rgb_f(image,i,0)->R, 3,
                       gan_image_get_pixptr_gl_f(dest,i,0),       1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_rgb_f(image,i,0)->G, 3,
                       gan_image_get_pixptr_gl_f(dest,i,0),       1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_BLUE_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_rgb_f(image,i,0)->B, 3,
                       gan_image_get_pixptr_gl_f(dest,i,0),       1,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_DOUBLE:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_rgb_d(image,i,0)->R, 3,
                       gan_image_get_pixptr_gl_d(dest,i,0),       1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_rgb_d(image,i,0)->G, 3,
                       gan_image_get_pixptr_gl_d(dest,i,0),       1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_BLUE_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_rgb_d(image,i,0)->B, 3,
                       gan_image_get_pixptr_gl_d(dest,i,0),       1,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      
      case GAN_UCHAR:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_uc (
                       &gan_image_get_pixptr_rgb_uc(image,i,0)->R, 3,
                       gan_image_get_pixptr_gl_uc(dest,i,0),       1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_uc (
                       &gan_image_get_pixptr_rgb_uc(image,i,0)->G, 3,
                       gan_image_get_pixptr_gl_uc(dest,i,0),       1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_BLUE_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_uc (
                       &gan_image_get_pixptr_rgb_uc(image,i,0)->B, 3,
                       gan_image_get_pixptr_gl_uc(dest,i,0),       1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_USHORT:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_us (
                       &gan_image_get_pixptr_rgb_us(image,i,0)->R, 3,
                       gan_image_get_pixptr_gl_us(dest,i,0),       1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_us (
                       &gan_image_get_pixptr_rgb_us(image,i,0)->G, 3,
                       gan_image_get_pixptr_gl_us(dest,i,0),       1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_BLUE_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_us (
                       &gan_image_get_pixptr_rgb_us(image,i,0)->B, 3,
                       gan_image_get_pixptr_gl_us(dest,i,0),       1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;
      
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_rgb_gl",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_rgb_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}


static Gan_Image *
 image_convolve1Dx_rgba_gl ( Gan_Image *image, Gan_ImageChannelType channel,
                             Gan_Mask1D *mask, Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "image_convolve1Dx_rgba_gl", GAN_ERROR_INCOMPATIBLE, "");
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_rgba_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "");

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_rgba_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_INT:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_rgba_i(image,i,0)->R, 4,
                       gan_image_get_pixptr_gl_i(dest,i,0),        1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_rgba_i(image,i,0)->G, 4,
                       gan_image_get_pixptr_gl_i(dest,i,0),        1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_BLUE_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_i (
                       &gan_image_get_pixptr_rgba_i(image,i,0)->B, 4,
                       gan_image_get_pixptr_gl_i(dest,i,0),        1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_FLOAT:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_rgba_f(image,i,0)->R, 4,
                       gan_image_get_pixptr_gl_f(dest,i,0),        1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_rgba_f(image,i,0)->G, 4,
                       gan_image_get_pixptr_gl_f(dest,i,0),        1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_BLUE_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_f (
                       &gan_image_get_pixptr_rgba_f(image,i,0)->B, 4,
                       gan_image_get_pixptr_gl_f(dest,i,0),        1,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgba_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_DOUBLE:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_rgba_d(image,i,0)->R, 4,
                       gan_image_get_pixptr_gl_d(dest,i,0),        1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_rgba_d(image,i,0)->G, 4,
                       gan_image_get_pixptr_gl_d(dest,i,0),        1,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_BLUE_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       &gan_image_get_pixptr_rgba_d(image,i,0)->B, 4,
                       gan_image_get_pixptr_gl_d(dest,i,0),        1,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgba_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      
      case GAN_UCHAR:
      switch ( channel )
      {
         case GAN_RED_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_uc (
                       &gan_image_get_pixptr_rgba_uc(image,i,0)->R, 4,
                       gan_image_get_pixptr_gl_uc(dest,i,0),        1,
                       mask, dest->width ) )
                 break;
 
           break;

         case GAN_GREEN_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_uc (
                       &gan_image_get_pixptr_rgba_uc(image,i,0)->G, 4,
                       gan_image_get_pixptr_gl_uc(dest,i,0),        1,
                       mask, dest->width ) )
                break;

         break;

         case GAN_BLUE_CHANNEL:
         for ( i = (int)dest->height-1; i >= 0; i-- )
            if ( !gan_convolve1D_uc (
                       &gan_image_get_pixptr_rgba_uc(image,i,0)->B, 4,
                       gan_image_get_pixptr_gl_uc(dest,i,0),        1,
                       mask, dest->width ) )
               break;

         break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_rgba_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_rgba_gl",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_rgba_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}
   
static Gan_Image *
 image_convolve1Dx_gl_v3D ( Gan_Image *image, Gan_ImageChannelType channel,
                            Gan_Mask1D *mask, Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_GREY_LEVEL_IMAGE,
                      "image_convolve1Dx_gl_v3D", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_gl_v3D",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_VECTOR_FIELD_3D, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_VECTOR_FIELD_3D,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_gl_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_DOUBLE:
      switch ( channel )
      {
         case GAN_X_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       gan_image_get_pixptr_gl_d(image,i,0),           1,
                       &gan_image_get_pixptr_vfield3D_d(image,i,0)->x, 3,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Y_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       gan_image_get_pixptr_gl_d(image,i,0),           1,
                       &gan_image_get_pixptr_vfield3D_d(image,i,0)->y, 3,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Z_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_d (
                       gan_image_get_pixptr_gl_d(image,i,0),           1,
                       &gan_image_get_pixptr_vfield3D_d(image,i,0)->z, 3,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_gl_v3D",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_INT:
      switch ( channel )
      {
         case GAN_X_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       gan_image_get_pixptr_gl_i(image,i,0),           1,
                       &gan_image_get_pixptr_vfield3D_i(image,i,0)->x, 3,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Y_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       gan_image_get_pixptr_gl_i(image,i,0),           1,
                       &gan_image_get_pixptr_vfield3D_i(image,i,0)->y, 3,
                       mask, dest->width ) )
                 break;

           break;

         case GAN_Z_CHANNEL:
           for ( i = (int)dest->height-1; i >= 0; i-- )
              if ( !gan_convolve1D_i (
                       gan_image_get_pixptr_gl_i(image,i,0),           1,
                       &gan_image_get_pixptr_vfield3D_i(image,i,0)->z, 3,
                       mask, dest->width ) )
                 break;

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dx_gl_v3D",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_gl_v3D",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_gl_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dx_v3D_v3D ( Gan_Image *image, Gan_Mask1D *mask,
                             Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_VECTOR_FIELD_3D,
                      "image_convolve1Dx_v3D_v3D", GAN_ERROR_INCOMPATIBLE, "");
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_v3D_v3D",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_VECTOR_FIELD_3D, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_VECTOR_FIELD_3D,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_v3D_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_DOUBLE:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_d (
                     &gan_image_get_pixptr_vfield3D_d(image,i,0)->x, 3,
                     &gan_image_get_pixptr_vfield3D_d(dest,i,0)->x,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_vfield3D_d(image,i,0)->y, 3,
                     &gan_image_get_pixptr_vfield3D_d(dest,i,0)->y,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_vfield3D_d(image,i,0)->z, 3,
                     &gan_image_get_pixptr_vfield3D_d(dest,i,0)->z,  3,
                     mask, dest->width ) )
              break;

        break;

      case GAN_INT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_i (
                     &gan_image_get_pixptr_vfield3D_i(image,i,0)->x, 3,
                     &gan_image_get_pixptr_vfield3D_i(dest,i,0)->x,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_vfield3D_i(image,i,0)->y, 3,
                     &gan_image_get_pixptr_vfield3D_i(dest,i,0)->y,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_vfield3D_i(image,i,0)->z, 3,
                     &gan_image_get_pixptr_vfield3D_i(dest,i,0)->z,  3,
                     mask, dest->width ) )
              break;

        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_v3D_v3D",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_v3D_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dx_rgb_rgb ( Gan_Image *image, Gan_Mask1D *mask,
                             Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_IMAGE,
                      "image_convolve1Dx_rgb_rgb", GAN_ERROR_INCOMPATIBLE, "");
   gan_err_test_ptr ( image->width >= mask->size, "image_convolve1Dx_rgb_rgb",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( image->format, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              image->format,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_rgb_rgb", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_DOUBLE:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_d (
                     &gan_image_get_pixptr_rgb_d(image,i,0)->R, 3,
                     &gan_image_get_pixptr_rgb_d(dest,i,0)->R,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_rgb_d(image,i,0)->G, 3,
                     &gan_image_get_pixptr_rgb_d(dest,i,0)->G,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_rgb_d(image,i,0)->B, 3,
                     &gan_image_get_pixptr_rgb_d(dest,i,0)->B,  3,
                     mask, dest->width ) )
              break;

        break;

      case GAN_FLOAT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_f (
                     &gan_image_get_pixptr_rgb_f(image,i,0)->R, 3,
                     &gan_image_get_pixptr_rgb_f(dest,i,0)->R,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_f (
                     &gan_image_get_pixptr_rgb_f(image,i,0)->G, 3,
                     &gan_image_get_pixptr_rgb_f(dest,i,0)->G,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_f (
                     &gan_image_get_pixptr_rgb_f(image,i,0)->B, 3,
                     &gan_image_get_pixptr_rgb_f(dest,i,0)->B,  3,
                     mask, dest->width ) )
              break;

        break;
        
      case GAN_INT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_i (
                     &gan_image_get_pixptr_rgb_i(image,i,0)->R, 3,
                     &gan_image_get_pixptr_rgb_i(dest,i,0)->R,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_rgb_i(image,i,0)->G, 3,
                     &gan_image_get_pixptr_rgb_i(dest,i,0)->G,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_rgb_i(image,i,0)->B, 3,
                     &gan_image_get_pixptr_rgb_i(dest,i,0)->B,  3,
                     mask, dest->width ) )
              break;

        break;
        
      case GAN_UINT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_ui (
                     &gan_image_get_pixptr_rgb_ui(image,i,0)->R, 3,
                     &gan_image_get_pixptr_rgb_ui(dest,i,0)->R,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_ui (
                     &gan_image_get_pixptr_rgb_ui(image,i,0)->G, 3,
                     &gan_image_get_pixptr_rgb_ui(dest,i,0)->G,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_ui (
                     &gan_image_get_pixptr_rgb_ui(image,i,0)->B, 3,
                     &gan_image_get_pixptr_rgb_ui(dest,i,0)->B,  3,
                     mask, dest->width ) )
              break;

        break;
        
      case GAN_UCHAR:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_uc (
                     &gan_image_get_pixptr_rgb_uc(image,i,0)->R, 3,
                     &gan_image_get_pixptr_rgb_uc(dest,i,0)->R,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_uc (
                     &gan_image_get_pixptr_rgb_uc(image,i,0)->G, 3,
                     &gan_image_get_pixptr_rgb_uc(dest,i,0)->G,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_uc (
                     &gan_image_get_pixptr_rgb_uc(image,i,0)->B, 3,
                     &gan_image_get_pixptr_rgb_uc(dest,i,0)->B,  3,
                     mask, dest->width ) )
              break;

        break;

      case GAN_USHORT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_us (
                     &gan_image_get_pixptr_rgb_us(image,i,0)->R, 3,
                     &gan_image_get_pixptr_rgb_us(dest,i,0)->R,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_us (
                     &gan_image_get_pixptr_rgb_us(image,i,0)->G, 3,
                     &gan_image_get_pixptr_rgb_us(dest,i,0)->G,  3,
                     mask, dest->width ) ||
                !gan_convolve1D_us (
                     &gan_image_get_pixptr_rgb_us(image,i,0)->B, 3,
                     &gan_image_get_pixptr_rgb_us(dest,i,0)->B,  3,
                     mask, dest->width ) )
              break;

        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_rgb_rgb",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_rgb_rgb", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dx_rgba_rgba ( Gan_Image *image, Gan_Mask1D *mask,
                               Gan_Image *dest )
{
   int i;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "image_convolve1Dx_rgba_rgba", GAN_ERROR_INCOMPATIBLE,
                      "" );
   gan_err_test_ptr ( image->width >= mask->size,"image_convolve1Dx_rgba_rgba",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( image->format, image->type,
                               image->height, image->width-mask->size+1 );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              image->format,
                                              image->type,
                                              image->height,
                                              image->width-mask->size+1 );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dx_rgba_rgba", GAN_ERROR_FAILURE, "");
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_DOUBLE:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_d (
                     &gan_image_get_pixptr_rgba_d(image,i,0)->R, 4,
                     &gan_image_get_pixptr_rgba_d(dest,i,0)->R,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_rgba_d(image,i,0)->G, 4,
                     &gan_image_get_pixptr_rgba_d(dest,i,0)->G,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_rgba_d(image,i,0)->B, 4,
                     &gan_image_get_pixptr_rgba_d(dest,i,0)->B,  4,
                     mask, dest->width ) )
              break;

        break;

      case GAN_FLOAT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_f (
                     &gan_image_get_pixptr_rgba_f(image,i,0)->R, 4,
                     &gan_image_get_pixptr_rgba_f(dest,i,0)->R,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_f (
                     &gan_image_get_pixptr_rgba_f(image,i,0)->G, 4,
                     &gan_image_get_pixptr_rgba_f(dest,i,0)->G,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_f (
                     &gan_image_get_pixptr_rgba_f(image,i,0)->B, 4,
                     &gan_image_get_pixptr_rgba_f(dest,i,0)->B,  4,
                     mask, dest->width ) )
              break;

        break;        
        
      case GAN_INT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_i (
                     &gan_image_get_pixptr_rgba_i(image,i,0)->R, 4,
                     &gan_image_get_pixptr_rgba_i(dest,i,0)->R,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_rgba_i(image,i,0)->G, 4,
                     &gan_image_get_pixptr_rgba_i(dest,i,0)->G,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_rgba_i(image,i,0)->B, 4,
                     &gan_image_get_pixptr_rgba_i(dest,i,0)->B,  4,
                     mask, dest->width ) )
              break;

        break;

      case GAN_UINT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_ui (
                     &gan_image_get_pixptr_rgba_ui(image,i,0)->R, 4,
                     &gan_image_get_pixptr_rgba_ui(dest,i,0)->R,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_ui (
                     &gan_image_get_pixptr_rgba_ui(image,i,0)->G, 4,
                     &gan_image_get_pixptr_rgba_ui(dest,i,0)->G,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_ui (
                     &gan_image_get_pixptr_rgba_ui(image,i,0)->B, 4,
                     &gan_image_get_pixptr_rgba_ui(dest,i,0)->B,  4,
                     mask, dest->width ) )
              break;

        break;
        
      case GAN_UCHAR:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_uc (
                     &gan_image_get_pixptr_rgba_uc(image,i,0)->R, 4,
                     &gan_image_get_pixptr_rgba_uc(dest,i,0)->R,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_uc (
                     &gan_image_get_pixptr_rgba_uc(image,i,0)->G, 4,
                     &gan_image_get_pixptr_rgba_uc(dest,i,0)->G,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_uc (
                     &gan_image_get_pixptr_rgba_uc(image,i,0)->B, 4,
                     &gan_image_get_pixptr_rgba_uc(dest,i,0)->B,  4,
                     mask, dest->width ) )
              break;

        break;

      case GAN_USHORT:
        for ( i = (int)dest->height-1; i >= 0; i-- )
           if ( !gan_convolve1D_us (
                     &gan_image_get_pixptr_rgba_us(image,i,0)->R, 4,
                     &gan_image_get_pixptr_rgba_us(dest,i,0)->R,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_us (
                     &gan_image_get_pixptr_rgba_us(image,i,0)->G, 4,
                     &gan_image_get_pixptr_rgba_us(dest,i,0)->G,  4,
                     mask, dest->width ) ||
                !gan_convolve1D_us (
                     &gan_image_get_pixptr_rgba_us(image,i,0)->B, 4,
                     &gan_image_get_pixptr_rgba_us(dest,i,0)->B,  4,
                     mask, dest->width ) )
              break;

        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dx_rgba_rgba",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( i >= 0 )
   {
      gan_err_register ( "image_convolve1Dx_rgba_rgba", GAN_ERROR_FAILURE, "");
      return NULL;
   }

   /* success */
   return dest;
}

/**
 * \brief Convolves an image in the x-direction.
 * \param image The input image
 * \param channel Colour channel to be convolved where applicable
 * \param mask The image convolution mask
 * \param dest The destination image for the convolution operation
 *
 * Applies a one-dimensional convolution operation to the given image in the
 * x-direction. When the image contains colour or vector field data,
 * a particular colour channel/vector field element can be specified by the
 * channel argument, which should otherwise be passed as #GAN_ALL_CHANNELS.
 * There is no checking for overflow of integer values.
 *
 * Macro call to gan_image_convolve1Dx_q().
 * \return Non-\c NULL on successfully returning the destination image \a dest,
 * \c NULL on failure.
 * \sa gan_image_convolve1Dx_q, gan_gauss_mask_new().
 */
Gan_Image *
02106  gan_image_convolve1Dx_q ( Gan_Image *image, Gan_ImageChannelType channel,
                           Gan_Mask1D *mask, Gan_Image *dest )
{
   switch ( image->format )
   {
      case GAN_GREY_LEVEL_IMAGE:
      switch ( channel )
      {
         case GAN_INTENSITY_CHANNEL:
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dx_gl_gl ( image, mask, dest );
           break;

         case GAN_X_CHANNEL:
         case GAN_Y_CHANNEL:
         case GAN_Z_CHANNEL:
           dest = image_convolve1Dx_gl_v3D ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dx_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_VECTOR_FIELD_3D:
      switch ( channel )
      {
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dx_v3D_v3D ( image, mask, dest );
           break;

         case GAN_X_CHANNEL:
         case GAN_Y_CHANNEL:
         case GAN_Z_CHANNEL:
           dest = image_convolve1Dx_v3D_gl ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dx_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;
      
      case GAN_RGB_COLOUR_IMAGE:
      switch ( channel )
      {
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dx_rgb_rgb ( image, mask, dest );
           break;

         case GAN_RED_CHANNEL:
         case GAN_GREEN_CHANNEL:
         case GAN_BLUE_CHANNEL:
           dest = image_convolve1Dx_rgb_gl ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dx_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_RGB_COLOUR_ALPHA_IMAGE:
      switch ( channel )
      {
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dx_rgba_rgba ( image, mask, dest );
           break;

         case GAN_RED_CHANNEL:
         case GAN_GREEN_CHANNEL:
         case GAN_BLUE_CHANNEL:
         case GAN_ALPHA_CHANNEL:  
           dest = image_convolve1Dx_rgba_gl ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dx_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;
      
      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_image_convolve1Dx_q", GAN_ERROR_ILLEGAL_TYPE,
                           "" );
        return NULL;
   }

   if ( dest == NULL )
   {
      gan_err_register ( "gan_image_convolve1Dx_q", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}


static Gan_Image *
 image_convolve1Dy_gl_gl ( Gan_Image *image, Gan_Mask1D *mask,
                           Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_GREY_LEVEL_IMAGE,
                      "image_convolve1Dy_gl_gl", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_gl_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_gl_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_gl_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_f ( gan_image_get_pixptr_gl_f(image,0,j),
                                    image->stride/sizeof(float),
                                    gan_image_get_pixptr_gl_f(dest,0,j),
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_gl_gl", GAN_ERROR_FAILURE,
                                 "" );
              return NULL;
           }
                        
        break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_gl_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_d ( gan_image_get_pixptr_gl_d(image,0,j),
                                    image->stride/sizeof(double),
                                    gan_image_get_pixptr_gl_d(dest,0,j),
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_gl_gl", GAN_ERROR_FAILURE,
                                 "" );
              return NULL;
           }
                        
        break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_gl_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_i ( gan_image_get_pixptr_gl_i(image,0,j),
                                    image->stride/sizeof(int),
                                    gan_image_get_pixptr_gl_i(dest,0,j),
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_gl_gl", GAN_ERROR_FAILURE,
                                 "" );
              return NULL;
           }

        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_gl_gl", GAN_ERROR_ILLEGAL_TYPE,
                           "" );
        return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dy_v3D_gl ( Gan_Image *image, Gan_ImageChannelType channel,
                            Gan_Mask1D *mask, Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_VECTOR_FIELD_3D,
                      "image_convolve1Dy_v3D_gl", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_v3D_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "");

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_v3D_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_v3D_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_X_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_vfield3D_f(image,0,j)->x,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Y_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_vfield3D_f(image,0,j)->y,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_Z_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_vfield3D_f(image,0,j)->z,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_v3D_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_v3D_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_X_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_vfield3D_d(image,0,j)->x,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Y_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_vfield3D_d(image,0,j)->y,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_Z_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_vfield3D_d(image,0,j)->z,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_v3D_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_v3D_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_X_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_vfield3D_i(image,0,j)->x,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }
 
             break;

           case GAN_Y_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_vfield3D_i(image,0,j)->y,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Z_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_vfield3D_i(image,0,j)->z,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_v3D_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_v3D_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_v3D_gl",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_v3D_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dy_rgb_gl ( Gan_Image *image, Gan_ImageChannelType channel,
                            Gan_Mask1D *mask, Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_IMAGE,
                      "image_convolve1Dy_rgb_gl", GAN_ERROR_INCOMPATIBLE, "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_rgb_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_rgb_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_rgb_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_rgb_f(image,0,j)->R,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_rgb_f(image,0,j)->G,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_rgb_f(image,0,j)->B,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_rgb_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_rgb_d(image,0,j)->R,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_rgb_d(image,0,j)->G,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_rgb_d(image,0,j)->B,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_rgb_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_rgb_i(image,0,j)->R,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }
 
             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_rgb_i(image,0,j)->G,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_rgb_i(image,0,j)->B,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_rgb_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      case GAN_UCHAR:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned char)) == 0 &&
                           (dest->stride % sizeof(unsigned char)) == 0,
                           "image_convolve1Dy_rgb_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_uc (
                          &gan_image_get_pixptr_rgb_uc(image,0,j)->R,
                          image->stride/sizeof(unsigned char),
                          gan_image_get_pixptr_gl_uc(dest,0,j),
                          dest->stride/sizeof(unsigned char),
                          mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }
 
             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_uc (
                          &gan_image_get_pixptr_rgb_uc(image,0,j)->G,
                          image->stride/sizeof(unsigned char),
                          gan_image_get_pixptr_gl_uc(dest,0,j),
                          dest->stride/sizeof(unsigned char),
                          mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_uc (
                          &gan_image_get_pixptr_rgb_uc(image,0,j)->B,
                          image->stride/sizeof(unsigned char),
                          gan_image_get_pixptr_gl_uc(dest,0,j),
                          dest->stride/sizeof(unsigned char),
                          mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_rgb_gl",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_rgb_gl",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_rgb_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dy_rgba_gl ( Gan_Image *image, Gan_ImageChannelType channel,
                             Gan_Mask1D *mask, Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "image_convolve1Dy_rgba_gl", GAN_ERROR_INCOMPATIBLE,
                      "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_rgba_gl",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_GREY_LEVEL_IMAGE,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_rgba_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_rgba_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_rgba_f(image,0,j)->R,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_rgba_f(image,0,j)->G,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          &gan_image_get_pixptr_rgba_f(image,0,j)->B,
                          image->stride/sizeof(float),
                          gan_image_get_pixptr_gl_f(dest,0,j),
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_rgba_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_rgba_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_rgba_d(image,0,j)->R,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgb_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_rgba_d(image,0,j)->G,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          &gan_image_get_pixptr_rgba_d(image,0,j)->B,
                          image->stride/sizeof(double),
                          gan_image_get_pixptr_gl_d(dest,0,j),
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_rgba_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_rgba_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_rgba_i(image,0,j)->R,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }
 
             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_rgba_i(image,0,j)->G,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          &gan_image_get_pixptr_rgba_i(image,0,j)->B,
                          image->stride/sizeof(int),
                          gan_image_get_pixptr_gl_i(dest,0,j),
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_rgba_gl",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      case GAN_UCHAR:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned char)) == 0 &&
                           (dest->stride % sizeof(unsigned char)) == 0,
                           "image_convolve1Dy_rgba_gl", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_RED_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_uc (
                          &gan_image_get_pixptr_rgba_uc(image,0,j)->R,
                          image->stride/sizeof(unsigned char),
                          gan_image_get_pixptr_gl_uc(dest,0,j),
                          dest->stride/sizeof(unsigned char),
                          mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }
 
             break;

           case GAN_GREEN_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_uc (
                          &gan_image_get_pixptr_rgba_uc(image,0,j)->G,
                          image->stride/sizeof(unsigned char),
                          gan_image_get_pixptr_gl_uc(dest,0,j),
                          dest->stride/sizeof(unsigned char),
                          mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_BLUE_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_uc (
                          &gan_image_get_pixptr_rgba_uc(image,0,j)->B,
                          image->stride/sizeof(unsigned char),
                          gan_image_get_pixptr_gl_uc(dest,0,j),
                          dest->stride/sizeof(unsigned char),
                          mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_rgba_gl",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_rgba_gl",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_rgba_gl",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_rgb_gl", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}


static Gan_Image *
 image_convolve1Dy_gl_v3D ( Gan_Image *image, Gan_ImageChannelType channel,
                            Gan_Mask1D *mask, Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_GREY_LEVEL_IMAGE,
                      "image_convolve1Dy_gl_v3D", GAN_ERROR_INCOMPATIBLE,
                      "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_gl_v3D",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_VECTOR_FIELD_3D, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_VECTOR_FIELD_3D,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_gl_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_gl_v3D", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_X_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          gan_image_get_pixptr_gl_f(image,0,j),
                          image->stride/sizeof(float),
                          &gan_image_get_pixptr_vfield3D_f(dest,0,j)->x,
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Y_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          gan_image_get_pixptr_gl_f(image,0,j),
                          image->stride/sizeof(float),
                          &gan_image_get_pixptr_vfield3D_f(dest,0,j)->y,
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Z_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_f (
                          gan_image_get_pixptr_gl_f(image,0,j),
                          image->stride/sizeof(float),
                          &gan_image_get_pixptr_vfield3D_f(dest,0,j)->z,
                          dest->stride/sizeof(float), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_gl_v3D",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_gl_v3D", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_X_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          gan_image_get_pixptr_gl_d(image,0,j),
                          image->stride/sizeof(double),
                          &gan_image_get_pixptr_vfield3D_d(dest,0,j)->x,
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Y_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          gan_image_get_pixptr_gl_d(image,0,j),
                          image->stride/sizeof(double),
                          &gan_image_get_pixptr_vfield3D_d(dest,0,j)->y,
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           case GAN_Z_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_d (
                          gan_image_get_pixptr_gl_d(image,0,j),
                          image->stride/sizeof(double),
                          &gan_image_get_pixptr_vfield3D_d(dest,0,j)->z,
                          dest->stride/sizeof(double), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "image_convolve1Dy_gl_v3D",
                                GAN_ERROR_ILLEGAL_TYPE, "" );
             return NULL;
        }
        break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_gl_v3D", GAN_ERROR_INCOMPATIBLE,
                           "" );
        switch ( channel )
        {
           case GAN_X_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          gan_image_get_pixptr_gl_i(image,0,j),
                          image->stride/sizeof(int),
                          &gan_image_get_pixptr_vfield3D_i(dest,0,j)->x,
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_Y_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          gan_image_get_pixptr_gl_i(image,0,j),
                          image->stride/sizeof(int),
                          &gan_image_get_pixptr_vfield3D_i(dest,0,j)->y,
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

           case GAN_Z_CHANNEL:
             for ( j = (int)dest->width-1; j >= 0; j-- )
                if ( !gan_convolve1D_i (
                          gan_image_get_pixptr_gl_i(image,0,j),
                          image->stride/sizeof(int),
                          &gan_image_get_pixptr_vfield3D_i(dest,0,j)->z,
                          dest->stride/sizeof(int), mask, dest->height ) )
                {
                   gan_err_register ( "image_convolve1Dy_gl_v3D",
                                      GAN_ERROR_FAILURE, "" );
                   return NULL;
                }

           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "image_convolve1Dy_gl_v3D",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_gl_v3D",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_gl_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dy_v3D_v3D ( Gan_Image *image, Gan_Mask1D *mask,
                             Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_VECTOR_FIELD_3D,
                      "image_convolve1Dy_v3D_v3D", GAN_ERROR_INCOMPATIBLE,
                      "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_v3D_v3D",
                      GAN_ERROR_IMAGE_TOO_SMALL, "in vertical direction");

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_VECTOR_FIELD_3D, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_VECTOR_FIELD_3D,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_v3D_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_v3D_v3D", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_f (
                     &gan_image_get_pixptr_vfield3D_f(image,0,j)->x,
                     image->stride/sizeof(float),
                     &gan_image_get_pixptr_vfield3D_f(dest,0,j)->x,
                     dest->stride/sizeof(float), mask, dest->height ) ||
                !gan_convolve1D_f (
                     &gan_image_get_pixptr_vfield3D_f(image,0,j)->y,
                     image->stride/sizeof(float),
                     &gan_image_get_pixptr_vfield3D_f(dest,0,j)->y,
                     dest->stride/sizeof(float), mask, dest->height ) ||
                !gan_convolve1D_f (
                     &gan_image_get_pixptr_vfield3D_f(image,0,j)->z,
                     image->stride/sizeof(float),
                     &gan_image_get_pixptr_vfield3D_f(dest,0,j)->z,
                     dest->stride/sizeof(float), mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_v3D_v3D",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_v3D_v3D", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_d (
                     &gan_image_get_pixptr_vfield3D_d(image,0,j)->x,
                     image->stride/sizeof(double),
                     &gan_image_get_pixptr_vfield3D_d(dest,0,j)->x,
                     dest->stride/sizeof(double), mask, dest->height ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_vfield3D_d(image,0,j)->y,
                     image->stride/sizeof(double),
                     &gan_image_get_pixptr_vfield3D_d(dest,0,j)->y,
                     dest->stride/sizeof(double), mask, dest->height ) ||
                !gan_convolve1D_d (
                     &gan_image_get_pixptr_vfield3D_d(image,0,j)->z,
                     image->stride/sizeof(double),
                     &gan_image_get_pixptr_vfield3D_d(dest,0,j)->z,
                     dest->stride/sizeof(double), mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_v3D_v3D",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_v3D_v3D", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_i (
                     &gan_image_get_pixptr_vfield3D_i(image,0,j)->x,
                     image->stride/sizeof(int),
                     &gan_image_get_pixptr_vfield3D_i(dest,0,j)->x,
                     dest->stride/sizeof(int), mask, dest->height ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_vfield3D_i(image,0,j)->y,
                     image->stride/sizeof(int),
                     &gan_image_get_pixptr_vfield3D_i(dest,0,j)->y,
                     dest->stride/sizeof(int), mask, dest->height ) ||
                !gan_convolve1D_i (
                     &gan_image_get_pixptr_vfield3D_i(image,0,j)->z,
                     image->stride/sizeof(int),
                     &gan_image_get_pixptr_vfield3D_i(dest,0,j)->z,
                     dest->stride/sizeof(int), mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_v3D_v3D",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_v3D_v3D",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_v3D_v3D", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dy_rgb_rgb ( Gan_Image *image, Gan_Mask1D *mask,
                             Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_IMAGE,
                      "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                      "" );
   gan_err_test_ptr ( image->height >= mask->size, "image_convolve1Dy_rgb_rgb",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_RGB_COLOUR_IMAGE, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_RGB_COLOUR_IMAGE,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_rgb_rgb", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_f ( &gan_image_get_pixptr_rgb_f(image,0,j)->R,
                                    image->stride/sizeof(float),
                                    &gan_image_get_pixptr_rgb_f(dest,0,j)->R,
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) ||
                !gan_convolve1D_f ( &gan_image_get_pixptr_rgb_f(image,0,j)->G,
                                    image->stride/sizeof(float),
                                    &gan_image_get_pixptr_rgb_f(dest,0,j)->G,
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) ||
                !gan_convolve1D_f ( &gan_image_get_pixptr_rgb_f(image,0,j)->B,
                                    image->stride/sizeof(float),
                                    &gan_image_get_pixptr_rgb_f(dest,0,j)->B,
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgb_rgb",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_d ( &gan_image_get_pixptr_rgb_d(image,0,j)->R,
                                    image->stride/sizeof(double),
                                    &gan_image_get_pixptr_rgb_d(dest,0,j)->R,
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) ||
                !gan_convolve1D_d ( &gan_image_get_pixptr_rgb_d(image,0,j)->G,
                                    image->stride/sizeof(double),
                                    &gan_image_get_pixptr_rgb_d(dest,0,j)->G,
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) ||
                !gan_convolve1D_d ( &gan_image_get_pixptr_rgb_d(image,0,j)->B,
                                    image->stride/sizeof(double),
                                    &gan_image_get_pixptr_rgb_d(dest,0,j)->B,
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgb_rgb",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                           "image stride" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_i ( &gan_image_get_pixptr_rgb_i(image,0,j)->R,
                                    image->stride/sizeof(int),
                                    &gan_image_get_pixptr_rgb_i(dest,0,j)->R,
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) ||
                !gan_convolve1D_i ( &gan_image_get_pixptr_rgb_i(image,0,j)->G,
                                    image->stride/sizeof(int),
                                    &gan_image_get_pixptr_rgb_i(dest,0,j)->G,
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) ||
                !gan_convolve1D_i ( &gan_image_get_pixptr_rgb_i(image,0,j)->B,
                                    image->stride/sizeof(int),
                                    &gan_image_get_pixptr_rgb_i(dest,0,j)->B,
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgb_rgb",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_UINT:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned int)) == 0 &&
                           (dest->stride % sizeof(unsigned int)) == 0,
                           "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_ui (&gan_image_get_pixptr_rgb_ui(image,0,j)->R,
                                    image->stride/sizeof(unsigned int),
                                    &gan_image_get_pixptr_rgb_ui(dest,0,j)->R,
                                    dest->stride/sizeof(unsigned int),
                                    mask, dest->height) ||
                !gan_convolve1D_ui (&gan_image_get_pixptr_rgb_ui(image,0,j)->G,
                                    image->stride/sizeof(unsigned int),
                                    &gan_image_get_pixptr_rgb_ui(dest,0,j)->G,
                                    dest->stride/sizeof(unsigned int),
                                    mask, dest->height) ||
                !gan_convolve1D_ui (&gan_image_get_pixptr_rgb_ui(image,0,j)->B,
                                    image->stride/sizeof(unsigned int),
                                    &gan_image_get_pixptr_rgb_ui(dest,0,j)->B,
                                    image->stride/sizeof(unsigned int),
                                    mask, dest->height) )
           {
              gan_err_register ( "image_convolve1Dy_rgb_rgb",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;
        
      case GAN_UCHAR:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned char)) == 0 &&
                           (dest->stride % sizeof(unsigned char)) == 0,
                           "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_uc (&gan_image_get_pixptr_rgb_uc(image,0,j)->R,
                                    image->stride/sizeof(unsigned char),
                                    &gan_image_get_pixptr_rgb_uc(dest,0,j)->R,
                                    dest->stride/sizeof(unsigned char),
                                    mask, dest->height) ||
                !gan_convolve1D_uc (&gan_image_get_pixptr_rgb_uc(image,0,j)->G,
                                    image->stride/sizeof(unsigned char),
                                    &gan_image_get_pixptr_rgb_uc(dest,0,j)->G,
                                    dest->stride/sizeof(unsigned char),
                                    mask, dest->height) ||
                !gan_convolve1D_uc (&gan_image_get_pixptr_rgb_uc(image,0,j)->B,
                                    image->stride/sizeof(unsigned char),
                                    &gan_image_get_pixptr_rgb_uc(dest,0,j)->B,
                                    dest->stride/sizeof(unsigned char),
                                    mask, dest->height) )
           {
              gan_err_register ( "image_convolve1Dy_rgb_rgb",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;
        
      case GAN_USHORT:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned short)) == 0 &&
                           (dest->stride % sizeof(unsigned short)) == 0,
                           "image_convolve1Dy_rgb_rgb", GAN_ERROR_INCOMPATIBLE,
                           "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_us (&gan_image_get_pixptr_rgb_us(image,0,j)->R,
                                    image->stride/sizeof(unsigned short),
                                    &gan_image_get_pixptr_rgb_us(dest,0,j)->R,
                                    dest->stride/sizeof(unsigned short),
                                    mask, dest->height) ||
                !gan_convolve1D_us (&gan_image_get_pixptr_rgb_us(image,0,j)->G,
                                    image->stride/sizeof(unsigned short),
                                    &gan_image_get_pixptr_rgb_us(dest,0,j)->G,
                                    dest->stride/sizeof(unsigned short),
                                    mask, dest->height) ||
                !gan_convolve1D_us (&gan_image_get_pixptr_rgb_us(image,0,j)->B,
                                    image->stride/sizeof(unsigned short),
                                    &gan_image_get_pixptr_rgb_us(dest,0,j)->B,
                                    dest->stride/sizeof(unsigned short),
                                    mask, dest->height) )
           {
              gan_err_register ( "image_convolve1Dy_rgb_rgb",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_rgb_rgb",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_rgb_rgb", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

static Gan_Image *
 image_convolve1Dy_rgba_rgba ( Gan_Image *image, Gan_Mask1D *mask,
                               Gan_Image *dest )
{
   int j;

   gan_err_test_ptr ( image->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "image_convolve1Dy_rgb_rgba", GAN_ERROR_INCOMPATIBLE,
                      "" );
   gan_err_test_ptr ( image->height >= mask->size,
                      "image_convolve1Dy_rgba_rgba",
                      GAN_ERROR_IMAGE_TOO_SMALL, "" );

   if ( dest == NULL )
      dest = gan_image_alloc ( GAN_RGB_COLOUR_ALPHA_IMAGE, image->type,
                               image->height-mask->size+1, image->width );
   else
      dest = gan_image_set_format_type_dims ( dest,
                                              GAN_RGB_COLOUR_ALPHA_IMAGE,
                                              image->type,
                                              image->height-mask->size+1,
                                              image->width );

   if ( dest == NULL )
   {
      gan_err_register ( "image_convolve1Dy_rgba_rgba", GAN_ERROR_FAILURE, "");
      return NULL;
   }

   dest->offset_x = image->offset_x+mask->size/2;
   dest->offset_y = image->offset_y+mask->size/2;

   switch ( image->type )
   {
      case GAN_FLOAT:
        gan_err_test_ptr ( (image->stride % sizeof(float)) == 0 &&
                           (dest->stride % sizeof(float)) == 0,
                           "image_convolve1Dy_rgba_rgba",
                           GAN_ERROR_INCOMPATIBLE, "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_f ( &gan_image_get_pixptr_rgba_f(image,0,j)->R,
                                    image->stride/sizeof(float),
                                    &gan_image_get_pixptr_rgba_f(dest,0,j)->R,
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) ||
                !gan_convolve1D_f ( &gan_image_get_pixptr_rgba_f(image,0,j)->G,
                                    image->stride/sizeof(float),
                                    &gan_image_get_pixptr_rgba_f(dest,0,j)->G,
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) ||
                !gan_convolve1D_f ( &gan_image_get_pixptr_rgba_f(image,0,j)->B,
                                    image->stride/sizeof(float),
                                    &gan_image_get_pixptr_rgba_f(dest,0,j)->B,
                                    dest->stride/sizeof(float),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgba_rgba",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_DOUBLE:
        gan_err_test_ptr ( (image->stride % sizeof(double)) == 0 &&
                           (dest->stride % sizeof(double)) == 0,
                           "image_convolve1Dy_rgba_rgba",
                           GAN_ERROR_INCOMPATIBLE, "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_d ( &gan_image_get_pixptr_rgba_d(image,0,j)->R,
                                    image->stride/sizeof(double),
                                    &gan_image_get_pixptr_rgba_d(dest,0,j)->R,
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) ||
                !gan_convolve1D_d ( &gan_image_get_pixptr_rgba_d(image,0,j)->G,
                                    image->stride/sizeof(double),
                                    &gan_image_get_pixptr_rgba_d(dest,0,j)->G,
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) ||
                !gan_convolve1D_d ( &gan_image_get_pixptr_rgba_d(image,0,j)->B,
                                    image->stride/sizeof(double),
                                    &gan_image_get_pixptr_rgba_d(dest,0,j)->B,
                                    dest->stride/sizeof(double),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgba_rgba",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_INT:
        gan_err_test_ptr ( (image->stride % sizeof(int)) == 0 &&
                           (dest->stride % sizeof(int)) == 0,
                           "image_convolve1Dy_rgb_rgba",
                           GAN_ERROR_INCOMPATIBLE, "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_i ( &gan_image_get_pixptr_rgba_i(image,0,j)->R,
                                    image->stride/sizeof(int),
                                    &gan_image_get_pixptr_rgba_i(dest,0,j)->R,
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) ||
                !gan_convolve1D_i ( &gan_image_get_pixptr_rgba_i(image,0,j)->G,
                                    image->stride/sizeof(int),
                                    &gan_image_get_pixptr_rgba_i(dest,0,j)->G,
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) ||
                !gan_convolve1D_i ( &gan_image_get_pixptr_rgba_i(image,0,j)->B,
                                    image->stride/sizeof(int),
                                    &gan_image_get_pixptr_rgba_i(dest,0,j)->B,
                                    dest->stride/sizeof(int),
                                    mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgba_rgba",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_UINT:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned int)) == 0 &&
                           (dest->stride % sizeof(unsigned int)) == 0,
                           "image_convolve1Dy_rgba_rgba",
                           GAN_ERROR_INCOMPATIBLE, "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_ui(&gan_image_get_pixptr_rgba_ui(image,0,j)->R,
                                   image->stride/sizeof(unsigned int),
                                   &gan_image_get_pixptr_rgba_ui(dest,0,j)->R,
                                   dest->stride/sizeof(unsigned int),
                                   mask, dest->height ) ||
                !gan_convolve1D_ui(&gan_image_get_pixptr_rgba_ui(image,0,j)->G,
                                   image->stride/sizeof(unsigned int),
                                   &gan_image_get_pixptr_rgba_ui(dest,0,j)->G,
                                   dest->stride/sizeof(unsigned int),
                                   mask, dest->height ) ||
                !gan_convolve1D_ui(&gan_image_get_pixptr_rgba_ui(image,0,j)->B,
                                   image->stride/sizeof(unsigned int),
                                   &gan_image_get_pixptr_rgba_ui(dest,0,j)->B,
                                   dest->stride/sizeof(unsigned int),
                                   mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgba_rgba",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;
        
      case GAN_UCHAR:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned char)) == 0 &&
                           (dest->stride % sizeof(unsigned char)) == 0,
                           "image_convolve1Dy_rgba_rgba",
                           GAN_ERROR_INCOMPATIBLE, "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_uc(&gan_image_get_pixptr_rgba_uc(image,0,j)->R,
                                   image->stride/sizeof(unsigned char),
                                   &gan_image_get_pixptr_rgba_uc(dest,0,j)->R,
                                   dest->stride/sizeof(unsigned char),
                                   mask, dest->height ) ||
                !gan_convolve1D_uc(&gan_image_get_pixptr_rgba_uc(image,0,j)->G,
                                   image->stride/sizeof(unsigned char),
                                   &gan_image_get_pixptr_rgba_uc(dest,0,j)->G,
                                   dest->stride/sizeof(unsigned char),
                                   mask, dest->height ) ||
                !gan_convolve1D_uc(&gan_image_get_pixptr_rgba_uc(image,0,j)->B,
                                   image->stride/sizeof(unsigned char),
                                   &gan_image_get_pixptr_rgba_uc(dest,0,j)->B,
                                   dest->stride/sizeof(unsigned char),
                                   mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgba_rgba",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;

      case GAN_USHORT:
        gan_err_test_ptr ( (image->stride % sizeof(unsigned short)) == 0 &&
                           (dest->stride % sizeof(unsigned short)) == 0,
                           "image_convolve1Dy_rgba_rgba",
                           GAN_ERROR_INCOMPATIBLE, "" );
        for ( j = (int)dest->width-1; j >= 0; j-- )
           if ( !gan_convolve1D_us(&gan_image_get_pixptr_rgba_us(image,0,j)->R,
                                   image->stride/sizeof(unsigned short),
                                   &gan_image_get_pixptr_rgba_us(dest,0,j)->R,
                                   dest->stride/sizeof(unsigned short),
                                   mask, dest->height ) ||
                !gan_convolve1D_us(&gan_image_get_pixptr_rgba_us(image,0,j)->G,
                                   image->stride/sizeof(unsigned short),
                                   &gan_image_get_pixptr_rgba_us(dest,0,j)->G,
                                   dest->stride/sizeof(unsigned short),
                                   mask, dest->height ) ||
                !gan_convolve1D_us(&gan_image_get_pixptr_rgba_us(image,0,j)->B,
                                   image->stride/sizeof(unsigned short),
                                   &gan_image_get_pixptr_rgba_us(dest,0,j)->B,
                                   dest->stride/sizeof(unsigned short),
                                   mask, dest->height ) )
           {
              gan_err_register ( "image_convolve1Dy_rgba_rgba",
                                 GAN_ERROR_FAILURE, "" );
              return NULL;
           }

        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "image_convolve1Dy_rgba_rgba",
                           GAN_ERROR_ILLEGAL_TYPE, "" );
        return NULL;
   }

   /* check if we aborted the loop early because of an error */
   if ( j >= 0 )
   {
      gan_err_register ( "image_convolve1Dy_rgba_rgba", GAN_ERROR_FAILURE, "");
      return NULL;
   }

   /* success */
   return dest;
}

/**
 * \brief Convolves an image in the y-direction.
 * \param image The input image
 * \param channel Colour channel to be convolved where applicable
 * \param mask The image convolution mask
 * \param dest The destination image for the convolution operation
 *
 * Applies a one-dimensional convolution operation to the
 * given image in the y-direction. When the image contains
 * colour or vector field data, a particular colour channel/vector
 * field element can be specified by the channel argument, which
 * should otherwise be passed as #GAN_ALL_CHANNELS.
 * There is no checking for overflow of integer values.
 *
 * Macro call to gan_image_convolve1Dy_q().
 *
 * \return Non-\c NULL on successfully returning the destination image \a dest,
 * \c NULL on failure.
 * \sa gan_image_convolve1Dy_q, gan_gauss_mask_new().
 */
Gan_Image *
03974  gan_image_convolve1Dy_q ( Gan_Image *image, Gan_ImageChannelType channel,
                           Gan_Mask1D *mask, Gan_Image *dest )
{
   switch ( image->format )
   {
      case GAN_GREY_LEVEL_IMAGE:
      switch ( channel )
      {
         case GAN_INTENSITY_CHANNEL:
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dy_gl_gl ( image, mask, dest );
           break;

         case GAN_X_CHANNEL:
         case GAN_Y_CHANNEL:
         case GAN_Z_CHANNEL:
           dest = image_convolve1Dy_gl_v3D ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dy_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_VECTOR_FIELD_3D:
      switch ( channel )
      {
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dy_v3D_v3D ( image, mask, dest );
           break;

         case GAN_X_CHANNEL:
         case GAN_Y_CHANNEL:
         case GAN_Z_CHANNEL:
           dest = image_convolve1Dy_v3D_gl ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dy_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_RGB_COLOUR_IMAGE:
      switch ( channel )
      {
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dy_rgb_rgb ( image, mask, dest );
           break;

         case GAN_RED_CHANNEL:
         case GAN_GREEN_CHANNEL:
         case GAN_BLUE_CHANNEL:
           dest = image_convolve1Dy_rgb_gl ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dy_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;

      case GAN_RGB_COLOUR_ALPHA_IMAGE:
      switch ( channel )
      {
         case GAN_ALL_CHANNELS:
           dest = image_convolve1Dy_rgba_rgba ( image, mask, dest );
           break;

         case GAN_RED_CHANNEL:
         case GAN_GREEN_CHANNEL:
         case GAN_BLUE_CHANNEL:
           dest = image_convolve1Dy_rgba_gl ( image, channel, mask, dest );
           break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "gan_image_convolve1Dy_q",
                              GAN_ERROR_ILLEGAL_TYPE, "" );
           return NULL;
      }
      break;      
      default:
        gan_err_flush_trace();
        gan_err_register ( "gan_image_convolve1Dy_q", GAN_ERROR_ILLEGAL_TYPE,
                           "" );
        return NULL;
   }

   if ( dest == NULL )
   {
      gan_err_register ( "gan_image_convolve1Dy_q", GAN_ERROR_FAILURE, "" );
      return NULL;
   }

   /* success */
   return dest;
}

/**
 * \}
 */

/**
 * \}
 */

Generated by  Doxygen 1.6.0   Back to index