Logo Search packages:      
Sourcecode: gandalf version File versions

image_extract.c

/**
 * File:          $RCSfile: image_extract.c,v $
 * Module:        Extract/convert part of an image
 * Part of:       Gandalf Library
 *
 * Revision:      $Revision: 1.55 $
 * Last edited:   $Date: 2003/05/12 08:28:35 $
 * 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_extract.h>
#include <gandalf/image/image_gl_float.h>
#include <gandalf/image/image_gl_double.h>
#include <gandalf/image/image_bit.h>
#include <gandalf/image/image_gl_uchar.h>
#include <gandalf/image/image_gl_ushort.h>
#include <gandalf/image/image_gl_int.h>
#include <gandalf/image/image_gl_uint.h>
#include <gandalf/image/image_gla_uchar.h>
#include <gandalf/image/image_gla_ushort.h>
#include <gandalf/image/image_gla_int.h>
#include <gandalf/image/image_gla_uint.h>
#include <gandalf/image/image_gla_float.h>
#include <gandalf/image/image_gla_double.h>
#include <gandalf/image/image_rgb_uchar.h>
#include <gandalf/image/image_rgb_ushort.h>
#include <gandalf/image/image_rgb_int.h>
#include <gandalf/image/image_rgb_uint.h>
#include <gandalf/image/image_rgb_double.h>
#include <gandalf/image/image_rgb_float.h>
#include <gandalf/image/image_rgba_uchar.h>
#include <gandalf/image/image_rgba_ushort.h>
#include <gandalf/image/image_rgba_int.h>
#include <gandalf/image/image_rgba_uint.h>
#include <gandalf/image/image_rgba_double.h>
#include <gandalf/image/image_rgba_float.h>
#include <gandalf/common/misc_error.h>
#include <gandalf/common/array.h>

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

/**
 * \addtogroup ImageExtract
 * \{
 */

