Logo Search packages:      
Sourcecode: gandalf version File versions

image_pyramid.c

/**
 * File:          $RCSfile: image_pyramid.c,v $
 * Module:        Construct multi-resolution image pyramid
 * Part of:       Gandalf Library
 *
 * Revision:      $Revision: 1.30 $
 * Last edited:   $Date: 2002/04/22 13:42:18 $
 * 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/image/image_pyramid.h>
#include <gandalf/image/image_gl_uchar.h>
#include <gandalf/image/image_gl_ushort.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_float.h>
#include <gandalf/image/image_rgb_double.h>
#include <gandalf/image/image_rgb_uchar.h>
#include <gandalf/image/image_rgb_ushort.h>
#include <gandalf/image/image_rgb_uint.h>
#include <gandalf/image/image_rgba_float.h>
#include <gandalf/image/image_rgba_double.h>
#include <gandalf/image/image_rgba_uchar.h>
#include <gandalf/image/image_rgba_ushort.h>
#include <gandalf/image/image_rgba_uint.h>
#include <gandalf/image/image_vfield2D_short.h>
#include <gandalf/image/image_vfield2D_int.h>
#include <gandalf/image/image_vfield2D_float.h>
#include <gandalf/image/image_vfield2D_double.h>
#include <gandalf/image/image_vfield3D_short.h>
#include <gandalf/image/image_vfield3D_int.h>
#include <gandalf/image/image_vfield3D_float.h>
#include <gandalf/image/image_vfield3D_double.h>
#include <gandalf/image/image_bit.h>
#include <gandalf/common/allocate.h>
#include <gandalf/common/misc_error.h>

/**
 * \addtogroup ImagePackage
 * \{
 */

/**
 * \defgroup ImagePyramid Image Pyramids
 * \{
 */

