pixops_medialib_scale     (guchar          *dest_buf,
                           int              dest_width,
                           int              dest_height,
                           int              dest_rowstride,
                           int              dest_channels,
                           int              dest_has_alpha,
                           const guchar    *src_buf,
                           int              src_width,
                           int              src_height,
                           int              src_rowstride,
                           int              src_channels,
                           int              src_has_alpha,
                           int              dest_x,
                           int              dest_y,
                           int              dest_region_width,
                           int              dest_region_height,
                           double           offset_x,
                           double           offset_y,
                           double           scale_x,
                           double           scale_y,
                           PixopsInterpType interp_type)
{
  if (scale_x == 0 || scale_y == 0)
    return;

  if (!medialib_initialized)
    _pixops_use_medialib ();
 
  /*
   * We no longer support mediaLib 2.1 because it has a core dumping problem
   * in the mlib_ImageZoomTranslateTable function that has been corrected in
   * 2.2.  Although the mediaLib_zoom function could be used, it does not
   * work properly if the source and destination images have different 
   * values for "has_alpha" or "num_channels".  The complicated if-logic
   * required to support both versions is not worth supporting
   * mediaLib 2.1 moving forward.
   */
  if (!use_medialib)
    {
      _pixops_scale_real (dest_buf + (gsize)dest_y * dest_rowstride + (gsize)dest_x *
			  dest_channels, dest_x - offset_x, dest_y - offset_y,
			  dest_x + dest_region_width - offset_x,
			  dest_y + dest_region_height - offset_y,
			  dest_rowstride, dest_channels, dest_has_alpha,
			  src_buf, src_width, src_height, src_rowstride,
			  src_channels, src_has_alpha, scale_x, scale_y,
			  interp_type);
    }
  else 
    {
      mlInterp ml_interp;
      mlib_image img_orig_src, img_src, img_dest;
      double ml_offset_x, ml_offset_y;
      guchar *tmp_buf = NULL;

      mlib_ImageSetStruct (&img_orig_src, MLIB_BYTE, src_channels, src_width, 
			   src_height, src_rowstride, src_buf);

      if (dest_x == 0 && dest_y == 0 &&
          dest_width == dest_region_width &&
          dest_height == dest_region_height)
        {
          mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
			       dest_width, dest_height, dest_rowstride,
			       dest_buf);
        }
      else
        {
	  mlib_u8 *data = dest_buf + (gsize)dest_y * dest_rowstride +
				     (gsize)dest_x * dest_channels;

          mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
			       dest_region_width, dest_region_height,
			       dest_rowstride, data);
        }

      ml_offset_x = floor (offset_x) - dest_x;
      ml_offset_y = floor (offset_y) - dest_y;

     /*
      * Note that zoomTranslate and zoomTranslateTable are faster
      * than zoomTranslateBlend and zoomTranslateTableBlend.  However
      * the faster functions only work in the following case:
      *
      *   if (src_channels == dest_channels &&
      *       (!src_alpha && interp_table != PIXOPS_INTERP_NEAREST))
      *
      * We use the faster versions if we can.
      *
      * Note when the interp_type is BILINEAR and the interpolation
      * table will be size 2x2 (when both x/y scale factors > 1.0),
      * then we do not bother building the interpolation table.   In
      * this case we can just use MLIB_BILINEAR, which is faster than
      * using a specified interpolation table.
      */
      img_src = img_orig_src;

      if (!src_has_alpha)
        {
          if (src_channels > dest_channels)
            {
              int channels  = 3;
              int rowstride = (channels * src_width + 3) & ~3;
        
              tmp_buf = g_malloc_n (src_rowstride, src_height);

              if (src_buf != NULL)
                {
                  src_channels  = channels;
                  src_rowstride = rowstride;
          
                  mlib_ImageSetStruct (&img_src, MLIB_BYTE, src_channels,
				       src_width, src_height, src_rowstride,
				       tmp_buf);
                  mlib_ImageChannelExtract (&img_src, &img_orig_src, 0xE);  
                }
            }
        }
    
      if (interp_type == PIXOPS_INTERP_NEAREST)
        {
          if (src_channels == dest_channels)
            {
              mlib_ImageZoomTranslate (&img_dest,
                                       &img_src,
                                       scale_x,
                                       scale_y,
                                       ml_offset_x,
                                       ml_offset_y,
                                       MLIB_NEAREST,
                                       MLIB_EDGE_SRC_EXTEND_INDEF);
            }
          else
            {
              mlib_ImageZoomTranslateBlend (&img_dest,
                                            &img_src,
                                            scale_x,
                                            scale_y,
                                            ml_offset_x,
                                            ml_offset_y,
                                            MLIB_NEAREST,
                                            MLIB_EDGE_SRC_EXTEND_INDEF,
                                            MLIB_BLEND_GTK_SRC,
                                            1.0,
                                            1);
            }
        }
      else if (src_channels == dest_channels && !src_has_alpha)
        {
          if (interp_type == PIXOPS_INTERP_BILINEAR &&
              scale_x > 1.0 && scale_y > 1.0)
            {
               mlib_ImageZoomTranslate (&img_dest,
                                        &img_src,
                                        scale_x,
                                        scale_y,
                                        ml_offset_x,
                                        ml_offset_y,
                                        MLIB_BILINEAR,
                                        MLIB_EDGE_SRC_EXTEND_INDEF);
            }
          else
            {
              medialib_get_interpolation (&ml_interp, interp_type,
                                          scale_x, scale_y, 1.0);

              if (ml_interp.interp_table != NULL)
                {
                  mlib_ImageZoomTranslateTable (&img_dest, 
                                                &img_src,
                                                scale_x,
                                                scale_y,
                                                ml_offset_x + ml_interp.tx,
                                                ml_offset_y + ml_interp.ty,
                                                ml_interp.interp_table,
                                                MLIB_EDGE_SRC_EXTEND_INDEF);

	          mlib_ImageInterpTableDelete (ml_interp.interp_table);
                }
              else
                {
                  /* Should not happen. */
                  mlib_filter  ml_filter;

                  switch (interp_type)
                    {
                    case PIXOPS_INTERP_BILINEAR:
                      ml_filter = MLIB_BILINEAR;
                      break;

                    case PIXOPS_INTERP_TILES:
                      ml_filter = MLIB_BILINEAR;
                      break;

                    case PIXOPS_INTERP_HYPER:
                      ml_filter = MLIB_BICUBIC;
                      break;
                    }

                  mlib_ImageZoomTranslate (&img_dest,
                                           &img_src,
                                           scale_x,
                                           scale_y,
                                           ml_offset_x,
                                           ml_offset_y,
                                           ml_filter,
                                           MLIB_EDGE_SRC_EXTEND_INDEF);
                }
            }
        }

      /* Deal with case where src_channels != dest_channels || src_has_alpha */
      else if (interp_type == PIXOPS_INTERP_BILINEAR &&
               scale_x > 1.0 && scale_y > 1.0)
        {
          mlib_ImageZoomTranslateBlend (&img_dest,
                                        &img_src,
                                        scale_x,
                                        scale_y,
                                        ml_offset_x,
                                        ml_offset_y,
                                        MLIB_BILINEAR,
                                        MLIB_EDGE_SRC_EXTEND_INDEF,
                                        MLIB_BLEND_GTK_SRC,
                                        1.0,
                                        1);
        }
      else
        {
          medialib_get_interpolation (&ml_interp, interp_type,
                                      scale_x, scale_y, 1.0);

          if (ml_interp.interp_table != NULL)
            {
              mlib_ImageZoomTranslateTableBlend (&img_dest,
                                                 &img_src,
                                                 scale_x,
                                                 scale_y,
                                                 ml_offset_x + ml_interp.tx,
                                                 ml_offset_y + ml_interp.ty,
                                                 ml_interp.interp_table,
                                                 MLIB_EDGE_SRC_EXTEND_INDEF,
                                                 MLIB_BLEND_GTK_SRC,
                                                 1);
              mlib_ImageInterpTableDelete (ml_interp.interp_table);
            }
          else
            {
              mlib_filter  ml_filter;

              switch (interp_type)
                {
                case PIXOPS_INTERP_BILINEAR:
                  ml_filter = MLIB_BILINEAR;
                  break;
            
                case PIXOPS_INTERP_TILES:
                  ml_filter = MLIB_BILINEAR;
                  break;

                case PIXOPS_INTERP_HYPER:
                  ml_filter = MLIB_BICUBIC;
                  break;
                }

              mlib_ImageZoomTranslate (&img_dest,
                                       &img_src,
                                       scale_x,
                                       scale_y,
                                       ml_offset_x,
                                       ml_offset_y,
                                       ml_filter,
                                       MLIB_EDGE_SRC_EXTEND_INDEF);
            }
        }

      if (tmp_buf != NULL)
        g_free (tmp_buf);
    }
}