/* converts grey-level image from one type to another */
static Gan_Image *
 extract_grey ( Gan_Image *source,
                unsigned r0s,    unsigned c0s,
                unsigned height, unsigned width,
                Gan_Bool copy_pixels,
                Gan_Image *dest, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;

   gan_err_test_ptr ( source->format == GAN_GREY_LEVEL_IMAGE &&
                      dest->format == GAN_GREY_LEVEL_IMAGE,
                      "extract_grey", GAN_ERROR_INCOMPATIBLE, "" );

   switch ( dest->type )
   {
      case GAN_UCHAR:
        switch ( source->type )
        {
           case GAN_UCHAR:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_uc (
                       gan_image_get_pixptr_gl_uc(source,r0s+r,c0s),
                       1, width,
                       gan_image_get_pixptr_gl_uc(dest,r0d+r,c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_grey",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gl.uc[r] =
                                  gan_image_get_pixptr_gl_uc(source,r0s+r,c0s);
             }

             break;
                  
           case GAN_USHORT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( dest, r0d+r, c0d+c,
                      gan_pixel_us_to_uc (
                          gan_image_get_pix_gl_us(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_UINT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( dest, r0d+r, c0d+c,
                      gan_pixel_ui_to_uc (
                          gan_image_get_pix_gl_ui(source,r0s+r,c0s+c) ) );

             break;

           case GAN_FLOAT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( dest, r0d+r, c0d+c,
                      gan_pixel_f_to_uc (
                          gan_image_get_pix_gl_f(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_DOUBLE:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( dest, r0d+r, c0d+c,
                      gan_pixel_d_to_uc (
                          gan_image_get_pix_gl_d(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_BOOL:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( dest, r0d+r, c0d+c,(unsigned char)
                                 (gan_image_get_pix_b ( source, r0s+r, c0s+c )
                                  ? UCHAR_MAX : 0) );

             break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_USHORT:
        switch ( source->type )
        {
           case GAN_UCHAR:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( dest, r0d+r, c0d+c,
                      gan_pixel_uc_to_us (
                          gan_image_get_pix_gl_uc(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_USHORT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_us (
                       gan_image_get_pixptr_gl_us(source, r0s+r, c0s),
                       1, width,
                       gan_image_get_pixptr_gl_us(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_grey",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gl.us[r] =
                                gan_image_get_pixptr_gl_us(source, r0s+r, c0s);
             }

             break;
                  
           case GAN_UINT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( dest, r0d+r, c0d+c,
                      gan_pixel_ui_to_us (
                          gan_image_get_pix_gl_ui(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_FLOAT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( dest, r0d+r, c0d+c,
                      gan_pixel_f_to_us (
                          gan_image_get_pix_gl_f(source,r0s+r,c0s+c) ) );

             break;
            
           case GAN_DOUBLE:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( dest, r0d+r, c0d+c,
                      gan_pixel_d_to_us (
                          gan_image_get_pix_gl_d(source,r0s+r,c0s+c) ) );
             break;
            
           case GAN_BOOL:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( dest, r0d+r, c0d+c,(unsigned short)
                                 (gan_image_get_pix_b ( source, r0s+r, c0s+c )
                                  ? USHRT_MAX : 0) );

             break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_UINT:
        switch ( source->type )
        {
           case GAN_UCHAR:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( dest, r0d+r, c0d+c,
                      gan_pixel_uc_to_ui (
                          gan_image_get_pix_gl_uc(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_USHORT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( dest, r0d+r, c0d+c,
                      gan_pixel_us_to_ui (
                          gan_image_get_pix_gl_us(source,r0s+r,c0s+c) ) );

           break;
         
           case GAN_UINT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_ui (
                       gan_image_get_pixptr_gl_ui(source, r0s+r, c0s),
                       1, width,
                       gan_image_get_pixptr_gl_ui(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_grey",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gl.ui[r] =
                                gan_image_get_pixptr_gl_ui(source, r0s+r, c0s);
             }

             break;
                  
           case GAN_FLOAT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( dest, r0d+r, c0d+c,
                      gan_pixel_f_to_ui (
                          gan_image_get_pix_gl_f(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_DOUBLE:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( dest, r0d+r, c0d+c,
                      gan_pixel_d_to_ui (
                          gan_image_get_pix_gl_d(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_BOOL:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( dest, r0d+r, c0d+c,
                                 (gan_image_get_pix_b ( source, r0s+r, c0s+c )
                                  ? UINT_MAX : 0) );

             break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_INT:
        switch ( source->type )
        {
           case GAN_FLOAT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_i ( dest, r0d+r, c0d+c,
                      gan_pixel_f_to_i (
                          gan_image_get_pix_gl_f(source,r0s+r,c0s+c) ) );

             break;
         
           case GAN_DOUBLE:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_i ( dest, r0d+r, c0d+c,
                      gan_pixel_d_to_i (
                          gan_image_get_pix_gl_d(source,r0s+r,c0s+c) ) );

             break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_FLOAT:
        switch ( source->type )
        {
           case GAN_UCHAR:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( dest, r0d+r, c0d+c,
                      gan_pixel_uc_to_f (
                          gan_image_get_pix_gl_uc(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_USHORT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( dest, r0d+r, c0d+c,
                      gan_pixel_us_to_f (
                          gan_image_get_pix_gl_us(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_INT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( dest, r0d+r, c0d+c,
                      gan_pixel_i_to_f (
                          gan_image_get_pix_gl_i(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_UINT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( dest, r0d+r, c0d+c,
                      gan_pixel_ui_to_f (
                          gan_image_get_pix_gl_ui(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_FLOAT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_f (
                       gan_image_get_pixptr_gl_f(source, r0s+r, c0s),
                       1, width,
                       gan_image_get_pixptr_gl_f(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_grey",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gl.f[r] =
                                 gan_image_get_pixptr_gl_f(source, r0s+r, c0s);
             }

             break;
                     
           case GAN_DOUBLE:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( dest, r0d+r, c0d+c, (float)
                             gan_image_get_pix_gl_d ( source, r0s+r, c0s+c ) );
             break;
               
           case GAN_BOOL:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( dest, r0d+r, c0d+c,
                                            gan_image_get_pix_b ( source,
                                                                  r0s+r, c0s+c)
                                            ? 1.0F : 0.0F );
             break;
               
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
         
      case GAN_DOUBLE:
        switch ( source->type )
        {
           case GAN_UCHAR:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( dest, r0d+r, c0d+c,
                      gan_pixel_uc_to_d (
                          gan_image_get_pix_gl_uc(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_USHORT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( dest, r0d+r, c0d+c,
                      gan_pixel_us_to_d (
                          gan_image_get_pix_gl_us(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_INT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( dest, r0d+r, c0d+c,
                      gan_pixel_i_to_d (
                          gan_image_get_pix_gl_i(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_UINT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( dest, r0d+r, c0d+c,
                      gan_pixel_ui_to_d (
                          gan_image_get_pix_gl_ui(source,r0s+r,c0s+c) ) );

             break;
               
           case GAN_DOUBLE:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_d (
                       gan_image_get_pixptr_gl_d(source, r0s+r, c0s),
                       1, width,
                       gan_image_get_pixptr_gl_d(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_grey",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gl.d[r] =
                                 gan_image_get_pixptr_gl_d(source, r0s+r, c0s);
             }

             break;
                     
           case GAN_FLOAT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( dest, r0d+r, c0d+c, (double)
                             gan_image_get_pix_gl_f ( source, r0s+r, c0s+c ) );
             break;
               
           case GAN_BOOL:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_ILLEGAL_ARGUMENT, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( dest, r0d+r, c0d+c,
                                            gan_image_get_pix_b ( source,
                                                                  r0s+r, c0s+c)
                                            ? 1.0 : 0.0 );
             break;
               
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
         
      case GAN_BOOL:
        switch ( source->type )
        {
           case GAN_UCHAR:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_INCOMPATIBLE, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( dest, r0d+r, c0d+c,
                             gan_image_get_pix_gl_uc ( source, r0s+r, c0s+c )
                             ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_USHORT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_INCOMPATIBLE, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( dest, r0d+r, c0d+c,
                             gan_image_get_pix_gl_us ( source, r0s+r, c0s+c )
                             ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_UINT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_INCOMPATIBLE, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( dest, r0d+r, c0d+c,
                             gan_image_get_pix_gl_ui ( source, r0s+r, c0s+c )
                             ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_BOOL:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   for ( c=0; c < width; c++ )
                      gan_image_set_pix_b ( dest, r0d+r, c0d+c,
                                gan_image_get_pix_b ( source, r0s+r, c0s+c ) );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_grey",
                                   GAN_ERROR_INCOMPATIBLE, "" );

                /* insertion of one bit array into another must conform to
                   word boundaries */
                gan_err_test_ptr ( (c0s % GAN_BITWORD_SIZE) == 0,
                                   "extract_grey", GAN_ERROR_INCOMPATIBLE,
                                   "" );
                for ( r=0; r < height; r++ )
                {
                   dest->row_data.gl.b[r] = dest->ba[r].data =
                   &source->row_data.gl.b[r0s+r][c0s/GAN_BITWORD_SIZE];
                   dest->ba[r].no_bits = width;
                   dest->ba[r].no_words = GAN_NO_BITWORDS(width);
                }
             }

             break;
                  
           case GAN_FLOAT:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_INCOMPATIBLE, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( dest, r0d+r, c0d+c,
                             (gan_image_get_pix_gl_f ( source, r0s+r, c0s+c )
                              == 0.0F) ? GAN_FALSE : GAN_TRUE );
             break;

           case GAN_DOUBLE:
             gan_err_test_ptr ( copy_pixels, "extract_grey",
                                GAN_ERROR_INCOMPATIBLE, "" );
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( dest, r0d+r, c0d+c,
                             (gan_image_get_pix_gl_d ( source, r0s+r, c0s+c )
                              == 0.0) ? GAN_FALSE : GAN_TRUE );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
            
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_grey", GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }

   return dest;
}

static Gan_Image *
 extract_grey_to_gla ( Gan_Image *grey, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *gla, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( grey->format == GAN_GREY_LEVEL_IMAGE &&
                      gla->format == GAN_GREY_LEVEL_ALPHA_IMAGE,
                      "extract_grey_to_gla", GAN_ERROR_INCOMPATIBLE,
                      "" );
   switch ( gla->type )
   {
      case GAN_UCHAR:
        switch ( grey->type )
        {
           Gan_GLAPixel_uc glaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c );
                   glaPix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_us_to_uc (
                       gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_ui_to_uc (
                        gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_f_to_uc (
                        gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_d_to_uc (
                        gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( grey->type )
        {
           Gan_GLAPixel_us glaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_uc_to_us (
                        gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c ) );
                   glaPix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c );
                   glaPix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_ui_to_us (
                        gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c ) );
                   glaPix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_f_to_us (
                        gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c ) );
                   glaPix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_d_to_us (
                       gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c ) );
                   glaPix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_UINT:
        switch ( grey->type )
        {
           Gan_GLAPixel_ui glaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_uc_to_ui (
                        gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_us_to_ui (
                        gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c );
                   glaPix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_f_to_ui (
                        gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_d_to_ui (
                        gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c ) );
                   glaPix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_FLOAT:
        switch ( grey->type )
        {
           Gan_GLAPixel_f glaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_uc_to_f (
                       gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c ) );
                   glaPix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_us_to_f (
                       gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c ) );
                   glaPix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_ui_to_f (
                       gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c ) );
                   glaPix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c );
                   glaPix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = (float)
                              gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c );
                   glaPix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_DOUBLE:
        switch ( grey->type )
        {
           Gan_GLAPixel_d glaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_uc_to_d (
                       gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c ) );
                   glaPix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_us_to_d (
                       gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c ) );
                   glaPix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_pixel_ui_to_d (
                       gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c ) );
                   glaPix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = (double)
                              gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c );
                   glaPix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   glaPix.I = gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c );
                   glaPix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &glaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_grey_to_gla",
                           GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }
             
   return gla;
}

/* Converts an RGB image with alpha channel to a different type
 *
 * The converted RGB image is returned.
 */
static Gan_Image *
 extract_gla ( Gan_Image *source, unsigned r0s, unsigned c0s,
                unsigned height, unsigned width, Gan_Bool copy_pixels,
                Gan_Image *dest, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( source->format == GAN_GREY_LEVEL_ALPHA_IMAGE &&
                      dest->format == GAN_GREY_LEVEL_ALPHA_IMAGE,
                      "extract_gla", GAN_ERROR_INCOMPATIBLE, "" );
   
   switch ( dest->type )
   {
      case GAN_UCHAR:
        switch ( source->type )
        {
           Gan_GLAPixel_uc ucpix;

           case GAN_UCHAR:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_uc ( (unsigned char *)
                            gan_image_get_pixptr_gla_uc(source, r0s+r, c0s),
                            1, 2*width, (unsigned char *)
                            gan_image_get_pixptr_gla_uc(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_gla",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gla.uc[r] =
                               gan_image_get_pixptr_gla_uc(source, r0s+r, c0s);
             }
             break;
         
           case GAN_USHORT:
           {
              Gan_GLAPixel_us uspix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    uspix = gan_image_get_pix_gla_us ( source, r0s+r, c0s+c );
                    ucpix.I = gan_pixel_us_to_uc(uspix.I);
                    ucpix.A = gan_pixel_us_to_uc(uspix.A);
                    gan_image_set_pix_gla_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_UINT:
           {
              Gan_GLAPixel_ui uipix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    uipix = gan_image_get_pix_gla_ui ( source, r0s+r, c0s+c );
                    ucpix.I = gan_pixel_ui_to_uc(uipix.I);
                    ucpix.A = gan_pixel_ui_to_uc(uipix.A);
                    gan_image_set_pix_gla_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_FLOAT:
           {
              Gan_GLAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_gla_f ( source, r0s+r, c0s+c );
                    ucpix.I = gan_pixel_f_to_uc(fpix.I);
                    ucpix.A = gan_pixel_f_to_uc(fpix.A);
                    gan_image_set_pix_gla_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_GLAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_gla_d ( source, r0s+r, c0s+c );
                    ucpix.I = gan_pixel_d_to_uc(dpix.I);
                    ucpix.A = gan_pixel_d_to_uc(dpix.A);
                    gan_image_set_pix_gla_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla", GAN_ERROR_NOT_IMPLEMENTED,
                                "" );
             return NULL;
        }
        break;
      
      case GAN_USHORT:
        switch ( source->type )
        {
           Gan_GLAPixel_us uspix;

           case GAN_UCHAR:
           {
              Gan_GLAPixel_uc ucpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    ucpix = gan_image_get_pix_gla_uc ( source, r0s+r, c0s+c );
                    uspix.I = gan_pixel_uc_to_us(ucpix.I);
                    uspix.A = gan_pixel_uc_to_us(ucpix.A);
                    gan_image_set_pix_gla_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_USHORT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_us ((unsigned short *)
                            gan_image_get_pixptr_gla_us(source, r0s+r, c0s),
                            1, 2*width, (unsigned short *)
                            gan_image_get_pixptr_gla_us(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_gla",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gla.us[r] =
                               gan_image_get_pixptr_gla_us(source, r0s+r, c0s);
             }
             break;
         
           case GAN_UINT:
           {
              Gan_GLAPixel_ui uipix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    uipix = gan_image_get_pix_gla_ui ( source, r0s+r, c0s+c );
                    uspix.I = gan_pixel_ui_to_us(uipix.I);
                    uspix.A = gan_pixel_ui_to_us(uipix.A);
                    gan_image_set_pix_gla_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_FLOAT:
           {
              Gan_GLAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_gla_f ( source, r0s+r, c0s+c );
                    uspix.I = gan_pixel_f_to_us(fpix.I);
                    uspix.A = gan_pixel_f_to_us(fpix.A);
                    gan_image_set_pix_gla_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_GLAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_gla_d ( source, r0s+r, c0s+c );
                    uspix.I = gan_pixel_d_to_us(dpix.I);
                    uspix.A = gan_pixel_d_to_us(dpix.A);
                    gan_image_set_pix_gla_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_UINT:
        switch ( source->type )
        {
           Gan_GLAPixel_ui uipix;

           case GAN_UCHAR:
           {
              Gan_GLAPixel_uc ucpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    ucpix = gan_image_get_pix_gla_uc ( source, r0s+r, c0s+c );
                    uipix.I = gan_pixel_uc_to_ui(ucpix.I);
                    uipix.A = gan_pixel_uc_to_ui(ucpix.A);
                    gan_image_set_pix_gla_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_USHORT:
           {
              Gan_GLAPixel_us uspix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    uspix = gan_image_get_pix_gla_us ( source, r0s+r, c0s+c );
                    uipix.I = gan_pixel_us_to_ui(uspix.I);
                    uipix.A = gan_pixel_us_to_ui(uspix.A);
                    gan_image_set_pix_gla_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_UINT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_ui ((unsigned int *)
                            gan_image_get_pixptr_gla_ui(source, r0s+r, c0s),
                            1, 2*width, (unsigned int *)
                            gan_image_get_pixptr_gla_ui(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_gla",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gla.ui[r] =
                               gan_image_get_pixptr_gla_ui(source, r0s+r, c0s);
             }
             break;
         
           case GAN_FLOAT:
           {
              Gan_GLAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_gla_f ( source, r0s+r, c0s+c );
                    uipix.I = gan_pixel_f_to_ui(fpix.I);
                    uipix.A = gan_pixel_f_to_ui(fpix.A);
                    gan_image_set_pix_gla_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_GLAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip GLA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_gla_d ( source, r0s+r, c0s+c );
                    uipix.I = gan_pixel_d_to_ui(dpix.I);
                    uipix.A = gan_pixel_d_to_ui(dpix.A);
                    gan_image_set_pix_gla_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_FLOAT:
        switch ( source->type )
        {
           Gan_GLAPixel_f fpix;

           case GAN_UCHAR:
           {
              Gan_GLAPixel_uc ucpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    ucpix = gan_image_get_pix_gla_uc ( source, r0s+r, c0s+c );
                    fpix.I = gan_pixel_uc_to_f(ucpix.I);
                    fpix.A = gan_pixel_uc_to_f(ucpix.A);
                    gan_image_set_pix_gla_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_USHORT:
           {
              Gan_GLAPixel_us uspix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uspix = gan_image_get_pix_gla_us ( source, r0s+r, c0s+c );
                    fpix.I = gan_pixel_us_to_f(uspix.I);
                    fpix.A = gan_pixel_us_to_f(uspix.A);
                    gan_image_set_pix_gla_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_UINT:
           {
              Gan_GLAPixel_ui uipix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uipix = gan_image_get_pix_gla_ui ( source, r0s+r, c0s+c );
                    fpix.I = gan_pixel_ui_to_f(uipix.I);
                    fpix.A = gan_pixel_ui_to_f(uipix.A);
                    gan_image_set_pix_gla_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_FLOAT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_f ( (float *)
                             gan_image_get_pixptr_gla_f(source, r0s+r, c0s),
                             1, 2*width, (float *)
                             gan_image_get_pixptr_gla_f(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_gla",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gla.f[r] =
                                gan_image_get_pixptr_gla_f(source, r0s+r, c0s);
             }
             break;
            
           case GAN_DOUBLE:
           {
              Gan_GLAPixel_d dpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    dpix = gan_image_get_pix_gla_d ( source, r0s+r, c0s+c );
                    fpix.I = (float)dpix.I;
                    fpix.A = (float)dpix.A;
                    gan_image_set_pix_gla_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
         
      case GAN_DOUBLE:
        switch ( source->type )
        {
           Gan_GLAPixel_d dpix;

           case GAN_UCHAR:
           {
              Gan_GLAPixel_uc ucpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    ucpix = gan_image_get_pix_gla_uc ( source, r0s+r, c0s+c );
                    dpix.I = gan_pixel_uc_to_d(ucpix.I);
                    dpix.A = gan_pixel_uc_to_d(ucpix.A);
                    gan_image_set_pix_gla_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_USHORT:
           {
              Gan_GLAPixel_us uspix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uspix = gan_image_get_pix_gla_us ( source, r0s+r, c0s+c );
                    dpix.I = gan_pixel_us_to_d(uspix.I);
                    dpix.A = gan_pixel_us_to_d(uspix.A);
                    gan_image_set_pix_gla_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_UINT:
           {
              Gan_GLAPixel_ui uipix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uipix = gan_image_get_pix_gla_ui ( source, r0s+r, c0s+c );
                    dpix.I = gan_pixel_ui_to_d(uipix.I);
                    dpix.A = gan_pixel_ui_to_d(uipix.A);
                    gan_image_set_pix_gla_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_FLOAT:
           {
              Gan_GLAPixel_f fpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_gla",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    fpix = gan_image_get_pix_gla_f ( source, r0s+r, c0s+c );
                    dpix.I = (double)fpix.I;
                    dpix.A = (double)fpix.A;
                    gan_image_set_pix_gla_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_DOUBLE:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_d ( (double *)
                             gan_image_get_pixptr_gla_d(source, r0s+r, c0s),
                             1, 2*width, (double *)
                             gan_image_get_pixptr_gla_d(dest, r0d+r, c0d), 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_gla",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.gla.d[r] =
                                gan_image_get_pixptr_gla_d(source, r0s+r, c0s);
             }
             break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
         
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_gla", GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }
   
   return dest;
}

static Gan_Image *
 extract_grey_to_rgb ( Gan_Image *grey, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *rgb, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   switch ( rgb->type )
   {
      case GAN_UCHAR:
        switch ( grey->type )
        {
           Gan_RGBPixel_uc rgbPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                       gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_uc ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_us_to_uc(gan_image_get_pix_gl_us (grey,
                                                               r0s+r, c0s+c));
                   gan_image_set_pix_rgb_uc ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_ui_to_uc(gan_image_get_pix_gl_ui (grey,
                                                               r0s+r, c0s+c));
                   gan_image_set_pix_rgb_uc ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_f_to_uc(gan_image_get_pix_gl_f (grey,
                                                             r0s+r, c0s+c));
                   gan_image_set_pix_rgb_uc ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_d_to_uc(gan_image_get_pix_gl_d (grey,
                                                             r0s+r, c0s+c));
                   gan_image_set_pix_rgb_uc ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgb",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( grey->type )
        {
           Gan_RGBPixel_us rgbPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_uc_to_us(gan_image_get_pix_gl_uc (grey,
                                                               r0s+r, c0s+c));
                   gan_image_set_pix_rgb_us ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c);
                   gan_image_set_pix_rgb_us ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_ui_to_us(gan_image_get_pix_gl_ui (grey,
                                                               r0s+r, c0s+c));
                   gan_image_set_pix_rgb_us ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_f_to_us(gan_image_get_pix_gl_f (grey,
                                                             r0s+r, c0s+c));
                   gan_image_set_pix_rgb_us ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_d_to_us(gan_image_get_pix_gl_d (grey,
                                                             r0s+r, c0s+c));
                   gan_image_set_pix_rgb_us ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgb",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_INT:
        switch ( grey->type )
        {
           Gan_RGBPixel_i rgbPix;

           case GAN_INT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_image_get_pix_gl_i ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_i ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_f_to_i(gan_image_get_pix_gl_f (grey,
                                                            r0s+r, c0s+c));
                   gan_image_set_pix_rgb_i ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_d_to_i(gan_image_get_pix_gl_d (grey,
                                                            r0s+r, c0s+c));
                   gan_image_set_pix_rgb_i ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgb",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_UINT:
        switch ( grey->type )
        {
           Gan_RGBPixel_ui rgbPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_uc_to_ui(gan_image_get_pix_gl_uc (grey,
                                                               r0s+r, c0s+c));
                   gan_image_set_pix_rgb_ui ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_us_to_ui(gan_image_get_pix_gl_us (grey,
                                                               r0s+r, c0s+c));
                   gan_image_set_pix_rgb_ui ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_ui ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_f_to_ui(gan_image_get_pix_gl_f (grey,
                                                             r0s+r, c0s+c));
                   gan_image_set_pix_rgb_ui ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_d_to_ui(gan_image_get_pix_gl_d (grey,
                                                             r0s+r, c0s+c));
                   gan_image_set_pix_rgb_ui ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgb",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_FLOAT:
        switch ( grey->type )
        {
           Gan_RGBPixel_f rgbPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_uc_to_f(gan_image_get_pix_gl_uc (grey,
                                                              r0s+r, c0s+c));
                   gan_image_set_pix_rgb_f ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_us_to_f(gan_image_get_pix_gl_us (grey,
                                                              r0s+r, c0s+c));
                   gan_image_set_pix_rgb_f ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_ui_to_f(gan_image_get_pix_gl_ui (grey,
                                                              r0s+r, c0s+c));
                   gan_image_set_pix_rgb_f ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_f ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   (float)gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_f ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgb",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_DOUBLE:
        switch ( grey->type )
        {
           Gan_RGBPixel_d rgbPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_uc_to_d(gan_image_get_pix_gl_uc (grey,
                                                              r0s+r, c0s+c));
                   gan_image_set_pix_rgb_d ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_us_to_d(gan_image_get_pix_gl_us (grey,
                                                              r0s+r, c0s+c));
                   gan_image_set_pix_rgb_d ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_pixel_ui_to_d(gan_image_get_pix_gl_ui (grey,
                                                              r0s+r, c0s+c));
                   gan_image_set_pix_rgb_d ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   (double)gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_d ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbPix.R = rgbPix.G = rgbPix.B =
                   gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c );
                   gan_image_set_pix_rgb_d ( rgb, r0d+r, c0d+c, &rgbPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgb",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_grey_to_rgb",
                           GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }
             
   return rgb;
}

static Gan_Image *
 extract_grey_to_rgba ( Gan_Image *grey, unsigned r0s, unsigned c0s,
                        unsigned height, unsigned width,
                        Gan_Image *rgba, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;

   switch ( rgba->type )
   {
      case GAN_UCHAR:
        switch ( grey->type )
        {
           Gan_RGBAPixel_uc rgbaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                       gan_image_get_pix_gl_uc ( grey, r0s+r, c0s+c );
                   rgbaPix.A = UCHAR_MAX;
                   gan_image_set_pix_rgba_uc ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_us_to_uc(gan_image_get_pix_gl_us (grey,
                                                               r0s+r, c0s+c));
                   rgbaPix.A = UCHAR_MAX;
                   gan_image_set_pix_rgba_uc ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_ui_to_uc(gan_image_get_pix_gl_ui (grey,
                                                               r0s+r, c0s+c));
                   rgbaPix.A = UCHAR_MAX;
                   gan_image_set_pix_rgba_uc ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_f_to_uc(gan_image_get_pix_gl_f (grey,
                                                             r0s+r, c0s+c));
                   rgbaPix.A = UCHAR_MAX;
                   gan_image_set_pix_rgba_uc ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_d_to_uc(gan_image_get_pix_gl_d (grey,
                                                             r0s+r, c0s+c));
                   rgbaPix.A = UCHAR_MAX;
                   gan_image_set_pix_rgba_uc ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgba",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( grey->type )
        {
           Gan_RGBAPixel_us rgbaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_uc_to_us(gan_image_get_pix_gl_uc (grey,
                                                               r0s+r, c0s+c));
                   rgbaPix.A = USHRT_MAX;
                   gan_image_set_pix_rgba_us ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_image_get_pix_gl_us ( grey, r0s+r, c0s+c);
                   rgbaPix.A = USHRT_MAX;
                   gan_image_set_pix_rgba_us ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_ui_to_us(gan_image_get_pix_gl_ui (grey,
                                                               r0s+r, c0s+c));
                   rgbaPix.A = USHRT_MAX;
                   gan_image_set_pix_rgba_us ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_f_to_us(gan_image_get_pix_gl_f (grey,
                                                             r0s+r, c0s+c));
                   rgbaPix.A = USHRT_MAX;
                   gan_image_set_pix_rgba_us ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_d_to_us(gan_image_get_pix_gl_d (grey,
                                                             r0s+r, c0s+c));
                   rgbaPix.A = USHRT_MAX;
                   gan_image_set_pix_rgba_us ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgba",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_INT:
        switch ( grey->type )
        {
           Gan_RGBAPixel_i rgbaPix;

           case GAN_INT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_image_get_pix_gl_i ( grey, r0s+r, c0s+c );
                   rgbaPix.A = INT_MAX;
                   gan_image_set_pix_rgba_i ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_f_to_i(gan_image_get_pix_gl_f (grey,
                                                            r0s+r, c0s+c));
                   rgbaPix.A = INT_MAX;
                   gan_image_set_pix_rgba_i ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_d_to_i(gan_image_get_pix_gl_d (grey,
                                                            r0s+r, c0s+c));
                   rgbaPix.A = INT_MAX;
                   gan_image_set_pix_rgba_i ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgba",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_UINT:
        switch ( grey->type )
        {
           Gan_RGBAPixel_ui rgbaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_uc_to_ui(gan_image_get_pix_gl_uc (grey,
                                                               r0s+r, c0s+c));
                   rgbaPix.A = UINT_MAX;
                   gan_image_set_pix_rgba_ui ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_us_to_ui(gan_image_get_pix_gl_us (grey,
                                                               r0s+r, c0s+c));
                   rgbaPix.A = UINT_MAX;
                   gan_image_set_pix_rgba_ui ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_image_get_pix_gl_ui ( grey, r0s+r, c0s+c );
                   rgbaPix.A = UINT_MAX;
                   gan_image_set_pix_rgba_ui ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_f_to_ui(gan_image_get_pix_gl_f (grey,
                                                             r0s+r, c0s+c));
                   rgbaPix.A = UINT_MAX;
                   gan_image_set_pix_rgba_ui ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_d_to_ui(gan_image_get_pix_gl_d (grey,
                                                             r0s+r, c0s+c));
                   rgbaPix.A = UINT_MAX;
                   gan_image_set_pix_rgba_ui ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgba",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_FLOAT:
        switch ( grey->type )
        {
           Gan_RGBAPixel_f rgbaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_uc_to_f(gan_image_get_pix_gl_uc (grey,
                                                              r0s+r, c0s+c));
                   rgbaPix.A = 1.0F;
                   gan_image_set_pix_rgba_f ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_us_to_f(gan_image_get_pix_gl_us (grey,
                                                              r0s+r, c0s+c));
                   rgbaPix.A = 1.0F;
                   gan_image_set_pix_rgba_f ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_ui_to_f(gan_image_get_pix_gl_ui (grey,
                                                              r0s+r, c0s+c));
                   rgbaPix.A = 1.0F;
                   gan_image_set_pix_rgba_f ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c );
                   rgbaPix.A = 1.0F;
                   gan_image_set_pix_rgba_f ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   (float)gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c );
                   rgbaPix.A = 1.0F;
                   gan_image_set_pix_rgba_f ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgba",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      case GAN_DOUBLE:
        switch ( grey->type )
        {
           Gan_RGBAPixel_d rgbaPix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_uc_to_d(gan_image_get_pix_gl_uc (grey,
                                                              r0s+r, c0s+c));
                   rgbaPix.A = 1.0;
                   gan_image_set_pix_rgba_d ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_us_to_d(gan_image_get_pix_gl_us (grey,
                                                              r0s+r, c0s+c));
                   rgbaPix.A = 1.0;
                   gan_image_set_pix_rgba_d ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_pixel_ui_to_d(gan_image_get_pix_gl_ui (grey,
                                                              r0s+r, c0s+c));
                   rgbaPix.A = 1.0;
                   gan_image_set_pix_rgba_d ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   (double)gan_image_get_pix_gl_f ( grey, r0s+r, c0s+c );
                   rgbaPix.A = 1.0;
                   gan_image_set_pix_rgba_d ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   rgbaPix.R = rgbaPix.G = rgbaPix.B =
                   gan_image_get_pix_gl_d ( grey, r0s+r, c0s+c );
                   rgbaPix.A = 1.0;
                   gan_image_set_pix_rgba_d ( rgba, r0d+r, c0d+c, &rgbaPix );
                }
             break;
             
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_grey_to_rgba",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
        
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_grey_to_rgba",
                           GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }
             
   return rgba;
}

static Gan_Image *
 extract_gla_to_grey ( Gan_Image *gla, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *grey, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;

   gan_err_test_ptr ( gla->format == GAN_GREY_LEVEL_ALPHA_IMAGE &&
                      grey->format == GAN_GREY_LEVEL_IMAGE,
                      "extract_gla_to_grey", GAN_ERROR_INCOMPATIBLE, "" );

   switch ( gla->type )
   {
      case GAN_UCHAR:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                                        gla->row_data.gla.uc[r0s+r][c0s+c].I );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                               gan_pixel_uc_to_us (
                                   gla->row_data.gla.uc[r0s+r][c0s+c].I ) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                               gan_pixel_uc_to_ui (
                                   gla->row_data.gla.uc[r0s+r][c0s+c].I ) );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                                         gla->row_data.gla.uc[r0s+r][c0s+c].I
                                         ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                               gan_pixel_uc_to_f (
                                   gla->row_data.gla.uc[r0s+r][c0s+c].I ) );
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                               gan_pixel_uc_to_d (
                                   gla->row_data.gla.uc[r0s+r][c0s+c].I ) );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_USHORT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                               gan_pixel_us_to_uc (
                                   gla->row_data.gla.us[r0s+r][c0s+c].I ) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                                        gla->row_data.gla.us[r0s+r][c0s+c].I );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                               gan_pixel_us_to_ui (
                                   gla->row_data.gla.us[r0s+r][c0s+c].I ) );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                                         gla->row_data.gla.us[r0s+r][c0s+c].I
                                         ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                               gan_pixel_us_to_f (
                                   gla->row_data.gla.us[r0s+r][c0s+c].I ) );
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                               gan_pixel_us_to_d (
                                   gla->row_data.gla.us[r0s+r][c0s+c].I ) );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_UINT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                               gan_pixel_ui_to_uc (             
                                   gla->row_data.gla.ui[r0s+r][c0s+c].I ) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                               gan_pixel_ui_to_us (
                                   gla->row_data.gla.ui[r0s+r][c0s+c].I ) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                                        gla->row_data.gla.ui[r0s+r][c0s+c].I );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                                         gla->row_data.gla.ui[r0s+r][c0s+c].I
                                         ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                               gan_pixel_ui_to_f (
                                   gla->row_data.gla.ui[r0s+r][c0s+c].I ) );
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                               gan_pixel_ui_to_d (
                                   gla->row_data.gla.ui[r0s+r][c0s+c].I ) );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_FLOAT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                               gan_pixel_f_to_uc (             
                                   gla->row_data.gla.f[r0s+r][c0s+c].I ) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                               gan_pixel_f_to_us (
                                   gla->row_data.gla.f[r0s+r][c0s+c].I ) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                               gan_pixel_f_to_ui (
                                   gla->row_data.gla.f[r0s+r][c0s+c].I ) );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                                         (gla->row_data.gla.f[r0s+r][c0s+c].I
                                          == 0.0F) ? GAN_FALSE : GAN_TRUE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f(grey, r0d+r, c0d+c,
                                          gla->row_data.gla.f[r0s+r][c0s+c].I);
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d(grey, r0d+r, c0d+c, (double)
                                          gla->row_data.gla.f[r0s+r][c0s+c].I);
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_DOUBLE:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                               gan_pixel_d_to_uc (
                                   gla->row_data.gla.d[r0s+r][c0s+c].I ) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                               gan_pixel_d_to_us (
                                   gla->row_data.gla.d[r0s+r][c0s+c].I ) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                               gan_pixel_d_to_ui (
                                   gla->row_data.gla.d[r0s+r][c0s+c].I ) );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                                         (gla->row_data.gla.d[r0s+r][c0s+c].I
                                          == 0.0) ? GAN_FALSE : GAN_TRUE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f(grey, r0d+r, c0d+c, (float)
                                          gla->row_data.gla.d[r0s+r][c0s+c].I);
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d(grey, r0d+r, c0d+c,
                                          gla->row_data.gla.d[r0s+r][c0s+c].I);
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_gla_to_grey", GAN_ERROR_NOT_IMPLEMENTED,
                           "" );
        return NULL;
   }

   return grey;
}

static Gan_Image *
 extract_rgb_to_grey ( Gan_Image *rgb, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *grey, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( rgb->format == GAN_RGB_COLOUR_IMAGE &&
                      grey->format == GAN_GREY_LEVEL_IMAGE,
                      "extract_rgb_to_grey", GAN_ERROR_INCOMPATIBLE, "" );

   switch ( rgb->type )
   {
      case GAN_UCHAR:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbuc_to_yuc (
                           gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c)) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbuc_to_yus (
                           gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c)) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbuc_to_yui (
                           gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c)) );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbuc_to_yus (
                                gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c))
                                ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_f (
                           gan_pixel_rgbuc_to_yus (
                               gan_image_get_pixptr_rgb_uc(rgb,r0s+r,c0s+c))));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_d (
                           gan_pixel_rgbuc_to_yus (
                               gan_image_get_pixptr_rgb_uc(rgb,r0s+r,c0s+c))));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_USHORT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbus_to_yuc (
                           gan_image_get_pixptr_rgb_us(rgb, r0s+r, c0s+c)) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbus_to_yus (
                           gan_image_get_pixptr_rgb_us(rgb, r0s+r, c0s+c)) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_ui (
                       gan_pixel_rgbus_to_yus (
                           gan_image_get_pixptr_rgb_us(rgb, r0s+r, c0s+c)) ) );
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                         gan_pixel_rgbus_to_yus (
                             gan_image_get_pixptr_rgb_us(rgb, r0s+r, c0s+c))
                             ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_f (
                           gan_pixel_rgbus_to_yus (
                               gan_image_get_pixptr_rgb_us(rgb,r0s+r,c0s+c))));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                        gan_pixel_us_to_d (
                           gan_pixel_rgbus_to_yus (
                               gan_image_get_pixptr_rgb_us(rgb,r0s+r,c0s+c))));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_UINT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_uc (
                           gan_pixel_rgbui_to_yf (
                               gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c))));
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_us (
                           gan_pixel_rgbui_to_yf (
                               gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c))));
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_ui (
                           gan_pixel_rgbui_to_yf (
                               gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                         gan_pixel_rgbui_to_yf (
                             gan_image_get_pixptr_rgb_ui(rgb, r0s+r, c0s+c))
                             ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                           gan_pixel_rgbui_to_yf (
                               gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c)));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c, (double)
                           gan_pixel_rgbui_to_yf (
                               gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c)));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_FLOAT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                           gan_pixel_f_to_uc (
                               gan_pixel_rgbf_to_yf (
                                gan_image_get_pixptr_rgb_f(rgb,r0s+r,c0s+c))));
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                           gan_pixel_f_to_us (
                               gan_pixel_rgbf_to_yf (
                                gan_image_get_pixptr_rgb_f(rgb,r0s+r,c0s+c))));
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                           gan_pixel_f_to_ui (
                               gan_pixel_rgbf_to_yf (
                                gan_image_get_pixptr_rgb_f(rgb,r0s+r,c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                           gan_pixel_rgbf_to_yf (
                               gan_image_get_pixptr_rgb_f(rgb, r0s+r, c0s+c) )
                           ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                           gan_pixel_rgbf_to_yf (
                               gan_image_get_pixptr_rgb_f(rgb, r0s+r, c0s+c)));
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c, (double)
                           gan_pixel_rgbf_to_yf (
                               gan_image_get_pixptr_rgb_f(rgb, r0s+r, c0s+c)));
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_DOUBLE:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                           gan_pixel_d_to_uc (
                               gan_pixel_rgbd_to_yd (
                                gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c))));
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                           gan_pixel_d_to_us (
                               gan_pixel_rgbd_to_yd (
                                gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c))));
             break;

           case GAN_INT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_i ( grey, r0d+r, c0d+c,
                           gan_pixel_d_to_i (
                               gan_pixel_rgbd_to_yd (
                                gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c))));
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                           gan_pixel_d_to_ui (
                               gan_pixel_rgbd_to_yd (
                                gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                           gan_pixel_rgbd_to_yd (
                               gan_image_get_pixptr_rgb_d(rgb, r0s+r, c0s+c) )
                           ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c, (float)
                           gan_pixel_rgbd_to_yd (
                               gan_image_get_pixptr_rgb_d(rgb, r0s+r, c0s+c)));
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                           gan_pixel_rgbd_to_yd (
                               gan_image_get_pixptr_rgb_d(rgb, r0s+r, c0s+c)));
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_rgb_to_grey", GAN_ERROR_NOT_IMPLEMENTED,
                           "" );
        return NULL;
   }

   return grey;
}

static Gan_Image *
 extract_rgba_to_grey ( Gan_Image *rgba, unsigned r0s, unsigned c0s,
                        unsigned height, unsigned width,
                        Gan_Image *grey, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( rgba->format == GAN_RGB_COLOUR_ALPHA_IMAGE &&
                      grey->format == GAN_GREY_LEVEL_IMAGE,
                      "extract_rgba_to_grey", GAN_ERROR_INCOMPATIBLE, "" );
   
   switch ( rgba->type )
   {
      case GAN_UCHAR:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbauc_to_yuc (
                           gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c)) );
             
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbauc_to_yus (
                           gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c)) );

             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbauc_to_yui (
                           gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c)) );

             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbauc_to_yus (
                           gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c))
                           ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_f (
                         gan_pixel_rgbauc_to_yus (
                           gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c))));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_d (
                         gan_pixel_rgbauc_to_yus (
                           gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c))));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_USHORT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbaus_to_yuc (
                           gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c)) );
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbaus_to_yus (
                           gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c)) );
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_ui (
                         gan_pixel_rgbaus_to_yus (
                           gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                       gan_pixel_rgbaus_to_yus (
                           gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c))
                           ? GAN_TRUE : GAN_FALSE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_f (
                         gan_pixel_rgbaus_to_yus (
                           gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c))));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                       gan_pixel_us_to_d (
                         gan_pixel_rgbaus_to_yus (
                           gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c))));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_UINT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_uc (
                         gan_pixel_rgbaui_to_yf (
                           gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c))));
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_us (
                         gan_pixel_rgbaui_to_yf (
                           gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c))));
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_ui (
                         gan_pixel_rgbaui_to_yf (
                           gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                       (gan_pixel_rgbaui_to_yf (
                           gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c))
                        == 0.0F) ? GAN_FALSE : GAN_TRUE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                         gan_pixel_rgbaui_to_yf (
                            gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c)));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                        (double)gan_pixel_rgbaui_to_yf (
                            gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c)));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_FLOAT:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_uc (
                          gan_pixel_rgbaf_to_yf (
                            gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c))));
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_us (
                          gan_pixel_rgbaf_to_yf (
                            gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c))));
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_f_to_ui (
                          gan_pixel_rgbaf_to_yf (
                            gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                       (gan_pixel_rgbaf_to_yf (
                           gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c))
                        == 0.0F) ? GAN_FALSE : GAN_TRUE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c,
                         gan_pixel_rgbaf_to_yf (
                             gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c)));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                        (double)gan_pixel_rgbaf_to_yf (
                             gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c)));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_DOUBLE:
        switch ( grey->type )
        {
           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_uc ( grey, r0d+r, c0d+c,
                       gan_pixel_d_to_uc (
                          gan_pixel_rgbad_to_yd (
                            gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c))));
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_us ( grey, r0d+r, c0d+c,
                       gan_pixel_d_to_us (
                          gan_pixel_rgbad_to_yd (
                            gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c))));
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_ui ( grey, r0d+r, c0d+c,
                       gan_pixel_d_to_ui (
                          gan_pixel_rgbad_to_yd (
                            gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c))));
             break;

           case GAN_BOOL:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_b ( grey, r0d+r, c0d+c,
                       (gan_pixel_rgbad_to_yd (
                           gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c))
                        == 0.0F) ? GAN_FALSE : GAN_TRUE );
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_f ( grey, r0d+r, c0d+c, (float)
                          gan_pixel_rgbad_to_yd (
                             gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c)));

             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                   gan_image_set_pix_gl_d ( grey, r0d+r, c0d+c,
                        (double)gan_pixel_rgbad_to_yd (
                             gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c)));

             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_grey",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_rgba_to_grey", GAN_ERROR_NOT_IMPLEMENTED,
                           "" );
        return NULL;
   }

   return grey;
}

static Gan_Image *
 extract_rgb_to_gla ( Gan_Image *rgb, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *gla, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( rgb->format == GAN_RGB_COLOUR_IMAGE &&
                      gla->format == GAN_GREY_LEVEL_ALPHA_IMAGE,
                      "extract_rgb_to_gla", GAN_ERROR_INCOMPATIBLE, "" );

   switch ( gla->type )
   {
      case GAN_UCHAR:
        switch ( rgb->type )
        {
           Gan_GLAPixel_uc ucpix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_rgbuc_to_yuc (
                               gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c));
                   ucpix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_rgbus_to_yuc (
                               gan_image_get_pixptr_rgb_us(rgb, r0s+r, c0s+c));
                   ucpix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_f_to_uc (
                              gan_pixel_rgbui_to_yf (
                                gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c)));
                   ucpix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_d_to_uc (
                               gan_pixel_rgbf_to_yf (
                                 gan_image_get_pixptr_rgb_f(rgb,r0s+r,c0s+c)));
                   ucpix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_d_to_uc (
                               gan_pixel_rgbd_to_yd (
                                 gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c)));
                   ucpix.A = UCHAR_MAX;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_USHORT:
        switch ( rgb->type )
        {
           Gan_GLAPixel_us uspix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_rgbuc_to_yus (
                               gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c));
                   uspix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_rgbus_to_yus (
                               gan_image_get_pixptr_rgb_us(rgb, r0s+r, c0s+c));
                   uspix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_f_to_us (
                              gan_pixel_rgbui_to_yf (
                                gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c)));
                   uspix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_f_to_us (
                               gan_pixel_rgbf_to_yf (
                                 gan_image_get_pixptr_rgb_f(rgb,r0s+r,c0s+c)));
                   uspix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_d_to_us (
                               gan_pixel_rgbd_to_yd (
                                 gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c)));
                   uspix.A = USHRT_MAX;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_UINT:
        switch ( rgb->type )
        {
           Gan_GLAPixel_ui uipix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_rgbuc_to_yui (
                               gan_image_get_pixptr_rgb_uc(rgb, r0s+r, c0s+c));
                   uipix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_us_to_ui (
                               gan_pixel_rgbus_to_yus (
                                gan_image_get_pixptr_rgb_us(rgb,r0s+r,c0s+c)));
                   uipix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_f_to_ui (
                               gan_pixel_rgbui_to_yf (
                                gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c)));
                   uipix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_f_to_ui (
                               gan_pixel_rgbf_to_yf (
                                 gan_image_get_pixptr_rgb_f(rgb,r0s+r,c0s+c)));
                   uipix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_d_to_ui (
                               gan_pixel_rgbd_to_yd (
                                 gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c)));
                   uipix.A = UINT_MAX;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_FLOAT:
        switch ( rgb->type )
        {
           Gan_GLAPixel_f fpix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_us_to_f (
                              gan_pixel_rgbuc_to_yus (
                                gan_image_get_pixptr_rgb_uc(rgb,r0s+r,c0s+c)));
                   fpix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_us_to_f (
                              gan_pixel_rgbus_to_yus (
                                gan_image_get_pixptr_rgb_us(rgb,r0s+r,c0s+c)));
                   fpix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_rgbui_to_yf (
                                gan_image_get_pixptr_rgb_ui(rgb,r0s+r,c0s+c));
                   fpix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_rgbf_to_yf (
                                gan_image_get_pixptr_rgb_f(rgb, r0s+r, c0s+c));
                   fpix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = (float)gan_pixel_rgbd_to_yd (
                                  gan_image_get_pixptr_rgb_d(rgb,r0s+r,c0s+c));
                   fpix.A = 1.0F;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_DOUBLE:
        switch ( rgb->type )
        {
           Gan_GLAPixel_d dpix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = gan_pixel_us_to_d (
                              gan_pixel_rgbuc_to_yus (
                                gan_image_get_pixptr_rgb_uc(rgb,r0s+r,c0s+c)));
                   dpix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = gan_pixel_us_to_d (
                              gan_pixel_rgbus_to_yus (
                                gan_image_get_pixptr_rgb_us(rgb,r0s+r,c0s+c)));
                   dpix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = (double)gan_pixel_rgbui_to_yf (
                               gan_image_get_pixptr_rgb_ui(rgb, r0s+r, c0s+c));
                   dpix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = (double)gan_pixel_rgbf_to_yf (
                               gan_image_get_pixptr_rgb_f(rgb, r0s+r, c0s+c) );
                   dpix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = gan_pixel_rgbd_to_yd (
                                gan_image_get_pixptr_rgb_d(rgb, r0s+r, c0s+c));
                   dpix.A = 1.0;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_rgb_to_gla", GAN_ERROR_NOT_IMPLEMENTED,
                           "" );
        return NULL;
   }

   return gla;
}

static Gan_Image *
 extract_rgba_to_gla ( Gan_Image *rgba, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *gla, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( rgba->format == GAN_RGB_COLOUR_ALPHA_IMAGE &&
                      gla->format == GAN_GREY_LEVEL_ALPHA_IMAGE,
                      "extract_rgba_to_gla", GAN_ERROR_INCOMPATIBLE, "" );

   switch ( gla->type )
   {
      case GAN_UCHAR:
        switch ( rgba->type )
        {
           Gan_GLAPixel_uc ucpix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_rgbauc_to_yuc (
                             gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c));
                   ucpix.A = rgba->row_data.rgba.uc[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_rgbaus_to_yuc (
                             gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c));
                   ucpix.A = gan_pixel_us_to_uc (
                                  rgba->row_data.rgba.us[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_f_to_uc (
                              gan_pixel_rgbaui_to_yf (
                              gan_image_get_pixptr_rgba_ui(rgba,r0s+r,c0s+c)));
                   ucpix.A = gan_pixel_ui_to_uc (
                                  rgba->row_data.rgba.ui[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_f_to_uc (
                              gan_pixel_rgbaf_to_yf (
                               gan_image_get_pixptr_rgba_f(rgba,r0s+r,c0s+c)));
                   ucpix.A = gan_pixel_f_to_uc (
                                  rgba->row_data.rgba.f[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   ucpix.I = gan_pixel_d_to_uc (
                              gan_pixel_rgbad_to_yd (
                               gan_image_get_pixptr_rgba_d(rgba,r0s+r,c0s+c)));
                   ucpix.A = gan_pixel_d_to_uc (
                                  rgba->row_data.rgba.d[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_uc ( gla, r0d+r, c0d+c, &ucpix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_USHORT:
        switch ( rgba->type )
        {
           Gan_GLAPixel_us uspix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_rgbauc_to_yus (
                             gan_image_get_pixptr_rgba_uc(rgba, r0s+r, c0s+c));
                   uspix.A = gan_pixel_uc_to_us (
                                  rgba->row_data.rgba.uc[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_rgbaus_to_yus (
                             gan_image_get_pixptr_rgba_us(rgba, r0s+r, c0s+c));
                   uspix.A = rgba->row_data.rgba.us[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_f_to_us (
                              gan_pixel_rgbaui_to_yf (
                              gan_image_get_pixptr_rgba_ui(rgba,r0s+r,c0s+c)));
                   uspix.A = gan_pixel_ui_to_us (
                                  rgba->row_data.rgba.ui[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_f_to_us (
                              gan_pixel_rgbaf_to_yf (
                               gan_image_get_pixptr_rgba_f(rgba,r0s+r,c0s+c)));
                   uspix.A = gan_pixel_f_to_us (
                                  rgba->row_data.rgba.f[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uspix.I = gan_pixel_d_to_us (
                              gan_pixel_rgbad_to_yd (
                               gan_image_get_pixptr_rgba_d(rgba,r0s+r,c0s+c)));
                   uspix.A = gan_pixel_d_to_us (
                                  rgba->row_data.rgba.d[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_us ( gla, r0d+r, c0d+c, &uspix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_UINT:
        switch ( rgba->type )
        {
           Gan_GLAPixel_ui uipix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_rgbauc_to_yui (
                               gan_image_get_pixptr_rgba_uc(rgba,r0s+r,c0s+c));
                   uipix.A = gan_pixel_uc_to_ui (
                                  rgba->row_data.rgba.uc[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_us_to_ui (
                              gan_pixel_rgbaus_to_yus (
                              gan_image_get_pixptr_rgba_us(rgba,r0s+r,c0s+c)));
                   uipix.A = gan_pixel_us_to_ui (
                                  rgba->row_data.rgba.us[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_f_to_ui (
                              gan_pixel_rgbaui_to_yf (
                              gan_image_get_pixptr_rgba_ui(rgba,r0s+r,c0s+c)));
                   uipix.A = rgba->row_data.rgba.ui[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_f_to_ui (
                              gan_pixel_rgbaf_to_yf (
                               gan_image_get_pixptr_rgba_f(rgba,r0s+r,c0s+c)));
                   uipix.A = gan_pixel_f_to_ui (
                                  rgba->row_data.rgba.f[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   uipix.I = gan_pixel_d_to_ui (
                              gan_pixel_rgbad_to_yd (
                               gan_image_get_pixptr_rgba_d(rgba,r0s+r,c0s+c)));
                   uipix.A = gan_pixel_d_to_ui (
                                  rgba->row_data.rgba.d[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_ui ( gla, r0d+r, c0d+c, &uipix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_FLOAT:
        switch ( rgba->type )
        {
           Gan_GLAPixel_f fpix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_us_to_f (
                             gan_pixel_rgbauc_to_yus (
                              gan_image_get_pixptr_rgba_uc(rgba,r0s+r,c0s+c)));
                   fpix.A = gan_pixel_uc_to_f (
                                  rgba->row_data.rgba.uc[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_us_to_f (
                             gan_pixel_rgbaus_to_yus (
                              gan_image_get_pixptr_rgba_us(rgba,r0s+r,c0s+c)));
                   fpix.A = gan_pixel_us_to_f (
                                  rgba->row_data.rgba.us[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_rgbaui_to_yf (
                             gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c));
                   fpix.A = gan_pixel_ui_to_f (
                                  rgba->row_data.rgba.ui[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = gan_pixel_rgbaf_to_yf (
                              gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c));
                   fpix.A = rgba->row_data.rgba.f[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   fpix.I = (float)gan_pixel_rgbad_to_yd (
                                gan_image_get_pixptr_rgba_d(rgba,r0s+r,c0s+c));
                   fpix.A = (float)rgba->row_data.rgba.d[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_f ( gla, r0d+r, c0d+c, &fpix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      case GAN_DOUBLE:
        switch ( rgba->type )
        {
           Gan_GLAPixel_d dpix;

           case GAN_UCHAR:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = gan_pixel_us_to_d (
                             gan_pixel_rgbauc_to_yus (
                              gan_image_get_pixptr_rgba_uc(rgba,r0s+r,c0s+c)));
                   dpix.A = gan_pixel_uc_to_d (
                                  rgba->row_data.rgba.uc[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_USHORT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = gan_pixel_us_to_d (
                             gan_pixel_rgbaus_to_yus (
                              gan_image_get_pixptr_rgba_us(rgba,r0s+r,c0s+c)));
                   dpix.A = gan_pixel_us_to_d (
                                  rgba->row_data.rgba.us[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_UINT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = (double)gan_pixel_rgbaui_to_yf (
                             gan_image_get_pixptr_rgba_ui(rgba, r0s+r, c0s+c));
                   dpix.A = gan_pixel_ui_to_d (
                                  rgba->row_data.rgba.ui[r0s+r][c0s+c].A );
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_FLOAT:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = (double)gan_pixel_rgbaf_to_yf (
                              gan_image_get_pixptr_rgba_f(rgba, r0s+r, c0s+c));
                   dpix.A = (double)rgba->row_data.rgba.f[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           case GAN_DOUBLE:
             for ( r=0; r < height; r++ )
                for ( c=0; c < width; c++ )
                {
                   dpix.I = gan_pixel_rgbad_to_yd (
                              gan_image_get_pixptr_rgba_d(rgba, r0s+r, c0s+c));
                   dpix.A = rgba->row_data.rgba.d[r0s+r][c0s+c].A;
                   gan_image_set_pix_gla_d ( gla, r0d+r, c0d+c, &dpix );
                }
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_gla",
                                GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;

      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_rgba_to_gla", GAN_ERROR_NOT_IMPLEMENTED,
                           "" );
        return NULL;
   }

   return gla;
}

/* Converts an RGB image to a different type
 *
 * The converted RGB image is returned.
 */
static Gan_Image *
 extract_rgb ( Gan_Image *source, unsigned r0s, unsigned c0s,
               unsigned height, unsigned width, Gan_Bool copy_pixels,
               Gan_Image *dest, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( source->format == GAN_RGB_COLOUR_IMAGE &&
                      dest->format == GAN_RGB_COLOUR_IMAGE,
                      "extract_rgb", GAN_ERROR_INCOMPATIBLE, "" );

   switch ( dest->type )
   {
      case GAN_UCHAR:
        switch ( source->type )
        {
           Gan_RGBPixel_uc ucpix;

           case GAN_UCHAR:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_uc ( (unsigned char *)
                                       &source->row_data.rgb.uc[r0s+r][c0s],
                                       1, 3*width, (unsigned char *)
                                       &dest->row_data.rgb.uc[r0d+r][c0d],1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgb",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgb.uc[r] =
                                          &source->row_data.rgb.uc[r0s+r][c0s];
             }
             break;
         
           case GAN_USHORT:
           {
              Gan_RGBPixel_us uspix;

              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    uspix = gan_image_get_pix_rgb_us ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_us_to_uc(uspix.R);
                    ucpix.G = gan_pixel_us_to_uc(uspix.G);
                    ucpix.B = gan_pixel_us_to_uc(uspix.B);
                    gan_image_set_pix_rgb_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_UINT:
           {
              Gan_RGBPixel_ui uipix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    uipix = gan_image_get_pix_rgb_ui ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_ui_to_uc(uipix.R);
                    ucpix.G = gan_pixel_ui_to_uc(uipix.G);
                    ucpix.B = gan_pixel_ui_to_uc(uipix.B);
                    gan_image_set_pix_rgb_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_FLOAT:
           {
              Gan_RGBPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgb_f ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_f_to_uc(fpix.R);
                    ucpix.G = gan_pixel_f_to_uc(fpix.G);
                    ucpix.B = gan_pixel_f_to_uc(fpix.B);
                    gan_image_set_pix_rgb_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgb_d ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_d_to_uc(dpix.R);
                    ucpix.G = gan_pixel_d_to_uc(dpix.G);
                    ucpix.B = gan_pixel_d_to_uc(dpix.B);
                    gan_image_set_pix_rgb_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
      
      case GAN_USHORT:
        switch ( source->type )
        {
           Gan_RGBPixel_us uspix;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc ucpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    ucpix = gan_image_get_pix_rgb_uc ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_uc_to_us(ucpix.R);
                    uspix.G = gan_pixel_uc_to_us(ucpix.G);
                    uspix.B = gan_pixel_uc_to_us(ucpix.B);
                    gan_image_set_pix_rgb_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_USHORT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_us ( (unsigned short *)
                                       &source->row_data.rgb.us[r0s+r][c0s],
                                       1, 3*width, (unsigned short *)
                                       &dest->row_data.rgb.us[r0d+r][c0d],1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgb",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgb.us[r] =
                                          &source->row_data.rgb.us[r0s+r][c0s];
             }
             break;
         
           case GAN_UINT:
           {
              Gan_RGBPixel_ui uipix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned short limits */
                    uipix = gan_image_get_pix_rgb_ui ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_ui_to_us(uipix.R);
                    uspix.G = gan_pixel_ui_to_us(uipix.G);
                    uspix.B = gan_pixel_ui_to_us(uipix.B);
                    gan_image_set_pix_rgb_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_FLOAT:
           {
              Gan_RGBPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgb_f ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_f_to_us(fpix.R);
                    uspix.G = gan_pixel_f_to_us(fpix.G);
                    uspix.B = gan_pixel_f_to_us(fpix.B);
                    gan_image_set_pix_rgb_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgb_d ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_d_to_us(dpix.R);
                    uspix.G = gan_pixel_d_to_us(dpix.G);
                    uspix.B = gan_pixel_d_to_us(dpix.B);
                    gan_image_set_pix_rgb_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
      
      case GAN_INT:
        switch ( source->type )
        {
           Gan_RGBPixel_i ipix;

           case GAN_INT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_i ( (int *)
                                       &source->row_data.rgb.i[r0s+r][c0s],
                                       1, 3*width, (int *)
                                       &dest->row_data.rgb.i[r0d+r][c0d], 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgb",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgb.i[r]=&source->row_data.rgb.i[r0s+r][c0s];
             }
             break;
         
           case GAN_FLOAT:
           {
              Gan_RGBPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgb_f ( source, r0s+r, c0s+c );
                    ipix.R = gan_pixel_f_to_i(fpix.R);
                    ipix.G = gan_pixel_f_to_i(fpix.G);
                    ipix.B = gan_pixel_f_to_i(fpix.B);
                    gan_image_set_pix_rgb_i ( dest, r0d+r, c0d+c, &ipix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgb_d ( source, r0s+r, c0s+c );
                    ipix.R = gan_pixel_d_to_i(dpix.R);
                    ipix.G = gan_pixel_d_to_i(dpix.G);
                    ipix.B = gan_pixel_d_to_i(dpix.B);
                    gan_image_set_pix_rgb_i ( dest, r0d+r, c0d+c, &ipix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
      
      case GAN_UINT:
        switch ( source->type )
        {
           Gan_RGBPixel_ui uipix;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc ucpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    ucpix = gan_image_get_pix_rgb_uc ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_uc_to_ui(ucpix.R);
                    uipix.G = gan_pixel_uc_to_ui(ucpix.G);
                    uipix.B = gan_pixel_uc_to_ui(ucpix.B);
                    gan_image_set_pix_rgb_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_USHORT:
           {
              Gan_RGBPixel_us uspix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    uspix = gan_image_get_pix_rgb_us ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_us_to_ui(uspix.R);
                    uipix.G = gan_pixel_us_to_ui(uspix.G);
                    uipix.B = gan_pixel_us_to_ui(uspix.B);
                    gan_image_set_pix_rgb_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_UINT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_ui ( (unsigned int *)
                                       &source->row_data.rgb.ui[r0s+r][c0s],
                                       1, 3*width, (unsigned int *)
                                       &dest->row_data.rgb.ui[r0d+r][c0d],1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgb",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgb.ui[r] =
                                          &source->row_data.rgb.ui[r0s+r][c0s];
             }
             break;
         
           case GAN_FLOAT:
           {
              Gan_RGBPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgb_f ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_f_to_ui(fpix.R);
                    uipix.G = gan_pixel_f_to_ui(fpix.G);
                    uipix.B = gan_pixel_f_to_ui(fpix.B);
                    gan_image_set_pix_rgb_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGB pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgb_d ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_d_to_ui(dpix.R);
                    uipix.G = gan_pixel_d_to_ui(dpix.G);
                    uipix.B = gan_pixel_d_to_ui(dpix.B);
                    gan_image_set_pix_rgb_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
      
      case GAN_FLOAT:
        switch ( source->type )
        {
           Gan_RGBPixel_f fpix;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc ucpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    ucpix = gan_image_get_pix_rgb_uc ( source, r0s+r, c0s+c );
                    fpix.R = gan_pixel_uc_to_f(ucpix.R);
                    fpix.G = gan_pixel_uc_to_f(ucpix.G);
                    fpix.B = gan_pixel_uc_to_f(ucpix.B);
                    gan_image_set_pix_rgb_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_USHORT:
           {
              Gan_RGBPixel_us uspix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uspix = gan_image_get_pix_rgb_us ( source, r0s+r, c0s+c );
                    fpix.R = gan_pixel_us_to_f(uspix.R);
                    fpix.G = gan_pixel_us_to_f(uspix.G);
                    fpix.B = gan_pixel_us_to_f(uspix.B);
                    gan_image_set_pix_rgb_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_UINT:
           {
              Gan_RGBPixel_ui uipix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uipix = gan_image_get_pix_rgb_ui ( source, r0s+r, c0s+c );
                    fpix.R = gan_pixel_ui_to_f(uipix.R);
                    fpix.G = gan_pixel_ui_to_f(uipix.G);
                    fpix.B = gan_pixel_ui_to_f(uipix.B);
                    gan_image_set_pix_rgb_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_FLOAT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_f ( (float *)
                                      &source->row_data.rgb.f[r0s+r][c0s],
                                      1, 3*width, (float *)
                                      &dest->row_data.rgb.f[r0d+r][c0d], 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgb",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgb.f[r] =
                                          &source->row_data.rgb.f[r0s+r][c0s];
             }
             break;
            
           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d dpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    dpix = gan_image_get_pix_rgb_d ( source, r0s+r, c0s+c );
                    fpix.R = (float)dpix.R;
                    fpix.G = (float)dpix.G;
                    fpix.B = (float)dpix.B;
                    gan_image_set_pix_rgb_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
         
      case GAN_DOUBLE:
        switch ( source->type )
        {
           Gan_RGBPixel_d dpix;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc ucpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    ucpix = gan_image_get_pix_rgb_uc ( source, r0s+r, c0s+c );
                    dpix.R = gan_pixel_uc_to_d(ucpix.R);
                    dpix.G = gan_pixel_uc_to_d(ucpix.G);
                    dpix.B = gan_pixel_uc_to_d(ucpix.B);
                    gan_image_set_pix_rgb_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_USHORT:
           {
              Gan_RGBPixel_us uspix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uspix = gan_image_get_pix_rgb_us ( source, r0s+r, c0s+c );
                    dpix.R = gan_pixel_us_to_d(uspix.R);
                    dpix.G = gan_pixel_us_to_d(uspix.G);
                    dpix.B = gan_pixel_us_to_d(uspix.B);
                    gan_image_set_pix_rgb_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_UINT:
           {
              Gan_RGBPixel_ui uipix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uipix = gan_image_get_pix_rgb_ui ( source, r0s+r, c0s+c );
                    dpix.R = gan_pixel_ui_to_d(uipix.R);
                    dpix.G = gan_pixel_ui_to_d(uipix.G);
                    dpix.B = gan_pixel_ui_to_d(uipix.B);
                    gan_image_set_pix_rgb_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_FLOAT:
           {
              Gan_RGBPixel_f fpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgb",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    fpix = gan_image_get_pix_rgb_f ( source, r0s+r, c0s+c );
                    dpix.R = (double)fpix.R;
                    dpix.G = (double)fpix.G;
                    dpix.B = (double)fpix.B;
                    gan_image_set_pix_rgb_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_DOUBLE:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_d ( (double *)
                                      &source->row_data.rgb.d[r0s+r][c0s],
                                      1, 3*width, (double *)
                                      &dest->row_data.rgb.d[r0d+r][c0d], 1 );
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgb",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgb.d[r] =
                                          &source->row_data.rgb.d[r0s+r][c0s];
             }
             break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
             return NULL;
        }
        break;
         
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_rgb", GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }
   
   return dest;
}

/*
 * Converts the RGB image with alpha channel rgba to an RGB image rgb.
 * The RGB values are copied and the alpha channel is stripped out.
 *
 * The RGB image is returned.
 */
static Gan_Image *
 extract_rgba_to_rgb ( Gan_Image *rgba, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *rgb, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( rgba->format == GAN_RGB_COLOUR_ALPHA_IMAGE &&
                      rgb->format == GAN_RGB_COLOUR_IMAGE,
                      "extract_rgba_to_rgb", GAN_ERROR_INCOMPATIBLE, "" );
   switch ( rgba->type )
   {
      case GAN_UCHAR:
        switch ( rgb->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pixa;
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_uc(rgba,r0s+r,c0s+c);
                    pix.R = pixa.R;
                    pix.G = pixa.G;
                    pix.B = pixa.B;
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_uc pixa;
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_uc(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_uc_to_us(pixa.R);
                    pix.G = gan_pixel_uc_to_us(pixa.G);
                    pix.B = gan_pixel_uc_to_us(pixa.B);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_uc pixa;
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_uc(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_uc_to_ui(pixa.R);
                    pix.G = gan_pixel_uc_to_ui(pixa.G);
                    pix.B = gan_pixel_uc_to_ui(pixa.B);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_uc pixa;
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_uc(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_uc_to_f(pixa.R);
                    pix.G = gan_pixel_uc_to_f(pixa.G);
                    pix.B = gan_pixel_uc_to_f(pixa.B);
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_uc pixa;
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_uc(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_uc_to_d(pixa.R);
                    pix.G = gan_pixel_uc_to_d(pixa.G);
                    pix.B = gan_pixel_uc_to_d(pixa.B);
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba_to_rgb", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( rgb->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBAPixel_us pixa;
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_us(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_us_to_uc(pixa.R);
                    pix.G = gan_pixel_us_to_uc(pixa.G);
                    pix.B = gan_pixel_us_to_uc(pixa.B);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pixa;
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_us(rgba,r0s+r,c0s+c);
                    pix.R = pixa.R;
                    pix.G = pixa.G;
                    pix.B = pixa.B;
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_us pixa;
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_us(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_us_to_ui(pixa.R);
                    pix.G = gan_pixel_us_to_ui(pixa.G);
                    pix.B = gan_pixel_us_to_ui(pixa.B);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_us pixa;
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_us(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_us_to_f(pixa.R);
                    pix.G = gan_pixel_us_to_f(pixa.G);
                    pix.B = gan_pixel_us_to_f(pixa.B);
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_us pixa;
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_us(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_us_to_d(pixa.R);
                    pix.G = gan_pixel_us_to_d(pixa.G);
                    pix.B = gan_pixel_us_to_d(pixa.B);
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_UINT:
        switch ( rgb->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBAPixel_ui pixa;
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_ui(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_ui_to_uc(pixa.R);
                    pix.G = gan_pixel_ui_to_uc(pixa.G);
                    pix.B = gan_pixel_ui_to_uc(pixa.B);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_ui pixa;
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_ui(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_ui_to_us(pixa.R);
                    pix.G = gan_pixel_ui_to_us(pixa.G);
                    pix.B = gan_pixel_ui_to_us(pixa.B);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pixa;
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_ui(rgba,r0s+r,c0s+c);
                    pix.R = pixa.R;
                    pix.G = pixa.G;
                    pix.B = pixa.B;
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_ui pixa;
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_ui(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_ui_to_f(pixa.R);
                    pix.G = gan_pixel_ui_to_f(pixa.G);
                    pix.B = gan_pixel_ui_to_f(pixa.B);
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_ui pixa;
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_ui(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_ui_to_d(pixa.R);
                    pix.G = gan_pixel_ui_to_d(pixa.G);
                    pix.B = gan_pixel_ui_to_d(pixa.B);
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_FLOAT:
        switch ( rgb->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBAPixel_f pixa;
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_f(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_f_to_uc(pixa.R);
                    pix.G = gan_pixel_f_to_uc(pixa.G);
                    pix.B = gan_pixel_f_to_uc(pixa.B);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_f pixa;
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_f(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_f_to_us(pixa.R);
                    pix.G = gan_pixel_f_to_us(pixa.G);
                    pix.B = gan_pixel_f_to_us(pixa.B);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_f pixa;
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_f(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_f_to_ui(pixa.R);
                    pix.G = gan_pixel_f_to_ui(pixa.G);
                    pix.B = gan_pixel_f_to_ui(pixa.B);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pixa;
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_f(rgba,r0s+r,c0s+c);
                    pix.R = pixa.R;
                    pix.G = pixa.G;
                    pix.B = pixa.B;
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_f pixa;
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_f(rgba,r0s+r,c0s+c);
                    pix.R = (double)pixa.R;
                    pix.G = (double)pixa.G;
                    pix.B = (double)pixa.B;
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_DOUBLE:
        switch ( rgb->type )
        {
           case GAN_UCHAR:
           {
              Gan_RGBAPixel_d pixa;
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_d(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_d_to_uc(pixa.R);
                    pix.G = gan_pixel_d_to_uc(pixa.G);
                    pix.B = gan_pixel_d_to_uc(pixa.B);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_d pixa;
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_d(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_d_to_us(pixa.R);
                    pix.G = gan_pixel_d_to_us(pixa.G);
                    pix.B = gan_pixel_d_to_us(pixa.B);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_d pixa;
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_d(rgba,r0s+r,c0s+c);
                    pix.R = gan_pixel_d_to_ui(pixa.R);
                    pix.G = gan_pixel_d_to_ui(pixa.G);
                    pix.B = gan_pixel_d_to_ui(pixa.B);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_d pixa;
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_d(rgba,r0s+r,c0s+c);
                    pix.R = (float)pixa.R;
                    pix.G = (float)pixa.G;
                    pix.B = (float)pixa.B;
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pixa;
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_rgba_d(rgba,r0s+r,c0s+c);
                    pix.R = pixa.R;
                    pix.G = pixa.G;
                    pix.B = pixa.B;
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

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

   /* success */
   return rgb;
}

/*
 * Converts the grey level image gla with alpha channel into RGB image
 * rgb. The alpha channel of gla is stripped out.
 */
static Gan_Image *
 extract_gla_to_rgb ( Gan_Image *gla, unsigned r0s, unsigned c0s,
                      unsigned height, unsigned width,
                      Gan_Image *rgb, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( gla->format == GAN_GREY_LEVEL_ALPHA_IMAGE &&
                      rgb->format == GAN_RGB_COLOUR_IMAGE,
                      "extract_gla_to_rgb", GAN_ERROR_INCOMPATIBLE, "" );
   switch ( gla->type )
   {
      case GAN_UCHAR:
        switch ( rgb->type )
        {
           Gan_GLAPixel_uc pixa;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_us(pixa.I);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_ui(pixa.I);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_f(pixa.I);
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_d(pixa.I);
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_rgb", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( rgb->type )
        {
           Gan_GLAPixel_us pixa;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_uc(pixa.I);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_ui(pixa.I);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_f(pixa.I);
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_d(pixa.I);
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_UINT:
        switch ( rgb->type )
        {
           Gan_GLAPixel_ui pixa;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_uc(pixa.I);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_us(pixa.I);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_f(pixa.I);
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_d(pixa.I);
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_FLOAT:
        switch ( rgb->type )
        {
           Gan_GLAPixel_f pixa;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_f_to_uc(pixa.I);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_f_to_us(pixa.I);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_f_to_ui(pixa.I);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = (double)pixa.I;
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_DOUBLE:
        switch ( rgb->type )
        {
           Gan_GLAPixel_d pixa;

           case GAN_UCHAR:
           {
              Gan_RGBPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_d_to_uc(pixa.I);
                    gan_image_set_pix_rgb_uc(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_d_to_us(pixa.I);
                    gan_image_set_pix_rgb_us(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_d_to_ui(pixa.I);
                    gan_image_set_pix_rgb_ui(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = (float)pixa.I;
                    gan_image_set_pix_rgb_f(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    gan_image_set_pix_rgb_d(rgb,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

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

   /* success */
   return rgb;
}

/*
 * Converts the grey level image gla with alpha channel into RGB image
 * with alpha channel rgba.
 */
static Gan_Image *
 extract_gla_to_rgba ( Gan_Image *gla, unsigned r0s, unsigned c0s,
                      unsigned height, unsigned width,
                      Gan_Image *rgba, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( gla->format == GAN_GREY_LEVEL_ALPHA_IMAGE &&
                      rgba->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "extract_gla_to_rgba", GAN_ERROR_INCOMPATIBLE, "" );
   switch ( gla->type )
   {
      case GAN_UCHAR:
        switch ( rgba->type )
        {
           Gan_GLAPixel_uc pixa;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    pix.A = pixa.A;
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_us(pixa.I);
                    pix.A = gan_pixel_uc_to_us(pixa.A);
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_ui(pixa.I);
                    pix.A = gan_pixel_uc_to_ui(pixa.A);
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_f(pixa.I);
                    pix.A = gan_pixel_uc_to_f(pixa.A);
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_uc(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_uc_to_d(pixa.I);
                    pix.A = gan_pixel_uc_to_d(pixa.A);
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_gla_to_rgba", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( rgba->type )
        {
           Gan_GLAPixel_us pixa;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_uc(pixa.I);
                    pix.A = gan_pixel_us_to_uc(pixa.A);
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    pix.A = pixa.A;
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_ui(pixa.I);
                    pix.A = gan_pixel_us_to_ui(pixa.A);
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_f(pixa.I);
                    pix.A = gan_pixel_us_to_f(pixa.A);
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_us(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_us_to_d(pixa.I);
                    pix.A = gan_pixel_us_to_d(pixa.A);
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_UINT:
        switch ( rgba->type )
        {
           Gan_GLAPixel_ui pixa;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_uc(pixa.I);
                    pix.A = gan_pixel_ui_to_uc(pixa.A);
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_us(pixa.I);
                    pix.A = gan_pixel_ui_to_us(pixa.A);
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    pix.A = pixa.A;
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_f(pixa.I);
                    pix.A = gan_pixel_ui_to_f(pixa.A);
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_ui(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_ui_to_d(pixa.I);
                    pix.A = gan_pixel_ui_to_d(pixa.A);
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_FLOAT:
        switch ( rgba->type )
        {
           Gan_GLAPixel_f pixa;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_f_to_uc(pixa.I);
                    pix.A = gan_pixel_f_to_uc(pixa.A);
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_f_to_us(pixa.I);
                    pix.A = gan_pixel_f_to_us(pixa.A);
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_f_to_ui(pixa.I);
                    pix.A = gan_pixel_f_to_ui(pixa.A);
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    pix.A = pixa.A;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_f(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = (double)pixa.I;
                    pix.A = (double)pixa.A;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

      case GAN_DOUBLE:
        switch ( rgba->type )
        {
           Gan_GLAPixel_d pixa;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_d_to_uc(pixa.I);
                    pix.A = gan_pixel_d_to_uc(pixa.A);
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_d_to_us(pixa.I);
                    pix.A = gan_pixel_d_to_us(pixa.A);
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = gan_pixel_d_to_ui(pixa.I);
                    pix.A = gan_pixel_d_to_ui(pixa.A);
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = (float)pixa.I;
                    pix.A = (float)pixa.A;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pix;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pixa = gan_image_get_pix_gla_d(gla,r0s+r,c0s+c);
                    pix.R = pix.G = pix.B = pixa.I;
                    pix.A = pixa.A;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pix);
                 }
           }
           break;

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

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

   /* success */
   return rgba;
}

/* Converts an RGB image with alpha channel to a different type
 *
 * The converted RGB image is returned.
 */
static Gan_Image *
 extract_rgba ( Gan_Image *source, unsigned r0s, unsigned c0s,
                unsigned height, unsigned width, Gan_Bool copy_pixels,
                Gan_Image *dest, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( source->format == GAN_RGB_COLOUR_ALPHA_IMAGE &&
                      dest->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "extract_rgba", GAN_ERROR_INCOMPATIBLE, "" );
   
   switch ( dest->type )
   {
      case GAN_UCHAR:
        switch ( source->type )
        {
           Gan_RGBAPixel_uc ucpix;

           case GAN_UCHAR:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_uc ((unsigned char *)
                                      &source->row_data.rgba.uc[r0s+r][c0s],
                                      1, 4*width, (unsigned char *)
                                      &dest->row_data.rgba.uc[r0d+r][c0d],1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgba",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgba.uc[r] =
                                         &source->row_data.rgba.uc[r0s+r][c0s];
             }
             break;
         
           case GAN_USHORT:
           {
              Gan_RGBAPixel_us uspix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    uspix = gan_image_get_pix_rgba_us ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_us_to_uc(uspix.R);
                    ucpix.G = gan_pixel_us_to_uc(uspix.G);
                    ucpix.B = gan_pixel_us_to_uc(uspix.B);
                    ucpix.A = gan_pixel_us_to_uc(uspix.A);
                    gan_image_set_pix_rgba_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_UINT:
           {
              Gan_RGBAPixel_ui uipix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    uipix = gan_image_get_pix_rgba_ui ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_ui_to_uc(uipix.R);
                    ucpix.G = gan_pixel_ui_to_uc(uipix.G);
                    ucpix.B = gan_pixel_ui_to_uc(uipix.B);
                    ucpix.A = gan_pixel_ui_to_uc(uipix.A);
                    gan_image_set_pix_rgba_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgba_f ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_f_to_uc(fpix.R);
                    ucpix.G = gan_pixel_f_to_uc(fpix.G);
                    ucpix.B = gan_pixel_f_to_uc(fpix.B);
                    ucpix.A = gan_pixel_f_to_uc(fpix.A);
                    gan_image_set_pix_rgba_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgba_d ( source, r0s+r, c0s+c );
                    ucpix.R = gan_pixel_d_to_uc(dpix.R);
                    ucpix.G = gan_pixel_d_to_uc(dpix.G);
                    ucpix.B = gan_pixel_d_to_uc(dpix.B);
                    ucpix.A = gan_pixel_d_to_uc(dpix.A);
                    gan_image_set_pix_rgba_uc ( dest, r0d+r, c0d+c, &ucpix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED,
                                "" );
             return NULL;
        }
        break;
      
      case GAN_USHORT:
        switch ( source->type )
        {
           Gan_RGBAPixel_us uspix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc ucpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    ucpix = gan_image_get_pix_rgba_uc ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_uc_to_us(ucpix.R);
                    uspix.G = gan_pixel_uc_to_us(ucpix.G);
                    uspix.B = gan_pixel_uc_to_us(ucpix.B);
                    uspix.A = gan_pixel_uc_to_us(ucpix.A);
                    gan_image_set_pix_rgba_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_USHORT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_us ((unsigned short *)
                                      &source->row_data.rgba.us[r0s+r][c0s],
                                      1, 4*width, (unsigned short *)
                                      &dest->row_data.rgba.us[r0d+r][c0d], 1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgba",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgba.us[r] =
                                         &source->row_data.rgba.us[r0s+r][c0s];
             }
             break;
         
           case GAN_UINT:
           {
              Gan_RGBAPixel_ui uipix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    uipix = gan_image_get_pix_rgba_ui ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_ui_to_us(uipix.R);
                    uspix.G = gan_pixel_ui_to_us(uipix.G);
                    uspix.B = gan_pixel_ui_to_us(uipix.B);
                    uspix.A = gan_pixel_ui_to_us(uipix.A);
                    gan_image_set_pix_rgba_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgba_f ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_f_to_us(fpix.R);
                    uspix.G = gan_pixel_f_to_us(fpix.G);
                    uspix.B = gan_pixel_f_to_us(fpix.B);
                    uspix.A = gan_pixel_f_to_us(fpix.A);
                    gan_image_set_pix_rgba_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgba_d ( source, r0s+r, c0s+c );
                    uspix.R = gan_pixel_d_to_us(dpix.R);
                    uspix.G = gan_pixel_d_to_us(dpix.G);
                    uspix.B = gan_pixel_d_to_us(dpix.B);
                    uspix.A = gan_pixel_d_to_us(dpix.A);
                    gan_image_set_pix_rgba_us ( dest, r0d+r, c0d+c, &uspix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_INT:
        switch ( source->type )
        {
           Gan_RGBAPixel_i ipix;

           case GAN_INT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_i ((int *)
                                      &source->row_data.rgba.i[r0s+r][c0s],
                                      1, 4*width, (int *)
                                      &dest->row_data.rgba.i[r0d+r][c0d], 1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgba",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgba.i[r] =
                                          &source->row_data.rgba.i[r0s+r][c0s];
             }
             break;
         
           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgba_f ( source, r0s+r, c0s+c );
                    ipix.R = gan_pixel_f_to_i(fpix.R);
                    ipix.G = gan_pixel_f_to_i(fpix.G);
                    ipix.B = gan_pixel_f_to_i(fpix.B);
                    ipix.A = gan_pixel_f_to_i(fpix.A);
                    gan_image_set_pix_rgba_i ( dest, r0d+r, c0d+c, &ipix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgba_d ( source, r0s+r, c0s+c );
                    ipix.R = gan_pixel_d_to_i(dpix.R);
                    ipix.G = gan_pixel_d_to_i(dpix.G);
                    ipix.B = gan_pixel_d_to_i(dpix.B);
                    ipix.A = gan_pixel_d_to_i(dpix.A);
                    gan_image_set_pix_rgba_i ( dest, r0d+r, c0d+c, &ipix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_UINT:
        switch ( source->type )
        {
           Gan_RGBAPixel_ui uipix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc ucpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    ucpix = gan_image_get_pix_rgba_uc ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_uc_to_ui(ucpix.R);
                    uipix.G = gan_pixel_uc_to_ui(ucpix.G);
                    uipix.B = gan_pixel_uc_to_ui(ucpix.B);
                    uipix.A = gan_pixel_uc_to_ui(ucpix.A);
                    gan_image_set_pix_rgba_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_USHORT:
           {
              Gan_RGBAPixel_us uspix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    uspix = gan_image_get_pix_rgba_us ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_us_to_ui(uspix.R);
                    uipix.G = gan_pixel_us_to_ui(uspix.G);
                    uipix.B = gan_pixel_us_to_ui(uspix.B);
                    uipix.A = gan_pixel_us_to_ui(uspix.A);
                    gan_image_set_pix_rgba_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_UINT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_ui ((unsigned int *)
                                      &source->row_data.rgba.ui[r0s+r][c0s],
                                      1, 4*width, (unsigned int *)
                                      &dest->row_data.rgba.ui[r0d+r][c0d], 1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgba",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgba.ui[r] =
                                         &source->row_data.rgba.ui[r0s+r][c0s];
             }
             break;
         
           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f fpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    fpix = gan_image_get_pix_rgba_f ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_f_to_ui(fpix.R);
                    uipix.G = gan_pixel_f_to_ui(fpix.G);
                    uipix.B = gan_pixel_f_to_ui(fpix.B);
                    uipix.A = gan_pixel_f_to_ui(fpix.A);
                    gan_image_set_pix_rgba_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d dpix;
            
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    /* clip RGBA pixel values to unsigned character limits */
                    dpix = gan_image_get_pix_rgba_d ( source, r0s+r, c0s+c );
                    uipix.R = gan_pixel_d_to_ui(dpix.R);
                    uipix.G = gan_pixel_d_to_ui(dpix.G);
                    uipix.B = gan_pixel_d_to_ui(dpix.B);
                    uipix.A = gan_pixel_d_to_ui(dpix.A);
                    gan_image_set_pix_rgba_ui ( dest, r0d+r, c0d+c, &uipix );
                 }
           }
           break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
      
      case GAN_FLOAT:
        switch ( source->type )
        {
           Gan_RGBAPixel_f fpix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc ucpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    ucpix = gan_image_get_pix_rgba_uc ( source, r0s+r, c0s+c );
                    fpix.R = gan_pixel_uc_to_f(ucpix.R);
                    fpix.G = gan_pixel_uc_to_f(ucpix.G);
                    fpix.B = gan_pixel_uc_to_f(ucpix.B);
                    fpix.A = gan_pixel_uc_to_f(ucpix.A);
                    gan_image_set_pix_rgba_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_USHORT:
           {
              Gan_RGBAPixel_us uspix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uspix = gan_image_get_pix_rgba_us ( source, r0s+r, c0s+c );
                    fpix.R = gan_pixel_us_to_f(uspix.R);
                    fpix.G = gan_pixel_us_to_f(uspix.G);
                    fpix.B = gan_pixel_us_to_f(uspix.B);
                    fpix.A = gan_pixel_us_to_f(uspix.A);
                    gan_image_set_pix_rgba_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_UINT:
           {
              Gan_RGBAPixel_ui uipix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uipix = gan_image_get_pix_rgba_ui ( source, r0s+r, c0s+c );
                    fpix.R = gan_pixel_ui_to_f(uipix.R);
                    fpix.G = gan_pixel_ui_to_f(uipix.G);
                    fpix.B = gan_pixel_ui_to_f(uipix.B);
                    fpix.A = gan_pixel_ui_to_f(uipix.A);
                    gan_image_set_pix_rgba_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           case GAN_FLOAT:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_f ( (float *)
                                      &source->row_data.rgba.f[r0s+r][c0s],
                                      1, 4*width, (float *)
                                      &dest->row_data.rgba.f[r0d+r][c0d], 1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgba",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgba.f[r] =
                                         &source->row_data.rgba.f[r0s+r][c0s];
             }
             break;
            
           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d dpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    dpix = gan_image_get_pix_rgba_d ( source, r0s+r, c0s+c );
                    fpix.R = (float)dpix.R;
                    fpix.G = (float)dpix.G;
                    fpix.B = (float)dpix.B;
                    fpix.A = (float)dpix.A;
                    gan_image_set_pix_rgba_f ( dest, r0d+r, c0d+c, &fpix );
                 }
           }
           break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
         
      case GAN_DOUBLE:
        switch ( source->type )
        {
           Gan_RGBAPixel_d dpix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc ucpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    ucpix = gan_image_get_pix_rgba_uc ( source, r0s+r, c0s+c );
                    dpix.R = gan_pixel_uc_to_d(ucpix.R);
                    dpix.G = gan_pixel_uc_to_d(ucpix.G);
                    dpix.B = gan_pixel_uc_to_d(ucpix.B);
                    dpix.A = gan_pixel_uc_to_d(ucpix.A);
                    gan_image_set_pix_rgba_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_USHORT:
           {
              Gan_RGBAPixel_us uspix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uspix = gan_image_get_pix_rgba_us ( source, r0s+r, c0s+c );
                    dpix.R = gan_pixel_us_to_d(uspix.R);
                    dpix.G = gan_pixel_us_to_d(uspix.G);
                    dpix.B = gan_pixel_us_to_d(uspix.B);
                    dpix.A = gan_pixel_us_to_d(uspix.A);
                    gan_image_set_pix_rgba_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_UINT:
           {
              Gan_RGBAPixel_ui uipix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    uipix = gan_image_get_pix_rgba_ui ( source, r0s+r, c0s+c );
                    dpix.R = gan_pixel_ui_to_d(uipix.R);
                    dpix.G = gan_pixel_ui_to_d(uipix.G);
                    dpix.B = gan_pixel_ui_to_d(uipix.B);
                    dpix.A = gan_pixel_ui_to_d(uipix.A);
                    gan_image_set_pix_rgba_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f fpix;
               
              gan_err_test_ptr ( copy_pixels, "extract_rgba",
                                 GAN_ERROR_ILLEGAL_ARGUMENT, "" );
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    fpix = gan_image_get_pix_rgba_f ( source, r0s+r, c0s+c );
                    dpix.R = (double)fpix.R;
                    dpix.G = (double)fpix.G;
                    dpix.B = (double)fpix.B;
                    dpix.A = (double)fpix.A;
                    gan_image_set_pix_rgba_d ( dest, r0d+r, c0d+c, &dpix );
                 }
           }
           break;
            
           case GAN_DOUBLE:
             if ( copy_pixels )
                for ( r=0; r < height; r++ )
                   gan_copy_array_d ( (double *)
                                      &source->row_data.rgba.d[r0s+r][c0s],
                                      1, 4*width, (double *)
                                      &dest->row_data.rgba.d[r0d+r][c0d], 1);
             else
             {
                /* make destination image point into source image */
                gan_err_test_ptr ( r0d == 0 && c0d == 0, "extract_rgba",
                                   GAN_ERROR_INCOMPATIBLE, "" );
                for ( r=0; r < height; r++ )
                   dest->row_data.rgba.d[r] =
                                         &source->row_data.rgba.d[r0s+r][c0s];
             }
             break;
            
           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED, "");
             return NULL;
        }
        break;
         
      default:
        gan_err_flush_trace();
        gan_err_register ( "extract_rgba", GAN_ERROR_NOT_IMPLEMENTED, "" );
        return NULL;
   }
   
   return dest;
}

/*
 * Converts the RGB image rgb to an RGB image with alpha channel rgba.
 * The alpha channel is set to one.
 *
 * The RGBA image is returned.
 */
static Gan_Image *
 extract_rgb_to_rgba ( Gan_Image *rgb, unsigned r0s, unsigned c0s,
                       unsigned height, unsigned width,
                       Gan_Image *rgba, unsigned r0d, unsigned c0d )
{
   unsigned int r, c;
   
   gan_err_test_ptr ( rgb->format == GAN_RGB_COLOUR_IMAGE &&
                      rgba->format == GAN_RGB_COLOUR_ALPHA_IMAGE,
                      "extract_rgb_to_rgba", GAN_ERROR_INCOMPATIBLE, "" );
   switch ( rgb->type )
   {
      case GAN_UCHAR:
        switch ( rgba->type )
        {
           Gan_RGBPixel_uc pix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_uc(rgb,r0s+r,c0s+c);
                    pixa.R = pix.R;
                    pixa.G = pix.G;
                    pixa.B = pix.B;
                    pixa.A = UCHAR_MAX;
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_uc(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_uc_to_us(pix.R);
                    pixa.G = gan_pixel_uc_to_us(pix.G);
                    pixa.B = gan_pixel_uc_to_us(pix.B);
                    pixa.A = USHRT_MAX;
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_uc(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_uc_to_ui(pix.R);
                    pixa.G = gan_pixel_uc_to_ui(pix.G);
                    pixa.B = gan_pixel_uc_to_ui(pix.B);
                    pixa.A = UINT_MAX;
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_uc(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_uc_to_f(pix.R);
                    pixa.G = gan_pixel_uc_to_f(pix.G);
                    pixa.B = gan_pixel_uc_to_f(pix.B);
                    pixa.A = 1.0F;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_uc(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_uc_to_d(pix.R);
                    pixa.G = gan_pixel_uc_to_d(pix.G);
                    pixa.B = gan_pixel_uc_to_d(pix.B);
                    pixa.A = 1.0;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "extract_rgb_to_rgba", GAN_ERROR_ILLEGAL_TYPE,
                                "" );
             return NULL;
        }
        break;
        
      case GAN_USHORT:
        switch ( rgba->type )
        {
           Gan_RGBPixel_us pix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_us(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_us_to_uc(pix.R);
                    pixa.G = gan_pixel_us_to_uc(pix.G);
                    pixa.B = gan_pixel_us_to_uc(pix.B);
                    pixa.A = UCHAR_MAX;
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_us(rgb,r0s+r,c0s+c);
                    pixa.R = pix.R;
                    pixa.G = pix.G;
                    pixa.B = pix.B;
                    pixa.A = USHRT_MAX;
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_us(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_us_to_ui(pix.R);
                    pixa.G = gan_pixel_us_to_ui(pix.G);
                    pixa.B = gan_pixel_us_to_ui(pix.B);
                    pixa.A = UINT_MAX;
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_us(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_us_to_f(pix.R);
                    pixa.G = gan_pixel_us_to_f(pix.G);
                    pixa.B = gan_pixel_us_to_f(pix.B);
                    pixa.A = 1.0F;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_us(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_us_to_d(pix.R);
                    pixa.G = gan_pixel_us_to_d(pix.G);
                    pixa.B = gan_pixel_us_to_d(pix.B);
                    pixa.A = 1.0;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

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

      case GAN_UINT:
        switch ( rgba->type )
        {
           Gan_RGBPixel_ui pix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_ui(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_ui_to_uc(pix.R);
                    pixa.G = gan_pixel_ui_to_uc(pix.G);
                    pixa.B = gan_pixel_ui_to_uc(pix.B);
                    pixa.A = UCHAR_MAX;
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_ui(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_ui_to_us(pix.R);
                    pixa.G = gan_pixel_ui_to_us(pix.G);
                    pixa.B = gan_pixel_ui_to_us(pix.B);
                    pixa.A = USHRT_MAX;
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_ui(rgb,r0s+r,c0s+c);
                    pixa.R = pix.R;
                    pixa.G = pix.G;
                    pixa.B = pix.B;
                    pixa.A = UINT_MAX;
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_ui(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_ui_to_f(pix.R);
                    pixa.G = gan_pixel_ui_to_f(pix.G);
                    pixa.B = gan_pixel_ui_to_f(pix.B);
                    pixa.A = 1.0F;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_ui(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_ui_to_d(pix.R);
                    pixa.G = gan_pixel_ui_to_d(pix.G);
                    pixa.B = gan_pixel_ui_to_d(pix.B);
                    pixa.A = 1.0;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

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

      case GAN_FLOAT:
        switch ( rgba->type )
        {
           Gan_RGBPixel_f pix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_f(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_f_to_uc(pix.R);
                    pixa.G = gan_pixel_f_to_uc(pix.G);
                    pixa.B = gan_pixel_f_to_uc(pix.B);
                    pixa.A = UCHAR_MAX;
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_f(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_f_to_us(pix.R);
                    pixa.G = gan_pixel_f_to_us(pix.G);
                    pixa.B = gan_pixel_f_to_us(pix.B);
                    pixa.A = USHRT_MAX;
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_f(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_f_to_ui(pix.R);
                    pixa.G = gan_pixel_f_to_ui(pix.G);
                    pixa.B = gan_pixel_f_to_ui(pix.B);
                    pixa.A = UINT_MAX;
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_f(rgb,r0s+r,c0s+c);
                    pixa.R = pix.R;
                    pixa.G = pix.G;
                    pixa.B = pix.B;
                    pixa.A = 1.0F;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_f(rgb,r0s+r,c0s+c);
                    pixa.R = (double)pix.R;
                    pixa.G = (double)pix.G;
                    pixa.B = (double)pix.B;
                    pixa.A = 1.0;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

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

      case GAN_DOUBLE:
        switch ( rgba->type )
        {
           Gan_RGBPixel_d pix;

           case GAN_UCHAR:
           {
              Gan_RGBAPixel_uc pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_d(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_d_to_uc(pix.R);
                    pixa.G = gan_pixel_d_to_uc(pix.G);
                    pixa.B = gan_pixel_d_to_uc(pix.B);
                    pixa.A = UCHAR_MAX;
                    gan_image_set_pix_rgba_uc(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_USHORT:
           {
              Gan_RGBAPixel_us pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_d(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_d_to_us(pix.R);
                    pixa.G = gan_pixel_d_to_us(pix.G);
                    pixa.B = gan_pixel_d_to_us(pix.B);
                    pixa.A = USHRT_MAX;
                    gan_image_set_pix_rgba_us(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_INT:
           {
              Gan_RGBAPixel_i pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_d(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_d_to_i(pix.R);
                    pixa.G = gan_pixel_d_to_i(pix.G);
                    pixa.B = gan_pixel_d_to_i(pix.B);
                    pixa.A = INT_MAX;
                    gan_image_set_pix_rgba_i(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_UINT:
           {
              Gan_RGBAPixel_ui pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_d(rgb,r0s+r,c0s+c);
                    pixa.R = gan_pixel_d_to_ui(pix.R);
                    pixa.G = gan_pixel_d_to_ui(pix.G);
                    pixa.B = gan_pixel_d_to_ui(pix.B);
                    pixa.A = UINT_MAX;
                    gan_image_set_pix_rgba_ui(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_FLOAT:
           {
              Gan_RGBAPixel_f pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_d(rgb,r0s+r,c0s+c);
                    pixa.R = (float)pix.R;
                    pixa.G = (float)pix.G;
                    pixa.B = (float)pix.B;
                    pixa.A = 1.0F;
                    gan_image_set_pix_rgba_f(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

           case GAN_DOUBLE:
           {
              Gan_RGBAPixel_d pixa;
   
              for ( r=0; r < height; r++ )
                 for ( c=0; c < width; c++ )
                 {
                    pix = gan_image_get_pix_rgb_d(rgb,r0s+r,c0s+c);
                    pixa.R = pix.R;
                    pixa.G = pix.G;
                    pixa.B = pix.B;
                    pixa.A = 1.0;
                    gan_image_set_pix_rgba_d(rgba,r0d+r,c0d+c,&pixa);
                 }
           }
           break;

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

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

   /* success */
   return rgba;
}

/**
 * \brief Extracts part of an image.
 * \param source The input image
 * \param r0 Vertical offset of start of region
 * \param c0 Horizontal offset of start of region
 * \param height Height of region in pixels
 * \param width Width of region in pixels
 * \param format The format of the output image
 * \param type The type of the output image
 * \param copy_pixels Whether to copy the pixels from the source image
 * \param dest Destination image
 * \return Pointer to the extracted/converted image, or \c NULL on failure.
 *
 * Extracts a sub-part of an image, converting the image to a different format
 * and type if desired. If the \a copy_pixels flag is set to #GAN_TRUE,
 * the pixel data is copied into the destination image; otherwise the
 * destination image is set to point into the source image.
 *
 * \sa gan_image_extract_s().
 */
Gan_Image *
07368  gan_image_extract_q ( Gan_Image *source,
                       int      r0,     int      c0,
                       unsigned height, unsigned width,
                       Gan_ImageFormat format, Gan_Type type,
                       Gan_Bool copy_pixels, Gan_Image *dest )
{
   unsigned long stride;
   unsigned r0d=0, c0d=0, offset;
   Gan_Bool alloc_dest = (Gan_Bool) (dest == NULL), fill_dest = GAN_FALSE;

   if ( copy_pixels && !alloc_dest && !dest->pix_data_alloc )
   {
      /* we're copying pixels into a sub-image which already points into
         another image, so we can't change any property of the sub-image */
      gan_err_test_ptr ( format == dest->format && type == dest->type &&
                         width == dest->width && height == dest->height,
                         "gan_image_extract_q", GAN_ERROR_INCOMPATIBLE,
                         "format/type/dimensions can't change" );
   }
   else
   {
      /* set stride of output image */
      if ( copy_pixels )
         /* we're copying the data, so set the stride to match the output
            width */
         stride = gan_image_min_stride ( format, type, width, 0 );
      else
      {
         /* the destination image will point into the input image, so the
            format and type cannot change */
         gan_err_test_ptr ( format == source->format && type == source->type,
                            "gan_image_extract_q", GAN_ERROR_INCOMPATIBLE,
                            "format/type can't change" );

         /* the stride should be set to that of the input image */
         stride = source->stride;
      }

      /* allocate/set output image */
      if ( alloc_dest )
         dest = gan_image_form_gen ( NULL, format, type, height, width, stride,
                                     copy_pixels, NULL, 0, NULL, 0 );
      else
         dest = gan_image_set_format_type_dims_gen ( dest, format, type,
                                                     height, width, stride,
                                                     copy_pixels );

      if ( dest == NULL )
      {
         gan_err_register ( "gan_image_extract_q", GAN_ERROR_FAILURE, "" );
         return NULL;
      }
   }
   
   /* set offsets in destination image*/
   dest->offset_x = source->offset_x + c0;
   dest->offset_y = source->offset_y + r0;
      
   /* compute actual region to copy, compressing it to be inside the source
      image, and computing the offsets in the destination image */
   if ( c0 < 0 )
   {
      offset = (unsigned)(-c0);

      if ( width < offset )
      {
         /* no pixels to extract: fill with zeros if destination image was
            created and return immediately */
         if ( alloc_dest )
            gan_image_fill_zero(dest);

         return dest;
      }

      width -= offset;
      c0d = offset;
      c0 = 0;
      fill_dest = GAN_TRUE;
   }

   offset = (unsigned)c0;
   if ( offset + width > source->width )
   {
      if ( offset >= source->width )
      {
         /* no pixels to extract: fill with zeros if destination image was
            created and return immediately */
         if ( alloc_dest )
            gan_image_fill_zero(dest);

         return dest;
      }

      width = source->width - offset;
      fill_dest = GAN_TRUE;
   }

   if ( r0 < 0 )
   {
      offset = (unsigned)(-r0);

      if ( height < offset )
      {
         /* no pixels to extract: fill with zeros if destination image was
            created and return immediately */
         if ( alloc_dest )
            gan_image_fill_zero(dest);

         return dest;
      }

      height -= offset;
      r0d = offset;
      r0 = 0;
      fill_dest = GAN_TRUE;
   }

   offset = (unsigned)r0;
   if ( offset + height > source->height )
   {
      if ( offset >= source->height )
      {
         /* no pixels to extract: fill with zeros if destination image was
            created and return immediately */
         if ( alloc_dest )
            gan_image_fill_zero(dest);

         return dest;
      }

      height = source->height - offset;
      fill_dest = GAN_TRUE;
   }

   if ( width == 0 || height == 0 )
   {
      /* no pixels to extract: fill with zeros if destination image was
         created and return immediately */
      if ( alloc_dest )
         gan_image_fill_zero(dest);

      return dest;
   }

   /* fill destination image with zeros if it has a border of non-filled
      pixels */
   if ( fill_dest ) gan_image_fill_zero(dest);

   switch ( format )
   {
      case GAN_GREY_LEVEL_IMAGE:
        switch(source->format)
        {
           case GAN_GREY_LEVEL_IMAGE:
             dest = extract_grey ( source, r0, c0, height, width, copy_pixels,
                                   dest, r0d, c0d );
             break;
         
           case GAN_GREY_LEVEL_ALPHA_IMAGE:
             dest = extract_gla_to_grey ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;
         
           case GAN_RGB_COLOUR_IMAGE:
             dest = extract_rgb_to_grey ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;

           case GAN_RGB_COLOUR_ALPHA_IMAGE:
             dest = extract_rgba_to_grey ( source, r0, c0, height, width,
                                           dest, r0d, c0d );
             break;
         
           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_image_extract_q",
                                GAN_ERROR_NOT_IMPLEMENTED, "image conversion");
             return NULL;
        }
        break;
      
      case GAN_GREY_LEVEL_ALPHA_IMAGE:
        switch(source->format)
        {
           case GAN_GREY_LEVEL_IMAGE:
             dest = extract_grey_to_gla ( source, r0, c0, height, width,
                                                 dest, r0d, c0d );
             break;
            
           case GAN_GREY_LEVEL_ALPHA_IMAGE:
             dest = extract_gla ( source, r0, c0, height, width,
                                  copy_pixels, dest, r0d, c0d );
             break;
            
           case GAN_RGB_COLOUR_IMAGE:
             dest = extract_rgb_to_gla ( source, r0, c0, height, width,
                                         dest, r0d, c0d );
             break;

           case GAN_RGB_COLOUR_ALPHA_IMAGE:
             dest = extract_rgba_to_gla ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;

           default:
             gan_err_flush_trace();
             gan_err_register ( "gan_image_extract_q",
                                GAN_ERROR_NOT_IMPLEMENTED, "image conversion");
             return NULL;
        }
        break;
         
      case GAN_RGB_COLOUR_IMAGE:
        switch(source->format)
        {
           case GAN_GREY_LEVEL_IMAGE:
             dest = extract_grey_to_rgb ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;

           case GAN_GREY_LEVEL_ALPHA_IMAGE:
             dest = extract_gla_to_rgb ( source, r0, c0, height, width,
                                         dest, r0d, c0d );
             break;

           case GAN_RGB_COLOUR_IMAGE:
             dest = extract_rgb ( source, r0, c0, height, width,
                                  copy_pixels, dest, r0d, c0d );
             break;
               
           case GAN_RGB_COLOUR_ALPHA_IMAGE:
             dest = extract_rgba_to_rgb ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;
               
           default:
             gan_err_flush_trace();
             gan_err_register (  "gan_image_extract_q",
                                 GAN_ERROR_NOT_IMPLEMENTED,
                                 "image conversion" );
             return NULL;
        }
        break;
            
      case GAN_RGB_COLOUR_ALPHA_IMAGE:
        switch(source->format)
        {
           case GAN_GREY_LEVEL_IMAGE:
             dest = extract_grey_to_rgba ( source, r0, c0, height, width,
                                           dest, r0d, c0d );
             break;
               
           case GAN_GREY_LEVEL_ALPHA_IMAGE:
             dest = extract_gla_to_rgba ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;
               
           case GAN_RGB_COLOUR_IMAGE:
             dest = extract_rgb_to_rgba ( source, r0, c0, height, width,
                                          dest, r0d, c0d );
             break;
               
           case GAN_RGB_COLOUR_ALPHA_IMAGE:
             dest = extract_rgba ( source, r0, c0, height, width,
                                   copy_pixels, dest, r0d, c0d );
             break;
               
           default:
             gan_err_flush_trace();
             gan_err_register (  "gan_image_extract_q",
                                 GAN_ERROR_NOT_IMPLEMENTED,
                                 "image conversion" );
             return NULL;
        }
        break;
            
      default:
        gan_err_flush_trace();
        gan_err_register (  "gan_image_extract_q",
                            GAN_ERROR_NOT_IMPLEMENTED, "image conversion" );
        return NULL;
   }
   
   if ( dest == NULL )
      gan_err_register ( "gan_image_extract_q", GAN_ERROR_FAILURE, "" );
   
   /* success */
   return dest;
}

/**
 * \}
 */

/**
 * \}
 */

Generated by  Doxygen 1.6.0   Back to index