static Gan_Bool
 halve_size_b ( Gan_Image *image, Gan_Image *mask,
                Gan_ImagePyramidAverage average_type,
                unsigned no_neighbours,
                Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   gan_err_test_bool ( mask == NULL && hmask == NULL, "halve_size_b",
                       GAN_ERROR_FAILURE, "" );
   if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(image,i*2,j*2) )
               gan_image_set_pix_b ( himage, i, j, GAN_TRUE );
   }
   else /* no_neighbours < 4 */
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(image,i*2,j*2) )
               gan_image_set_pix_b ( himage, i, j, GAN_TRUE );
            else
            {
               num = 0;
               if ( gan_image_get_pix_b ( image, i*2,   j*2 )   ) num++;
               if ( gan_image_get_pix_b ( image, i*2,   j*2+1 ) ) num++;
               if ( gan_image_get_pix_b ( image, i*2+1, j*2 )   ) num++;
               if ( gan_image_get_pix_b ( image, i*2+1, j*2+1 ) ) num++;
               if ( num >= no_neighbours )
                  gan_image_set_pix_b ( himage, i, j, GAN_TRUE );
            }
   }
   
   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_gl_uc ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            gan_image_set_pix_gl_uc ( himage, i, j, (unsigned char)
                        (((unsigned) gan_image_get_pix_gl_uc(image,i*2,j*2) +
                          (unsigned) gan_image_get_pix_gl_uc(image,i*2,j*2+1) +
                          (unsigned) gan_image_get_pix_gl_uc(image,i*2+1,j*2) +
                          (unsigned) gan_image_get_pix_gl_uc(image,i*2+1,j*2+1)
                          + 2)/4) );
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_uc ( himage, i, j, (unsigned char)
                           (((unsigned)gan_image_get_pix_gl_uc(image,i*2,j*2) +
                           (unsigned)gan_image_get_pix_gl_uc(image,i*2,j*2+1) +
                           (unsigned)gan_image_get_pix_gl_uc(image,i*2+1,j*2) +
                           (unsigned)gan_image_get_pix_gl_uc(image,i*2+1,j*2+1)
                           + 2)/4) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned total, num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_uc ( himage, i, j, (unsigned char)
                           (((unsigned)gan_image_get_pix_gl_uc(image,i*2,j*2) +
                           (unsigned)gan_image_get_pix_gl_uc(image,i*2,j*2+1) +
                           (unsigned)gan_image_get_pix_gl_uc(image,i*2+1,j*2) +
                           (unsigned)gan_image_get_pix_gl_uc(image,i*2+1,j*2+1)
                           + 2)/4) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  total += (unsigned)gan_image_get_pix_gl_uc(image,i*2,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  total += (unsigned) gan_image_get_pix_gl_uc(image,i*2,j*2+1);
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  total += (unsigned) gan_image_get_pix_gl_uc(image,i*2+1,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  total += (unsigned)
                           gan_image_get_pix_gl_uc(image,i*2+1,j*2+1);
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                     gan_image_set_pix_gl_uc ( himage, i, j, (unsigned char)
                                               ((total + num/2)/num) );
                  else /* average_type == GAN_AVERAGE_ALL */
                     gan_image_set_pix_gl_uc ( himage, i, j, (unsigned char)
                                               ((total + 2)/4) );

                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
 
#if (SIZEOF_SHORT < SIZEOF_INT)
static Gan_Bool
 halve_size_gl_us ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            gan_image_set_pix_gl_us ( himage, i, j, (unsigned short)
                       (((unsigned)gan_image_get_pix_gl_us(image,i*2,j*2) +
                         (unsigned)gan_image_get_pix_gl_us(image,i*2,j*2+1) +
                         (unsigned)gan_image_get_pix_gl_us(image,i*2+1,j*2) +
                         (unsigned)gan_image_get_pix_gl_us(image,i*2+1,j*2+1)
                         + 2)/4) );
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_us ( himage, i, j,(unsigned short)
                         (((unsigned)gan_image_get_pix_gl_us(image,i*2,j*2) +
                           (unsigned)gan_image_get_pix_gl_us(image,i*2,j*2+1) +
                           (unsigned)gan_image_get_pix_gl_us(image,i*2+1,j*2) +
                           (unsigned)gan_image_get_pix_gl_us(image,i*2+1,j*2+1)
                           + 2)/4) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned total, num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_us ( himage, i, j, (unsigned short)
                           (((unsigned)gan_image_get_pix_gl_us(image,i*2,j*2) +
                           (unsigned)gan_image_get_pix_gl_us(image,i*2,j*2+1) +
                           (unsigned)gan_image_get_pix_gl_us(image,i*2+1,j*2) +
                           (unsigned)gan_image_get_pix_gl_us(image,i*2+1,j*2+1)
                           + 2)/4) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  total += (unsigned)gan_image_get_pix_gl_us(image,i*2,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  total += (unsigned) gan_image_get_pix_gl_us(image,i*2,j*2+1);
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  total += (unsigned) gan_image_get_pix_gl_us(image,i*2+1,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  total += (unsigned)
                           gan_image_get_pix_gl_us(image,i*2+1,j*2+1);
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                     gan_image_set_pix_gl_us ( himage, i, j, (unsigned short)
                                               ((total + num/2)/num) );
                  else /* average_type == GAN_AVERAGE_ALL */
                     gan_image_set_pix_gl_us ( himage, i, j, (unsigned short)
                                               ((total + 2)/4) );

                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#else
#error "Unsupported size combination"
#endif /* #if (SIZEOF_SHORT < SIZEOF_INT) */

#if (SIZEOF_INT == SIZEOF_LONG)
static Gan_Bool
 halve_size_gl_ui ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            gan_image_set_pix_gl_ui ( himage, i, j,
                            gan_image_get_pix_gl_ui(image,i*2,j*2)/4 +
                            gan_image_get_pix_gl_ui(image,i*2,j*2+1)/4 +
                            gan_image_get_pix_gl_ui(image,i*2+1,j*2)/4 +
                            gan_image_get_pix_gl_ui(image,i*2+1,j*2+1)/4 );
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_ui ( himage, i, j,
                            gan_image_get_pix_gl_ui(image,i*2,j*2)/4 +
                            gan_image_get_pix_gl_ui(image,i*2,j*2+1)/4 +
                            gan_image_get_pix_gl_ui(image,i*2+1,j*2)/4 +
                            gan_image_get_pix_gl_ui(image,i*2+1,j*2+1)/4 );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned total, num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_ui ( himage, i, j,
                            gan_image_get_pix_gl_ui(image,i*2,j*2)/4 +
                            gan_image_get_pix_gl_ui(image,i*2,j*2+1)/4 +
                            gan_image_get_pix_gl_ui(image,i*2+1,j*2)/4 +
                            gan_image_get_pix_gl_ui(image,i*2+1,j*2+1)/4 );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  total += gan_image_get_pix_gl_ui(image,i*2,j*2)/4;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  total += gan_image_get_pix_gl_ui(image,i*2,j*2+1)/4;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  total += gan_image_get_pix_gl_ui(image,i*2+1,j*2)/4;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  total += gan_image_get_pix_gl_ui(image,i*2+1,j*2+1)/4;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                     gan_image_set_pix_gl_ui ( himage, i, j, (total/num)*4 );
                  else /* average_type == GAN_AVERAGE_ALL */
                     gan_image_set_pix_gl_ui ( himage, i, j, total );

                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#else /* (SIZEOF_INT < SIZEOF_LONG) */
static Gan_Bool
 halve_size_gl_ui ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            gan_image_set_pix_gl_ui ( himage, i, j, (unsigned)
               (((unsigned long)gan_image_get_pix_gl_ui(i*2,j*2) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2,j*2+1) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2+1,j*2) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2+1,j*2+1) + 2)/4) );
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_ui ( himage, i, j, (unsigned)
               (((unsigned long)gan_image_get_pix_gl_ui(i*2,j*2) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2,j*2+1) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2+1,j*2) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2+1,j*2+1) + 2)/4) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned long total, num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_ui ( himage, i, j, (unsigned)
               (((unsigned long)gan_image_get_pix_gl_ui(i*2,j*2) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2,j*2+1) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2+1,j*2) +
                 (unsigned long)gan_image_get_pix_gl_ui(i*2+1,j*2+1) + 2)/4) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  total += (unsigned long)
                           gan_image_get_pix_gl_ui(image,i*2,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  total += (unsigned long)
                           gan_image_get_pix_gl_ui(image,i*2,j*2+1);
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  total += (unsigned long)
                           gan_image_get_pix_gl_ui(image,i*2+1,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  total += (unsigned long)
                           gan_image_get_pix_gl_ui(image,i*2+1,j*2+1);
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                     gan_image_set_pix_gl_ui ( himage, i, j, (unsigned)
                                               ((total + num/2)/num) );
                  else /* average_type == GAN_AVERAGE_ALL */
                     gan_image_set_pix_gl_ui ( himage, i, j, (unsigned)
                                               ((total + 2)/4) );

                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#endif /* #if (SIZEOF_INT == SIZEOF_LONG) */

static Gan_Bool
 halve_size_gl_f ( Gan_Image *image, Gan_Image *mask,
                   Gan_ImagePyramidAverage average_type,
                   unsigned no_neighbours,
                   Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            gan_image_set_pix_gl_f ( himage, i, j,
                           0.25F*(gan_image_get_pix_gl_f(image,i*2,j*2) +
                                  gan_image_get_pix_gl_f(image,i*2,j*2+1) +
                                  gan_image_get_pix_gl_f(image,i*2+1,j*2) +
                                  gan_image_get_pix_gl_f(image,i*2+1,j*2+1)) );
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_f ( himage, i, j,
                           0.25F*(gan_image_get_pix_gl_f(image,i*2,j*2) +
                                  gan_image_get_pix_gl_f(image,i*2,j*2+1) +
                                  gan_image_get_pix_gl_f(image,i*2+1,j*2) +
                                  gan_image_get_pix_gl_f(image,i*2+1,j*2+1)) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      float total;
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_f ( himage, i, j,
                           0.25F*(gan_image_get_pix_gl_f(image,i*2,j*2) +
                                  gan_image_get_pix_gl_f(image,i*2,j*2+1) +
                                  gan_image_get_pix_gl_f(image,i*2+1,j*2) +
                                  gan_image_get_pix_gl_f(image,i*2+1,j*2+1)) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; total = 0.0F;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  total += gan_image_get_pix_gl_f(image,i*2,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  total += gan_image_get_pix_gl_f(image,i*2,j*2+1);
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  total += gan_image_get_pix_gl_f(image,i*2+1,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  total += gan_image_get_pix_gl_f(image,i*2+1,j*2+1);
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                     gan_image_set_pix_gl_f ( himage, i, j,
                                              total/((float)num) );
                  else /* average_type == GAN_AVERAGE_ALL */
                     gan_image_set_pix_gl_f ( himage, i, j, 0.25F*total );

                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_gl_d ( Gan_Image *image, Gan_Image *mask,
                   Gan_ImagePyramidAverage average_type,
                   unsigned no_neighbours,
                   Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            gan_image_set_pix_gl_d ( himage, i, j,
                            0.25*(gan_image_get_pix_gl_d(image,i*2,j*2) +
                                  gan_image_get_pix_gl_d(image,i*2,j*2+1) +
                                  gan_image_get_pix_gl_d(image,i*2+1,j*2) +
                                  gan_image_get_pix_gl_d(image,i*2+1,j*2+1)) );
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_d ( himage, i, j,
                            0.25*(gan_image_get_pix_gl_d(image,i*2,j*2) +
                                  gan_image_get_pix_gl_d(image,i*2,j*2+1) +
                                  gan_image_get_pix_gl_d(image,i*2+1,j*2) +
                                  gan_image_get_pix_gl_d(image,i*2+1,j*2+1)) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      double total;
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               gan_image_set_pix_gl_d ( himage, i, j,
                            0.25*(gan_image_get_pix_gl_d(image,i*2,j*2) +
                                  gan_image_get_pix_gl_d(image,i*2,j*2+1) +
                                  gan_image_get_pix_gl_d(image,i*2+1,j*2) +
                                  gan_image_get_pix_gl_d(image,i*2+1,j*2+1)) );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; total = 0.0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  total += gan_image_get_pix_gl_d(image,i*2,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  total += gan_image_get_pix_gl_d(image,i*2,j*2+1);
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  total += gan_image_get_pix_gl_d(image,i*2+1,j*2);
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  total += gan_image_get_pix_gl_d(image,i*2+1,j*2+1);
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                     gan_image_set_pix_gl_d ( himage, i, j,
                                              total/((double)num) );
                  else /* average_type == GAN_AVERAGE_ALL */
                     gan_image_set_pix_gl_d ( himage, i, j, 0.25*total );

                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_rgb_f ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBPixel_f pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgb_f ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgb_f ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2+1 );
            pix.R = 0.25F*(pix1.R + pix2.R + pix3.R + pix4.R);
            pix.G = 0.25F*(pix1.G + pix2.G + pix3.G + pix4.G);
            pix.B = 0.25F*(pix1.B + pix2.B + pix3.B + pix4.B);
            gan_image_set_pix_rgb_f ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgb_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2+1 );
               pix.R = 0.25F*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25F*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25F*(pix1.B + pix2.B + pix3.B + pix4.B);
               gan_image_set_pix_rgb_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgb_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2+1 );
               pix.R = 0.25F*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25F*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25F*(pix1.B + pix2.B + pix3.B + pix4.B);
               gan_image_set_pix_rgb_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.R = pix.G = pix.B = 0.0F;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgb_f ( image, i*2, j*2 );
                  pix.R += pix1.R;
                  pix.G += pix1.G;
                  pix.B += pix1.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgb_f ( image, i*2, j*2+1 );
                  pix.R += pix2.R;
                  pix.G += pix2.G;
                  pix.B += pix2.B;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2 );
                  pix.R += pix3.R;
                  pix.G += pix3.G;
                  pix.B += pix3.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgb_f ( image, i*2+1, j*2+1 );
                  pix.R += pix4.R;
                  pix.G += pix4.G;
                  pix.B += pix4.B;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     float fnum = (float)num;

                     pix.R /= fnum;
                     pix.G /= fnum;
                     pix.B /= fnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R *= 0.25F;
                     pix.G *= 0.25F;
                     pix.B *= 0.25F;
                  }

                  gan_image_set_pix_rgb_f ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_rgb_d ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBPixel_d pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgb_d ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgb_d ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2+1 );
            pix.R = 0.25*(pix1.R + pix2.R + pix3.R + pix4.R);
            pix.G = 0.25*(pix1.G + pix2.G + pix3.G + pix4.G);
            pix.B = 0.25*(pix1.B + pix2.B + pix3.B + pix4.B);
            gan_image_set_pix_rgb_d ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgb_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2+1 );
               pix.R = 0.25*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25*(pix1.B + pix2.B + pix3.B + pix4.B);
               gan_image_set_pix_rgb_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgb_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2+1 );
               pix.R = 0.25*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25*(pix1.B + pix2.B + pix3.B + pix4.B);
               gan_image_set_pix_rgb_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.R = pix.G = pix.B = 0.0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgb_d ( image, i*2, j*2 );
                  pix.R += pix1.R;
                  pix.G += pix1.G;
                  pix.B += pix1.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgb_d ( image, i*2, j*2+1 );
                  pix.R += pix2.R;
                  pix.G += pix2.G;
                  pix.B += pix2.B;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2 );
                  pix.R += pix3.R;
                  pix.G += pix3.G;
                  pix.B += pix3.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgb_d ( image, i*2+1, j*2+1 );
                  pix.R += pix4.R;
                  pix.G += pix4.G;
                  pix.B += pix4.B;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     double dnum = (double)num;

                     pix.R /= dnum;
                     pix.G /= dnum;
                     pix.B /= dnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R *= 0.25;
                     pix.G *= 0.25;
                     pix.B *= 0.25;
                  }

                  gan_image_set_pix_rgb_d ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_rgb_uc ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBPixel_uc pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgb_uc ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgb_uc ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2+1 );
            pix.R = (unsigned char)
                    (((unsigned) pix1.R + (unsigned) pix2.R +
                      (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
            pix.G = (unsigned char)
                    (((unsigned) pix1.G + (unsigned) pix2.G +
                      (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
            pix.B = (unsigned char)
                    (((unsigned) pix1.B + (unsigned) pix2.B +
                      (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
            gan_image_set_pix_rgb_uc ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_uc ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgb_uc ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2+1);
               pix.R = (unsigned char)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned char)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned char)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               gan_image_set_pix_rgb_uc ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;
      Gan_RGBPixel_ui total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_uc ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgb_uc ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2+1);
               pix.R = (unsigned char)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned char)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned char)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               gan_image_set_pix_rgb_uc ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.R = total.G = total.B = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgb_uc ( image, i*2, j*2 );
                  total.R += (unsigned)pix1.R;
                  total.G += (unsigned)pix1.G;
                  total.B += (unsigned)pix1.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgb_uc ( image, i*2, j*2+1 );
                  total.R += (unsigned)pix2.R;
                  total.G += (unsigned)pix2.G;
                  total.B += (unsigned)pix2.B;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2 );
                  total.R += (unsigned)pix3.R;
                  total.G += (unsigned)pix3.G;
                  total.B += (unsigned)pix3.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgb_uc ( image, i*2+1, j*2+1 );
                  total.R += (unsigned)pix4.R;
                  total.G += (unsigned)pix4.G;
                  total.B += (unsigned)pix4.B;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (unsigned char) ((total.R + num/2)/num);
                     pix.G = (unsigned char) ((total.G + num/2)/num);
                     pix.B = (unsigned char) ((total.B + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R = (unsigned char) ((total.R + 2)/4);
                     pix.G = (unsigned char) ((total.G + 2)/4);
                     pix.B = (unsigned char) ((total.B + 2)/4);
                  }

                  gan_image_set_pix_rgb_uc ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

#if (SIZEOF_SHORT < SIZEOF_INT)
static Gan_Bool
 halve_size_rgb_us ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBPixel_us pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgb_us ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgb_us ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2+1 );
            pix.R = (unsigned short)
                    (((unsigned) pix1.R + (unsigned) pix2.R +
                      (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
            pix.G = (unsigned short)
                    (((unsigned) pix1.G + (unsigned) pix2.G +
                      (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
            pix.B = (unsigned short)
                    (((unsigned) pix1.B + (unsigned) pix2.B +
                      (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
            gan_image_set_pix_rgb_us ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_us ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgb_us ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2+1);
               pix.R = (unsigned short)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned short)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned short)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               gan_image_set_pix_rgb_us ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;
      Gan_RGBPixel_ui total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_us ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgb_us ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2+1);
               pix.R = (unsigned short)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned short)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned short)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               gan_image_set_pix_rgb_us ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.R = total.G = total.B = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgb_us ( image, i*2, j*2 );
                  total.R += (unsigned)pix1.R;
                  total.G += (unsigned)pix1.G;
                  total.B += (unsigned)pix1.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgb_us ( image, i*2, j*2+1 );
                  total.R += (unsigned)pix2.R;
                  total.G += (unsigned)pix2.G;
                  total.B += (unsigned)pix2.B;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2 );
                  total.R += (unsigned)pix3.R;
                  total.G += (unsigned)pix3.G;
                  total.B += (unsigned)pix3.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgb_us ( image, i*2+1, j*2+1 );
                  total.R += (unsigned)pix4.R;
                  total.G += (unsigned)pix4.G;
                  total.B += (unsigned)pix4.B;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (unsigned short) ((total.R + num/2)/num);
                     pix.G = (unsigned short) ((total.G + num/2)/num);
                     pix.B = (unsigned short) ((total.B + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R = (unsigned short) ((total.R + 2)/4);
                     pix.G = (unsigned short) ((total.G + 2)/4);
                     pix.B = (unsigned short) ((total.B + 2)/4);
                  }

                  gan_image_set_pix_rgb_us ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#else
#error "Unsupported size combination"
#endif /* #if (SIZEOF_SHORT < SIZEOF_INT) */

#if (SIZEOF_INT == SIZEOF_LONG)
static Gan_Bool
 halve_size_rgb_ui ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBPixel_ui pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1 );
            pix.R = pix1.R/4 + pix2.R/4 + pix3.R/4 + pix4.R/4;
            pix.G = pix1.G/4 + pix2.G/4 + pix3.G/4 + pix4.G/4;
            pix.B = pix1.B/4 + pix2.B/4 + pix3.B/4 + pix4.B/4;
            gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1 );
               pix.R = pix1.R/4 + pix2.R/4 + pix3.R/4 + pix4.R/4;
               pix.G = pix1.G/4 + pix2.G/4 + pix3.G/4 + pix4.G/4;
               pix.B = pix1.B/4 + pix2.B/4 + pix3.B/4 + pix4.B/4;
               gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1 );
               pix.R = pix1.R/4 + pix2.R/4 + pix3.R/4 + pix4.R/4;
               pix.G = pix1.G/4 + pix2.G/4 + pix3.G/4 + pix4.G/4;
               pix.B = pix1.B/4 + pix2.B/4 + pix3.B/4 + pix4.B/4;
               gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = pix.R = pix.G = pix.B = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgb_ui ( image, i*2, j*2 );
                  pix.R += pix1.R/4;
                  pix.G += pix1.G/4;
                  pix.B += pix1.B/4;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgb_ui ( image, i*2, j*2+1 );
                  pix.R += pix2.R/4;
                  pix.G += pix2.G/4;
                  pix.B += pix2.B/4;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2 );
                  pix.R += pix3.R/4;
                  pix.G += pix3.G/4;
                  pix.B += pix3.B/4;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1 );
                  pix.R += pix4.R/4;
                  pix.G += pix4.G/4;
                  pix.B += pix4.B/4;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (pix.R/num)*4;
                     pix.G = (pix.G/num)*4;
                     pix.B = (pix.B/num)*4;
                  }

                  gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#else /* (SIZEOF_INT < SIZEOF_LONG) */
static Gan_Bool
 halve_size_rgb_ui ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBPixel_ui pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1 );
            pix.R = (unsigned int)
                    (((unsigned long) pix1.R + (unsigned long) pix2.R +
                      (unsigned long) pix3.R + (unsigned long) pix4.R + 2)/4);
            pix.G = (unsigned int)
                    (((unsigned long) pix1.G + (unsigned long) pix2.G +
                      (unsigned long) pix3.G + (unsigned long) pix4.G + 2)/4);
            pix.B = (unsigned int)
                    (((unsigned long) pix1.B + (unsigned long) pix2.B +
                      (unsigned long) pix3.B + (unsigned long) pix4.B + 2)/4);
            gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1);
               pix.R = (unsigned int)
                     (((unsigned long) pix1.R + (unsigned long) pix2.R +
                       (unsigned long) pix3.R + (unsigned long) pix4.R + 2)/4);
               pix.G = (unsigned int)
                     (((unsigned long) pix1.G + (unsigned long) pix2.G +
                       (unsigned long) pix3.G + (unsigned long) pix4.G + 2)/4);
               pix.B = (unsigned int)
                     (((unsigned long) pix1.B + (unsigned long) pix2.B +
                       (unsigned long) pix3.B + (unsigned long) pix4.B + 2)/4);
               gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned long num;
      Gan_RGBPixel_ul total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgb_ui ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1);
               pix.R = (unsigned int)
                     (((unsigned long) pix1.R + (unsigned long) pix2.R +
                       (unsigned long) pix3.R + (unsigned long) pix4.R + 2)/4);
               pix.G = (unsigned int)
                     (((unsigned long) pix1.G + (unsigned long) pix2.G +
                       (unsigned long) pix3.G + (unsigned long) pix4.G + 2)/4);
               pix.B = (unsigned int)
                     (((unsigned long) pix1.B + (unsigned long) pix2.B +
                       (unsigned long) pix3.B + (unsigned long) pix4.B + 2)/4);
               gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.R = total.G = total.B = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgb_ui ( image, i*2, j*2 );
                  total.R += (unsigned long)pix1.R;
                  total.G += (unsigned long)pix1.G;
                  total.B += (unsigned long)pix1.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgb_ui ( image, i*2, j*2+1 );
                  total.R += (unsigned long)pix2.R;
                  total.G += (unsigned long)pix2.G;
                  total.B += (unsigned long)pix2.B;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2 );
                  total.R += (unsigned long)pix3.R;
                  total.G += (unsigned long)pix3.G;
                  total.B += (unsigned long)pix3.B;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgb_ui ( image, i*2+1, j*2+1 );
                  total.R += (unsigned long)pix4.R;
                  total.G += (unsigned long)pix4.G;
                  total.B += (unsigned long)pix4.B;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (unsigned) ((total.R + num/2)/num);
                     pix.G = (unsigned) ((total.G + num/2)/num);
                     pix.B = (unsigned) ((total.B + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R = (unsigned) ((total.R + 2)/4);
                     pix.G = (unsigned) ((total.G + 2)/4);
                     pix.B = (unsigned) ((total.B + 2)/4);
                  }

                  gan_image_set_pix_rgb_ui ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#endif /* #if (SIZEOF_INT == SIZEOF_LONG) */

static Gan_Bool
 halve_size_rgba_f ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBAPixel_f pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgba_f ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgba_f ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2+1 );
            pix.R = 0.25F*(pix1.R + pix2.R + pix3.R + pix4.R);
            pix.G = 0.25F*(pix1.G + pix2.G + pix3.G + pix4.G);
            pix.B = 0.25F*(pix1.B + pix2.B + pix3.B + pix4.B);
            pix.A = 0.25F*(pix1.A + pix2.A + pix3.A + pix4.A);
            gan_image_set_pix_rgba_f ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgba_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2+1 );
               pix.R = 0.25F*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25F*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25F*(pix1.B + pix2.B + pix3.B + pix4.B);
               pix.A = 0.25F*(pix1.A + pix2.A + pix3.A + pix4.A);
               gan_image_set_pix_rgba_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgba_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2+1 );
               pix.R = 0.25F*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25F*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25F*(pix1.B + pix2.B + pix3.B + pix4.B);
               pix.A = 0.25F*(pix1.A + pix2.A + pix3.A + pix4.A);
               gan_image_set_pix_rgba_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.R = pix.G = pix.B = pix.A = 0.0F;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgba_f ( image, i*2, j*2 );
                  pix.R += pix1.R;
                  pix.G += pix1.G;
                  pix.B += pix1.B;
                  pix.A += pix1.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgba_f ( image, i*2, j*2+1 );
                  pix.R += pix2.R;
                  pix.G += pix2.G;
                  pix.B += pix2.B;
                  pix.A += pix2.A;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2 );
                  pix.R += pix3.R;
                  pix.G += pix3.G;
                  pix.B += pix3.B;
                  pix.A += pix3.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgba_f ( image, i*2+1, j*2+1 );
                  pix.R += pix4.R;
                  pix.G += pix4.G;
                  pix.B += pix4.B;
                  pix.A += pix4.A;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     float fnum = (float)num;

                     pix.R /= fnum;
                     pix.G /= fnum;
                     pix.B /= fnum;
                     pix.A /= fnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R *= 0.25F;
                     pix.G *= 0.25F;
                     pix.B *= 0.25F;
                     pix.A *= 0.25F;
                  }

                  gan_image_set_pix_rgba_f ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_rgba_d ( Gan_Image *image, Gan_Image *mask,
                    Gan_ImagePyramidAverage average_type,
                    unsigned no_neighbours,
                    Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBAPixel_d pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgba_d ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgba_d ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2+1 );
            pix.R = 0.25*(pix1.R + pix2.R + pix3.R + pix4.R);
            pix.G = 0.25*(pix1.G + pix2.G + pix3.G + pix4.G);
            pix.B = 0.25*(pix1.B + pix2.B + pix3.B + pix4.B);
            pix.A = 0.25*(pix1.A + pix2.A + pix3.A + pix4.A);
            gan_image_set_pix_rgba_d ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgba_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2+1 );
               pix.R = 0.25*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25*(pix1.B + pix2.B + pix3.B + pix4.B);
               pix.A = 0.25*(pix1.A + pix2.A + pix3.A + pix4.A);
               gan_image_set_pix_rgba_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgba_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2+1 );
               pix.R = 0.25*(pix1.R + pix2.R + pix3.R + pix4.R);
               pix.G = 0.25*(pix1.G + pix2.G + pix3.G + pix4.G);
               pix.B = 0.25*(pix1.B + pix2.B + pix3.B + pix4.B);
               pix.A = 0.25*(pix1.A + pix2.A + pix3.A + pix4.A);
               gan_image_set_pix_rgba_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.R = pix.G = pix.B = pix.A = 0.0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgba_d ( image, i*2, j*2 );
                  pix.R += pix1.R;
                  pix.G += pix1.G;
                  pix.B += pix1.B;
                  pix.A += pix1.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgba_d ( image, i*2, j*2+1 );
                  pix.R += pix2.R;
                  pix.G += pix2.G;
                  pix.B += pix2.B;
                  pix.A += pix2.A;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2 );
                  pix.R += pix3.R;
                  pix.G += pix3.G;
                  pix.B += pix3.B;
                  pix.A += pix3.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgba_d ( image, i*2+1, j*2+1 );
                  pix.R += pix4.R;
                  pix.G += pix4.G;
                  pix.B += pix4.B;
                  pix.A += pix4.A;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     double dnum = (double)num;

                     pix.R /= dnum;
                     pix.G /= dnum;
                     pix.B /= dnum;
                     pix.A /= dnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R *= 0.25;
                     pix.G *= 0.25;
                     pix.B *= 0.25;
                     pix.A *= 0.25;
                  }

                  gan_image_set_pix_rgba_d ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_rgba_uc ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBAPixel_uc pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgba_uc ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgba_uc ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2+1 );
            pix.R = (unsigned char)
                    (((unsigned) pix1.R + (unsigned) pix2.R +
                      (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
            pix.G = (unsigned char)
                    (((unsigned) pix1.G + (unsigned) pix2.G +
                      (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
            pix.B = (unsigned char)
                    (((unsigned) pix1.B + (unsigned) pix2.B +
                      (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
            pix.A = (unsigned char)
                    (((unsigned) pix1.A + (unsigned) pix2.A +
                      (unsigned) pix3.A + (unsigned) pix4.A + 2)/4);
            gan_image_set_pix_rgba_uc ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_uc ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgba_uc ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2+1);
               pix.R = (unsigned char)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned char)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned char)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               pix.A = (unsigned char)
                       (((unsigned) pix1.A + (unsigned) pix2.A +
                         (unsigned) pix3.A + (unsigned) pix4.A + 2)/4);
               gan_image_set_pix_rgba_uc ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;
      Gan_RGBAPixel_ui total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_uc ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgba_uc ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2+1);
               pix.R = (unsigned char)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned char)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned char)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               pix.A = (unsigned char)
                       (((unsigned) pix1.A + (unsigned) pix2.A +
                         (unsigned) pix3.A + (unsigned) pix4.A + 2)/4);
               gan_image_set_pix_rgba_uc ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.R = total.G = total.B = total.A = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgba_uc ( image, i*2, j*2 );
                  total.R += (unsigned)pix1.R;
                  total.G += (unsigned)pix1.G;
                  total.B += (unsigned)pix1.B;
                  total.A += (unsigned)pix1.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgba_uc ( image, i*2, j*2+1 );
                  total.R += (unsigned)pix2.R;
                  total.G += (unsigned)pix2.G;
                  total.B += (unsigned)pix2.B;
                  total.A += (unsigned)pix2.A;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2 );
                  total.R += (unsigned)pix3.R;
                  total.G += (unsigned)pix3.G;
                  total.B += (unsigned)pix3.B;
                  total.A += (unsigned)pix3.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgba_uc ( image, i*2+1, j*2+1 );
                  total.R += (unsigned)pix4.R;
                  total.G += (unsigned)pix4.G;
                  total.B += (unsigned)pix4.B;
                  total.A += (unsigned)pix4.A;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (unsigned char) ((total.R + num/2)/num);
                     pix.G = (unsigned char) ((total.G + num/2)/num);
                     pix.B = (unsigned char) ((total.B + num/2)/num);
                     pix.A = (unsigned char) ((total.A + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R = (unsigned char) ((total.R + 2)/4);
                     pix.G = (unsigned char) ((total.G + 2)/4);
                     pix.B = (unsigned char) ((total.B + 2)/4);
                     pix.A = (unsigned char) ((total.A + 2)/4);
                  }

                  gan_image_set_pix_rgba_uc ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

#if (SIZEOF_SHORT < SIZEOF_INT)
static Gan_Bool
 halve_size_rgba_us ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBAPixel_us pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgba_us ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgba_us ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2+1 );
            pix.R = (unsigned short)
                    (((unsigned) pix1.R + (unsigned) pix2.R +
                      (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
            pix.G = (unsigned short)
                    (((unsigned) pix1.G + (unsigned) pix2.G +
                      (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
            pix.B = (unsigned short)
                    (((unsigned) pix1.B + (unsigned) pix2.B +
                      (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
            pix.A = (unsigned short)
                    (((unsigned) pix1.A + (unsigned) pix2.A +
                      (unsigned) pix3.A + (unsigned) pix4.A + 2)/4);
            gan_image_set_pix_rgba_us ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_us ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgba_us ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2+1);
               pix.R = (unsigned short)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned short)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned short)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               pix.A = (unsigned short)
                       (((unsigned) pix1.A + (unsigned) pix2.A +
                         (unsigned) pix3.A + (unsigned) pix4.A + 2)/4);
               gan_image_set_pix_rgba_us ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;
      Gan_RGBAPixel_ui total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_us ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgba_us ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2+1);
               pix.R = (unsigned short)
                       (((unsigned) pix1.R + (unsigned) pix2.R +
                         (unsigned) pix3.R + (unsigned) pix4.R + 2)/4);
               pix.G = (unsigned short)
                       (((unsigned) pix1.G + (unsigned) pix2.G +
                         (unsigned) pix3.G + (unsigned) pix4.G + 2)/4);
               pix.B = (unsigned short)
                       (((unsigned) pix1.B + (unsigned) pix2.B +
                         (unsigned) pix3.B + (unsigned) pix4.B + 2)/4);
               pix.A = (unsigned short)
                       (((unsigned) pix1.A + (unsigned) pix2.A +
                         (unsigned) pix3.A + (unsigned) pix4.A + 2)/4);
               gan_image_set_pix_rgba_us ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.R = total.G = total.B = total.A = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgba_us ( image, i*2, j*2 );
                  total.R += (unsigned)pix1.R;
                  total.G += (unsigned)pix1.G;
                  total.B += (unsigned)pix1.B;
                  total.A += (unsigned)pix1.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgba_us ( image, i*2, j*2+1 );
                  total.R += (unsigned)pix2.R;
                  total.G += (unsigned)pix2.G;
                  total.B += (unsigned)pix2.B;
                  total.A += (unsigned)pix2.A;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2 );
                  total.R += (unsigned)pix3.R;
                  total.G += (unsigned)pix3.G;
                  total.B += (unsigned)pix3.B;
                  total.A += (unsigned)pix3.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgba_us ( image, i*2+1, j*2+1 );
                  total.R += (unsigned)pix4.R;
                  total.G += (unsigned)pix4.G;
                  total.B += (unsigned)pix4.B;
                  total.A += (unsigned)pix4.A;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (unsigned short) ((total.R + num/2)/num);
                     pix.G = (unsigned short) ((total.G + num/2)/num);
                     pix.B = (unsigned short) ((total.B + num/2)/num);
                     pix.A = (unsigned short) ((total.A + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R = (unsigned short) ((total.R + 2)/4);
                     pix.G = (unsigned short) ((total.G + 2)/4);
                     pix.B = (unsigned short) ((total.B + 2)/4);
                     pix.A = (unsigned short) ((total.A + 2)/4);
                  }

                  gan_image_set_pix_rgba_us ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#else
#error "Unsupported size combination"
#endif /* #if (SIZEOF_SHORT < SIZEOF_INT) */

#if (SIZEOF_INT == SIZEOF_LONG)
static Gan_Bool
 halve_size_rgba_ui ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBAPixel_ui pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1 );
            pix.R = pix1.R/4 + pix2.R/4 + pix3.R/4 + pix4.R/4;
            pix.G = pix1.G/4 + pix2.G/4 + pix3.G/4 + pix4.G/4;
            pix.B = pix1.B/4 + pix2.B/4 + pix3.B/4 + pix4.B/4;
            pix.A = pix1.A/4 + pix2.A/4 + pix3.A/4 + pix4.A/4;
            gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1 );
               pix.R = pix1.R/4 + pix2.R/4 + pix3.R/4 + pix4.R/4;
               pix.G = pix1.G/4 + pix2.G/4 + pix3.G/4 + pix4.G/4;
               pix.B = pix1.B/4 + pix2.B/4 + pix3.B/4 + pix4.B/4;
               pix.A = pix1.A/4 + pix2.A/4 + pix3.A/4 + pix4.A/4;
               gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1 );
               pix.R = pix1.R/4 + pix2.R/4 + pix3.R/4 + pix4.R/4;
               pix.G = pix1.G/4 + pix2.G/4 + pix3.G/4 + pix4.G/4;
               pix.B = pix1.B/4 + pix2.B/4 + pix3.B/4 + pix4.B/4;
               pix.A = pix1.A/4 + pix2.A/4 + pix3.A/4 + pix4.A/4;
               gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = pix.R = pix.G = pix.B = pix.A = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgba_ui ( image, i*2, j*2 );
                  pix.R += pix1.R/4;
                  pix.G += pix1.G/4;
                  pix.B += pix1.B/4;
                  pix.A += pix1.A/4;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgba_ui ( image, i*2, j*2+1 );
                  pix.R += pix2.R/4;
                  pix.G += pix2.G/4;
                  pix.B += pix2.B/4;
                  pix.A += pix2.A/4;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2 );
                  pix.R += pix3.R/4;
                  pix.G += pix3.G/4;
                  pix.B += pix3.B/4;
                  pix.A += pix3.A/4;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1 );
                  pix.R += pix4.R/4;
                  pix.G += pix4.G/4;
                  pix.B += pix4.B/4;
                  pix.A += pix4.A/4;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (pix.R/num)*4;
                     pix.G = (pix.G/num)*4;
                     pix.B = (pix.B/num)*4;
                     pix.A = (pix.A/num)*4;
                  }

                  gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#else /* (SIZEOF_INT < SIZEOF_LONG) */
static Gan_Bool
 halve_size_rgba_ui ( Gan_Image *image, Gan_Image *mask,
                     Gan_ImagePyramidAverage average_type,
                     unsigned no_neighbours,
                     Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_RGBAPixel_ui pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1 );
            pix.R = (unsigned int)
                    (((unsigned long) pix1.R + (unsigned long) pix2.R +
                      (unsigned long) pix3.R + (unsigned long) pix4.R + 2)/4);
            pix.G = (unsigned int)
                    (((unsigned long) pix1.G + (unsigned long) pix2.G +
                      (unsigned long) pix3.G + (unsigned long) pix4.G + 2)/4);
            pix.B = (unsigned int)
                    (((unsigned long) pix1.B + (unsigned long) pix2.B +
                      (unsigned long) pix3.B + (unsigned long) pix4.B + 2)/4);
            pix.A = (unsigned int)
                    (((unsigned long) pix1.A + (unsigned long) pix2.A +
                      (unsigned long) pix3.A + (unsigned long) pix4.A + 2)/4);
            gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1);
               pix.R = (unsigned int)
                     (((unsigned long) pix1.R + (unsigned long) pix2.R +
                       (unsigned long) pix3.R + (unsigned long) pix4.R + 2)/4);
               pix.G = (unsigned int)
                     (((unsigned long) pix1.G + (unsigned long) pix2.G +
                       (unsigned long) pix3.G + (unsigned long) pix4.G + 2)/4);
               pix.B = (unsigned int)
                     (((unsigned long) pix1.B + (unsigned long) pix2.B +
                       (unsigned long) pix3.B + (unsigned long) pix4.B + 2)/4);
               pix.A = (unsigned int)
                     (((unsigned long) pix1.A + (unsigned long) pix2.A +
                       (unsigned long) pix3.A + (unsigned long) pix4.A + 2)/4);
               gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned long num;
      Gan_RGBAPixel_ul total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2  );
               pix2 = gan_image_get_pix_rgba_ui ( image, i*2,   j*2+1);
               pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2  );
               pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1);
               pix.R = (unsigned int)
                     (((unsigned long) pix1.R + (unsigned long) pix2.R +
                       (unsigned long) pix3.R + (unsigned long) pix4.R + 2)/4);
               pix.G = (unsigned int)
                     (((unsigned long) pix1.G + (unsigned long) pix2.G +
                       (unsigned long) pix3.G + (unsigned long) pix4.G + 2)/4);
               pix.B = (unsigned int)
                     (((unsigned long) pix1.B + (unsigned long) pix2.B +
                       (unsigned long) pix3.B + (unsigned long) pix4.B + 2)/4);
               pix.A = (unsigned int)
                     (((unsigned long) pix1.A + (unsigned long) pix2.A +
                       (unsigned long) pix3.A + (unsigned long) pix4.A + 2)/4);
               gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.R = total.G = total.B = total.A = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_rgba_ui ( image, i*2, j*2 );
                  total.R += (unsigned long)pix1.R;
                  total.G += (unsigned long)pix1.G;
                  total.B += (unsigned long)pix1.B;
                  total.A += (unsigned long)pix1.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_rgba_ui ( image, i*2, j*2+1 );
                  total.R += (unsigned long)pix2.R;
                  total.G += (unsigned long)pix2.G;
                  total.B += (unsigned long)pix2.B;
                  total.A += (unsigned long)pix2.A;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2 );
                  total.R += (unsigned long)pix3.R;
                  total.G += (unsigned long)pix3.G;
                  total.B += (unsigned long)pix3.B;
                  total.A += (unsigned long)pix3.A;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_rgba_ui ( image, i*2+1, j*2+1 );
                  total.R += (unsigned long)pix4.R;
                  total.G += (unsigned long)pix4.G;
                  total.B += (unsigned long)pix4.B;
                  total.A += (unsigned long)pix4.A;
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.R = (unsigned) ((total.R + num/2)/num);
                     pix.G = (unsigned) ((total.G + num/2)/num);
                     pix.B = (unsigned) ((total.B + num/2)/num);
                     pix.A = (unsigned) ((total.A + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.R = (unsigned) ((total.R + 2)/4);
                     pix.G = (unsigned) ((total.G + 2)/4);
                     pix.B = (unsigned) ((total.B + 2)/4);
                     pix.A = (unsigned) ((total.A + 2)/4);
                  }

                  gan_image_set_pix_rgba_ui ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}
#endif /* #if (SIZEOF_INT == SIZEOF_LONG) */

static Gan_Bool
 halve_size_vfield2D_s ( Gan_Image *image, Gan_Image *mask,
                         Gan_ImagePyramidAverage average_type,
                         unsigned no_neighbours,
                         Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_Vector2_s pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_vfield2D_s ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_vfield2D_s ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2+1 );
            pix.x = (short) (((int) pix1.x + (int) pix2.x +
                              (int) pix3.x + (int) pix4.x + 2)/4);
            pix.y = (short) (((int) pix1.y + (int) pix2.y +
                              (int) pix3.y + (int) pix4.y + 2)/4);
            gan_image_set_pix_vfield2D_s ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield2D_s ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield2D_s ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2+1 );
               pix.x = (short) (((int) pix1.x + (int) pix2.x +
                                 (int) pix3.x + (int) pix4.x + 2)/4);
               pix.y = (short) (((int) pix1.y + (int) pix2.y +
                                 (int) pix3.y + (int) pix4.y + 2)/4);
               gan_image_set_pix_vfield2D_s ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      int num;
      Gan_Vector2_i total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield2D_s ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield2D_s ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2+1 );
               pix.x = (short) (((int) pix1.x + (int) pix2.x +
                                 (int) pix3.x + (int) pix4.x + 2)/4);
               pix.y = (short) (((int) pix1.y + (int) pix2.y +
                                 (int) pix3.y + (int) pix4.y + 2)/4);
               gan_image_set_pix_vfield2D_s ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.x = total.y = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_vfield2D_s ( image, i*2, j*2 );
                  total.x += (int)pix1.x;
                  total.y += (int)pix1.y;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_vfield2D_s ( image, i*2, j*2+1 );
                  total.x += (int)pix2.x;
                  total.y += (int)pix2.y;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2 );
                  total.x += (int)pix3.x;
                  total.y += (int)pix3.y;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_vfield2D_s ( image, i*2+1, j*2+1 );
                  total.x += (int)pix4.x;
                  total.y += (int)pix4.y;
                  num++;
               }

               if ( (unsigned)num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.x = (short) ((total.x + num/2)/num);
                     pix.y = (short) ((total.y + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.x = (short) ((total.x + 2)/4);
                     pix.y = (short) ((total.y + 2)/4);
                  }

                  gan_image_set_pix_vfield2D_s ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_vfield2D_f ( Gan_Image *image, Gan_Image *mask,
                         Gan_ImagePyramidAverage average_type,
                         unsigned no_neighbours,
                         Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_Vector2_f pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_vfield2D_f ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_vfield2D_f ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2+1 );
            pix.x = 0.25F*(pix1.x + pix2.x + pix3.x + pix4.x);
            pix.y = 0.25F*(pix1.y + pix2.y + pix3.y + pix4.y);
            gan_image_set_pix_vfield2D_f ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield2D_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield2D_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2+1 );
               pix.x = 0.25F*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25F*(pix1.y + pix2.y + pix3.y + pix4.y);
               gan_image_set_pix_vfield2D_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      float num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield2D_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield2D_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2+1 );
               pix.x = 0.25F*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25F*(pix1.y + pix2.y + pix3.y + pix4.y);
               gan_image_set_pix_vfield2D_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.x = pix.y = 0.0F;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_vfield2D_f ( image, i*2, j*2 );
                  (void)gan_vec2f_increment ( &pix, &pix1 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_vfield2D_f ( image, i*2, j*2+1 );
                  (void)gan_vec2f_increment ( &pix, &pix2 );
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2 );
                  (void)gan_vec2f_increment ( &pix, &pix3 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_vfield2D_f ( image, i*2+1, j*2+1 );
                  (void)gan_vec2f_increment ( &pix, &pix4 );
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     float fnum = (float)num;

                     pix.x /= fnum;
                     pix.y /= fnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.x *= 0.25F;
                     pix.y *= 0.25F;
                  }

                  gan_image_set_pix_vfield2D_f ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_vfield2D_d ( Gan_Image *image, Gan_Image *mask,
                         Gan_ImagePyramidAverage average_type,
                         unsigned no_neighbours,
                         Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_Vector2_d pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_vfield2D_d ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_vfield2D_d ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2+1 );
            pix.x = 0.25*(pix1.x + pix2.x + pix3.x + pix4.x);
            pix.y = 0.25*(pix1.y + pix2.y + pix3.y + pix4.y);
            gan_image_set_pix_vfield2D_d ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield2D_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield2D_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2+1 );
               pix.x = 0.25*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25*(pix1.y + pix2.y + pix3.y + pix4.y);
               gan_image_set_pix_vfield2D_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield2D_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield2D_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2+1 );
               pix.x = 0.25*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25*(pix1.y + pix2.y + pix3.y + pix4.y);
               gan_image_set_pix_vfield2D_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.x = pix.y = 0.0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_vfield2D_d ( image, i*2, j*2 );
                  (void)gan_vec2_increment ( &pix, &pix1 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_vfield2D_d ( image, i*2, j*2+1 );
                  (void)gan_vec2_increment ( &pix, &pix2 );
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2 );
                  (void)gan_vec2_increment ( &pix, &pix3 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_vfield2D_d ( image, i*2+1, j*2+1 );
                  (void)gan_vec2_increment ( &pix, &pix4 );
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     double dnum = (double)num;

                     pix.x /= dnum;
                     pix.y /= dnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.x *= 0.25;
                     pix.y *= 0.25;
                  }

                  gan_image_set_pix_vfield2D_d ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_vfield3D_s ( Gan_Image *image, Gan_Image *mask,
                         Gan_ImagePyramidAverage average_type,
                         unsigned no_neighbours,
                         Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_Vector3_s pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_vfield3D_s ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_vfield3D_s ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2+1 );
            pix.x = (short) (((int) pix1.x + (int) pix2.x +
                              (int) pix3.x + (int) pix4.x + 2)/4);
            pix.y = (short) (((int) pix1.y + (int) pix2.y +
                              (int) pix3.y + (int) pix4.y + 2)/4);
            pix.z = (short) (((int) pix1.z + (int) pix2.z +
                              (int) pix3.z + (int) pix4.z + 2)/4);
            gan_image_set_pix_vfield3D_s ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield3D_s ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield3D_s ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2+1 );
               pix.x = (short) (((int) pix1.x + (int) pix2.x +
                                 (int) pix3.x + (int) pix4.x + 2)/4);
               pix.y = (short) (((int) pix1.y + (int) pix2.y +
                                 (int) pix3.y + (int) pix4.y + 2)/4);
               pix.z = (short) (((int) pix1.z + (int) pix2.z +
                                 (int) pix3.z + (int) pix4.z + 2)/4);
               gan_image_set_pix_vfield3D_s ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      int num;
      Gan_Vector3_i total;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield3D_s ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield3D_s ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2+1 );
               pix.x = (short) (((int) pix1.x + (int) pix2.x +
                                 (int) pix3.x + (int) pix4.x + 2)/4);
               pix.y = (short) (((int) pix1.y + (int) pix2.y +
                                 (int) pix3.y + (int) pix4.y + 2)/4);
               pix.z = (short) (((int) pix1.z + (int) pix2.z +
                                 (int) pix3.z + (int) pix4.z + 2)/4);
               gan_image_set_pix_vfield3D_s ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = total.x = total.y = total.z = 0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_vfield3D_s ( image, i*2, j*2 );
                  total.x += (int)pix1.x;
                  total.y += (int)pix1.y;
                  total.z += (int)pix1.z;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_vfield3D_s ( image, i*2, j*2+1 );
                  total.x += (int)pix2.x;
                  total.y += (int)pix2.y;
                  total.z += (int)pix2.z;
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2 );
                  total.x += (int)pix3.x;
                  total.y += (int)pix3.y;
                  total.z += (int)pix3.z;
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_vfield3D_s ( image, i*2+1, j*2+1 );
                  total.x += (int)pix4.x;
                  total.y += (int)pix4.y;
                  total.z += (int)pix4.z;
                  num++;
               }

               if ( (unsigned)num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     pix.x = (short) ((total.x + num/2)/num);
                     pix.y = (short) ((total.y + num/2)/num);
                     pix.z = (short) ((total.z + num/2)/num);
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.x = (short) ((total.x + 2)/4);
                     pix.y = (short) ((total.y + 2)/4);
                     pix.z = (short) ((total.z + 2)/4);
                  }

                  gan_image_set_pix_vfield3D_s ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_vfield3D_f ( Gan_Image *image, Gan_Image *mask,
                         Gan_ImagePyramidAverage average_type,
                         unsigned no_neighbours,
                         Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_Vector3_f pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_vfield3D_f ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_vfield3D_f ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2+1 );
            pix.x = 0.25F*(pix1.x + pix2.x + pix3.x + pix4.x);
            pix.y = 0.25F*(pix1.y + pix2.y + pix3.y + pix4.y);
            pix.z = 0.25F*(pix1.z + pix2.z + pix3.z + pix4.z);
            gan_image_set_pix_vfield3D_f ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield3D_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield3D_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2+1 );
               pix.x = 0.25F*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25F*(pix1.y + pix2.y + pix3.y + pix4.y);
               pix.z = 0.25F*(pix1.z + pix2.z + pix3.z + pix4.z);
               gan_image_set_pix_vfield3D_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      float num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield3D_f ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield3D_f ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2+1 );
               pix.x = 0.25F*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25F*(pix1.y + pix2.y + pix3.y + pix4.y);
               pix.z = 0.25F*(pix1.z + pix2.z + pix3.z + pix4.z);
               gan_image_set_pix_vfield3D_f ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.x = pix.y = pix.z = 0.0F;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_vfield3D_f ( image, i*2, j*2 );
                  (void)gan_vec3f_increment ( &pix, &pix1 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_vfield3D_f ( image, i*2, j*2+1 );
                  (void)gan_vec3f_increment ( &pix, &pix2 );
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2 );
                  (void)gan_vec3f_increment ( &pix, &pix3 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_vfield3D_f ( image, i*2+1, j*2+1 );
                  (void)gan_vec3f_increment ( &pix, &pix4 );
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     float fnum = (float)num;

                     pix.x /= fnum;
                     pix.y /= fnum;
                     pix.z /= fnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.x *= 0.25F;
                     pix.y *= 0.25F;
                     pix.z *= 0.25F;
                  }

                  gan_image_set_pix_vfield3D_f ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

static Gan_Bool
 halve_size_vfield3D_d ( Gan_Image *image, Gan_Image *mask,
                         Gan_ImagePyramidAverage average_type,
                         unsigned no_neighbours,
                         Gan_Image *himage, Gan_Image *hmask )
{
   int i, j;
   Gan_Vector3_d pix1, pix2, pix3, pix4, pix;

   /* if mask is NULL, other parameters are irrelevant */
   if ( mask == NULL )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
         {
            pix1 = gan_image_get_pix_vfield3D_d ( image, i*2,   j*2   );
            pix2 = gan_image_get_pix_vfield3D_d ( image, i*2,   j*2+1 );
            pix3 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2   );
            pix4 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2+1 );
            pix.x = 0.25*(pix1.x + pix2.x + pix3.x + pix4.x);
            pix.y = 0.25*(pix1.y + pix2.y + pix3.y + pix4.y);
            pix.z = 0.25*(pix1.z + pix2.z + pix3.z + pix4.z);
            gan_image_set_pix_vfield3D_d ( himage, i, j, &pix );
         }
   }
   /* mask != NULL, action depends on other parameters */
   else if ( no_neighbours == 4 )
   {
      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield3D_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield3D_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2+1 );
               pix.x = 0.25*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25*(pix1.y + pix2.y + pix3.y + pix4.y);
               pix.z = 0.25*(pix1.z + pix2.z + pix3.z + pix4.z);
               gan_image_set_pix_vfield3D_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
   }
   else
   {
      unsigned num;

      for ( i = (int)image->height/2-1; i >= 0; i-- )
         for ( j = (int)image->width/2-1; j >= 0; j-- )
            if ( gan_image_bit_get_pix_4group(mask,i*2,j*2) )
            {
               pix1 = gan_image_get_pix_vfield3D_d ( image, i*2,   j*2   );
               pix2 = gan_image_get_pix_vfield3D_d ( image, i*2,   j*2+1 );
               pix3 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2   );
               pix4 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2+1 );
               pix.x = 0.25*(pix1.x + pix2.x + pix3.x + pix4.x);
               pix.y = 0.25*(pix1.y + pix2.y + pix3.y + pix4.y);
               pix.z = 0.25*(pix1.z + pix2.z + pix3.z + pix4.z);
               gan_image_set_pix_vfield3D_d ( himage, i, j, &pix );
               gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
            }
            else
            {
               num = 0; pix.x = pix.y = pix.z = 0.0;
               if ( gan_image_get_pix_b(mask,i*2,j*2) )
               {
                  pix1 = gan_image_get_pix_vfield3D_d ( image, i*2, j*2 );
                  (void)gan_vec3_increment ( &pix, &pix1 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2,j*2+1) )
               {
                  pix2 = gan_image_get_pix_vfield3D_d ( image, i*2, j*2+1 );
                  (void)gan_vec3_increment ( &pix, &pix2 );
                  num++;
               }

               if ( gan_image_get_pix_b(mask,i*2+1,j*2) )
               {
                  pix3 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2 );
                  (void)gan_vec3_increment ( &pix, &pix3 );
                  num++;
               }
                    
               if ( gan_image_get_pix_b(mask,i*2+1,j*2+1) )
               {
                  pix4 = gan_image_get_pix_vfield3D_d ( image, i*2+1, j*2+1 );
                  (void)gan_vec3_increment ( &pix, &pix4 );
                  num++;
               }

               if ( num >= no_neighbours )
               {
                  if ( average_type == GAN_AVERAGE_IN_MASK )
                  {
                     double dnum = (double)num;

                     pix.x /= dnum;
                     pix.y /= dnum;
                     pix.z /= dnum;
                  }
                  else /* average_type == GAN_AVERAGE_ALL */
                  {
                     pix.x *= 0.25;
                     pix.y *= 0.25;
                     pix.z *= 0.25;
                  }

                  gan_image_set_pix_vfield3D_d ( himage, i, j, &pix );
                  gan_image_set_pix_b ( hmask, i, j, GAN_TRUE );
               }
            }
   }

   /* success */
   return GAN_TRUE;
}

/* Halve the size of an image requiring all four mask pixels in a neighbourhood
 * to be set.
 */
static Gan_Bool
 halve_size ( Gan_Image *image, Gan_Image *mask,
              Gan_ImagePyramidAverage average_type,
              unsigned no_neighbours,
              Gan_Image **himage, Gan_Image **hmask )
{
   Gan_Bool result;

   /* allocate half-size image and initialize it to zero */
   *himage = gan_image_alloc ( image->format, image->type,
                               image->height/2, image->width/2 );
   if ( *himage == NULL )
   {
      gan_err_register ( "halve_size", GAN_ERROR_FAILURE, "" );
      return GAN_FALSE;
   }

   gan_image_fill_zero ( *himage );

   if ( mask == NULL )
   {
      gan_err_test_bool ( hmask == NULL, "halve_size",
                          GAN_ERROR_INCOMPATIBLE, "mask images" );
   }
   else
   {
      /* allocate half-size mask and initialize it to zero (false) */
      *hmask = gan_image_alloc ( GAN_GREY_LEVEL_IMAGE, GAN_BOOL,
                                 image->height/2, image->width/2 );
      if ( *hmask == NULL )
      {
         gan_err_register ( "halve_size", GAN_ERROR_FAILURE, "" );
         return GAN_FALSE;
      }

      gan_image_fill_zero ( *hmask );
   }

   switch ( image->format )
   {
      case GAN_GREY_LEVEL_IMAGE:
        switch ( image->type )
        {
           case GAN_BOOL:
             result = halve_size_b ( image, mask, average_type,
                                     no_neighbours, *himage,
                                     (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_UCHAR:
             result = halve_size_gl_uc ( image, mask, average_type,
                                         no_neighbours, *himage,
                                         (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_USHORT:
             result = halve_size_gl_us ( image, mask, average_type,
                                         no_neighbours, *himage,
                                         (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_UINT:
             result = halve_size_gl_ui ( image, mask, average_type,
                                         no_neighbours, *himage,
                                         (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_FLOAT:
             result = halve_size_gl_f ( image, mask, average_type,
                                        no_neighbours, *himage,
                                        (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_DOUBLE:
             result = halve_size_gl_d ( image, mask, average_type,
                                        no_neighbours, *himage,
                                        (mask == NULL) ? NULL : *hmask );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
             gan_image_free ( *himage );
             if ( mask != NULL ) gan_image_free ( *hmask );
             return GAN_FALSE;
        }
        break;

      case GAN_RGB_COLOUR_IMAGE:
        
        switch ( image->type )
        {
           case GAN_FLOAT:
             result = halve_size_rgb_f ( image, mask, average_type,
                                         no_neighbours, *himage,
                                         (mask == NULL) ? NULL : *hmask );
             break;
         
           case GAN_DOUBLE:
             result = halve_size_rgb_d ( image, mask, average_type,
                                         no_neighbours, *himage,
                                         (mask == NULL) ? NULL : *hmask );
             break;
         
           case GAN_UCHAR:
             result = halve_size_rgb_uc ( image, mask, average_type,
                                          no_neighbours, *himage,
                                          (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_USHORT:
             result = halve_size_rgb_us ( image, mask, average_type,
                                          no_neighbours, *himage,
                                          (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_UINT:
             result = halve_size_rgb_ui ( image, mask, average_type,
                                          no_neighbours, *himage,
                                          (mask == NULL) ? NULL : *hmask );
             break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
           gan_image_free ( *himage );
           if ( mask != NULL ) gan_image_free ( *hmask );
           return GAN_FALSE;
      }
      break;

      case GAN_RGB_COLOUR_ALPHA_IMAGE:
        switch ( image->type )
        {
           case GAN_FLOAT:
             result = halve_size_rgba_f ( image, mask, average_type,
                                          no_neighbours, *himage,
                                          (mask == NULL) ? NULL : *hmask );
             break;
         
           case GAN_DOUBLE:
             result = halve_size_rgba_d ( image, mask, average_type,
                                          no_neighbours, *himage,
                                          (mask == NULL) ? NULL : *hmask );
             break;
         
           case GAN_UCHAR:
             result = halve_size_rgba_uc ( image, mask, average_type,
                                           no_neighbours, *himage,
                                           (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_USHORT:
             result = halve_size_rgba_us ( image, mask, average_type,
                                           no_neighbours, *himage,
                                           (mask == NULL) ? NULL : *hmask );
             break;

           case GAN_UINT:
             result = halve_size_rgba_ui ( image, mask, average_type,
                                           no_neighbours, *himage,
                                           (mask == NULL) ? NULL : *hmask );
             break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
           gan_image_free ( *himage );
           if ( mask != NULL ) gan_image_free ( *hmask );
           return GAN_FALSE;
      }
      break;

      case GAN_VECTOR_FIELD_2D:
        switch ( image->type )
        {
           case GAN_SHORT:
             result = halve_size_vfield2D_s ( image, mask, average_type,
                                              no_neighbours, *himage,
                                              (mask == NULL) ? NULL : *hmask );
             break;

         case GAN_FLOAT:
             result = halve_size_vfield2D_f ( image, mask, average_type,
                                              no_neighbours, *himage,
                                              (mask == NULL) ? NULL : *hmask );
             break;

         case GAN_DOUBLE:
             result = halve_size_vfield2D_d ( image, mask, average_type,
                                              no_neighbours, *himage,
                                              (mask == NULL) ? NULL : *hmask );
             break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
           gan_image_free ( *himage );
           if ( mask != NULL ) gan_image_free ( *hmask );
           return GAN_FALSE;
      }
      break;

      case GAN_VECTOR_FIELD_3D:
      switch ( image->type )
      {
           case GAN_SHORT:
             result = halve_size_vfield3D_s ( image, mask, average_type,
                                              no_neighbours, *himage,
                                              (mask == NULL) ? NULL : *hmask );
             break;

         case GAN_FLOAT:
             result = halve_size_vfield3D_f ( image, mask, average_type,
                                              no_neighbours, *himage,
                                              (mask == NULL) ? NULL : *hmask );
             break;

         case GAN_DOUBLE:
             result = halve_size_vfield3D_d ( image, mask, average_type,
                                              no_neighbours, *himage,
                                              (mask == NULL) ? NULL : *hmask );
             break;

         default:
           gan_err_flush_trace();
           gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
           gan_image_free ( *himage );
           if ( mask != NULL ) gan_image_free ( *hmask );
           return GAN_FALSE;
      }
      break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
        gan_image_free ( *himage );
        if ( mask != NULL ) gan_image_free ( *hmask );
        return GAN_FALSE;
   }

   if ( !result )
   {
      gan_err_register ( "halve_size", GAN_ERROR_ILLEGAL_TYPE, "" );
      gan_image_free ( *himage );
      if ( mask != NULL ) gan_image_free ( *hmask );
      return GAN_FALSE;
   }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief Builds an image pyramid.
 * \param img The top-level image in the pyramid
 * \param mask The mask corresponding to the top-level image or NULL
 * \param no_levels The number of levels in the pyramid
 * \param average_type The type of averaging of four-pixel neighbourhoods
 * \param no_neighbours Minimum number of neighbours set to transfer resolution
 * \param pyramid Pointer to the pyramid
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 *
 * Builds an image pyramid. If the \a mask is \c NULL, the pyramid is built
 * without masks, i.e. assuming that all the pixels are valid.
 *
 * \a no_neighbours is the least number of number of pixels in any four-pixel
 * neighbourhood of mask pixels needed to be one in order for the lower
 * resolution mask to be set to one.
 *
 * \sa gan_image_pyramid_free().
 */
Gan_Bool
03380  gan_image_pyramid_build ( Gan_Image *img, Gan_Image *mask, unsigned no_levels,
                           Gan_ImagePyramidAverage average_type,
                           unsigned no_neighbours,
                           Gan_ImagePyramid **pyramid )
{
   unsigned i;

   gan_err_test_bool ( no_levels > 0 &&
                       no_neighbours > 0 && no_neighbours <= 4,
                       "gan_image_pyramid_build", GAN_ERROR_ILLEGAL_ARGUMENT,
                       "" );

   /* allocate pyramid array */
   *pyramid = gan_malloc_array ( Gan_ImagePyramid, no_levels );

   if ( *pyramid == NULL )
   {
      gan_err_flush_trace();
      gan_err_register ( "gan_image_pyramid_build", GAN_ERROR_MALLOC_FAILED,
                         "" );
      return GAN_FALSE;
   }

   /* set top level of pyramid */
   (*pyramid)[0].img  = img;
   (*pyramid)[0].mask = mask;

   /* initialise masks to NULL */
   for ( i = 1; i < no_levels; i++ )
      (*pyramid)[i].mask = NULL;

   /* build pyramid of images and masks */
   for ( i = 1; i < no_levels; i++ )
      if ( !halve_size ( (*pyramid)[i-1].img, (*pyramid)[i-1].mask,
                         average_type, no_neighbours,
                         &(*pyramid)[i].img,
                         (mask == NULL) ? NULL : &(*pyramid)[i].mask ) )
      {
         gan_err_register ( "gan_image_pyramid_build", GAN_ERROR_FAILURE, "" );
         return GAN_FALSE;
      }

   /* success */
   return GAN_TRUE;
}

/**
 * \brief Frees an image pyramid.
 * \param pyramid Pointer to the pyramid
 * \param no_levels The number of levels in the pyramid
 * \param free_top_level Whether to free the top level image
 * \return #GAN_TRUE on success, #GAN_FALSE on failure.
 *
 * Frees an image \a pyramid. The \a free_top_levels flag indicates whether
 * the top-level image should be freed.
 *
 * \sa gan_image_pyramid_build().
 */
void
03439  gan_image_pyramid_free ( Gan_ImagePyramid *pyramid, unsigned no_levels,
                          Gan_Bool free_top_level )
{
   unsigned i;

   for ( i = no_levels-1; i > 0; i-- )
   {
      if ( pyramid[i].mask != NULL ) 
      {
         gan_image_free ( pyramid[i].mask );
         pyramid[i].mask = NULL;
      }
      gan_image_free ( pyramid[i].img );
      pyramid[i].img = NULL;
   }

   if ( free_top_level )
   {
      if ( pyramid[0].mask != NULL )
      { 
         gan_image_free ( pyramid[0].mask );
         pyramid[0].mask = NULL;
      }
      gan_image_free ( pyramid[0].img );
      pyramid[i].img = NULL;
   }

   free ( pyramid );
}

/**
 * \}
 */

/**
 * \}
 */

Generated by  Doxygen 1.6.0   Back to index