/*
% Copyright (C) 2003-2025 GraphicsMagick Group
% Copyright (C) 2002 ImageMagick Studio
%
% This program is covered by multiple licenses, which are described in
% Copyright.txt. You should have received a copy of Copyright.txt with this
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%                             M   M  SSSSS  L                                 %
%                             MM MM  SS     L                                 %
%                             M M M   SSS   L                                 %
%                             M   M     SS  L                                 %
%                             M   M  SSSSS  LLLLL                             %
%                                                                             %
%                                                                             %
%                    Execute Magick Scripting Language Scripts.               %
%                                                                             %
%                                                                             %
%                              Software Design                                %
%                                John Cristy                                  %
%                             Leonard Rosenthol                               %
%                             William Radcliffe                               %
%                               December 2001                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/

/*
  Include declarations.
*/
#include "magick/studio.h"
#if defined(HasXML)
#include "magick/attribute.h"
#include "magick/blob.h"
#include "magick/color.h"
#include "magick/color_lookup.h"
#include "magick/pixel_cache.h"
#include "magick/composite.h"
#include "magick/constitute.h"
#include "magick/decorate.h"
#include "magick/effect.h"
#include "magick/enhance.h"
#include "magick/enum_strings.h"
#include "magick/fx.h"
#include "magick/log.h"
#include "magick/magick.h"
#include "magick/paint.h"
#include "magick/profile.h"
#include "magick/render.h"
#include "magick/resize.h"
#include "magick/shear.h"
#include "magick/texture.h"
#include "magick/transform.h"
#include "magick/utility.h"
#if defined(MSWINDOWS)
#  if defined(__MINGW32__)
#    if !defined(_MSC_VER)
#      define _MSC_VER 1200
#    endif
#  else
#    include <win32config.h>
#  endif
#endif
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
#include <libxml/parserInternals.h>
#include <libxml/xmlerror.h>

/*
  Avoid shadowing library globals and functions.
*/
#define attribute attribute_magick

/*
  Typedef declaractions.
*/
typedef struct _MSLGroupInfo
{
  unsigned long
    numImages;  /* how many images are in this group */
} MSLGroupInfo;

typedef struct _MSLInfo
{
  ExceptionInfo
    *exception;

  long
    n,
    nGroups;

  ImageInfo
    **image_info;

  DrawInfo
   **draw_info;

  Image
    **attributes,
    **image;

  MSLGroupInfo
    *group_info;

  unsigned long
    signature;
} MSLInfo;

/*
  Forward declarations.
*/
static unsigned int
  WriteMSLImage(const ImageInfo *,Image *);

static void
MSLError(void *context,const char *format,...) MAGICK_FUNC_PRINTF_FORMAT(2,3);

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d M S L I m a g e                                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method ReadMSLImage reads a Magick Scripting Language file and returns it.
%  It allocates the memory necessary for the new Image structure and returns a
%  pointer to the new image.
%
%  The format of the ReadMSLImage method is:
%
%      Image *ReadMSLImage(const ImageInfo *image_info,
%                          ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image:  Method ReadMSLImage returns a pointer to the image after
%      reading. A null image is returned if there is a memory shortage or if
%      the image cannot be read.
%
%    o image_info: Specifies a pointer to a ImageInfo structure.
%
%    o exception: return any errors or warnings in this structure.
%
%
*/

#if defined(__cplusplus) || defined(c_plusplus)
/* extern "C" { */
#endif

static void
MSLPushImage(MSLInfo *msl_info,Image *image)
{
  const ImageAttribute
    *attribute;

  long
    n;

  assert(msl_info != (MSLInfo *) NULL);
  msl_info->n++;
  n=msl_info->n;
  MagickReallocMemory(ImageInfo **,msl_info->image_info,
                      ((size_t)n+1)*sizeof(ImageInfo *));
  MagickReallocMemory(DrawInfo **,msl_info->draw_info,
                      ((size_t)n+1)*sizeof(DrawInfo *));
  MagickReallocMemory(Image **,msl_info->attributes,((size_t)n+1)*sizeof(Image *));
  MagickReallocMemory(Image **,msl_info->image,((size_t)n+1)*sizeof(Image *));
  if ((msl_info->image_info == (ImageInfo **) NULL) ||
      (msl_info->draw_info == (DrawInfo **) NULL) ||
      (msl_info->attributes == (Image **) NULL) ||
      (msl_info->image == (Image **) NULL))
    MagickFatalError3(ResourceLimitFatalError,
                      MemoryAllocationFailed,UnableToAllocateImage);
  msl_info->image_info[n]=CloneImageInfo(msl_info->image_info[n-1]);
  msl_info->draw_info[n]=
    CloneDrawInfo(msl_info->image_info[n-1], msl_info->draw_info[n-1]);
  msl_info->attributes[n]=AllocateImage(msl_info->image_info[n]);
  msl_info->image[n]=(Image *) image;
  if ((msl_info->image_info[n] == (ImageInfo *) NULL) ||
      (msl_info->attributes[n] == (Image *) NULL))
    ThrowException3(msl_info->exception,ResourceLimitFatalError,
                    MemoryAllocationFailed,UnableToAllocateImage);
  if ( msl_info->nGroups )
    msl_info->group_info[msl_info->nGroups-1].numImages++;
  if (msl_info->attributes[n-1] != (Image *) NULL)
    {
      attribute=GetImageAttribute(msl_info->attributes[n-1],(char *) NULL);
      while (attribute != (const ImageAttribute *) NULL)
        {
          (void) SetImageAttribute(msl_info->attributes[n],attribute->key,NULL);
          (void) SetImageAttribute(msl_info->attributes[n],attribute->key,
                                   attribute->value);
          attribute=attribute->next;
        }
    }
}

static void
MSLPopImage(MSLInfo *msl_info)
{
  /*
    only dispose of images when they aren't in a group
  */
  if ( (msl_info->nGroups == 0) && (msl_info->n > 0) )
    {
      DestroyImage(msl_info->image[msl_info->n]);
      msl_info->image[msl_info->n]=(Image *) NULL;

      DestroyDrawInfo(msl_info->draw_info[msl_info->n]);
      msl_info->draw_info[msl_info->n]=(DrawInfo *) NULL;

      DestroyImage(msl_info->attributes[msl_info->n]);
      msl_info->attributes[msl_info->n]=(Image *) NULL;

      DestroyImageInfo(msl_info->image_info[msl_info->n]);
      msl_info->image_info[msl_info->n]=(ImageInfo *) NULL;
      msl_info->n--;
    }
  if (msl_info->nGroups != 0)
    {
      (void) LogMagickEvent
        (CoderEvent,GetMagickModule(),
         "  Skipping destroy due to nGroups = %lu", msl_info->nGroups);
    }
}

#define MSL_BREAK_IF_IMAGE_NULL(_image)                        \
  if (_image == (Image *) NULL)                                \
    {                                                          \
      ThrowException(msl_info->exception,OptionError,          \
                     NoImagesDefined,(char *) name);           \
      break;                                                   \
    }

#define MSL_BREAK_IF_IMAGE_ZERO_SIZE(_image)                            \
  if ((_image->rows) == 0 ||                                            \
      (_image->columns == 0))                                           \
    {                                                                   \
      ThrowException(msl_info->exception,OptionError,                   \
                     NonzeroWidthAndHeightRequired,(char *) name);      \
      break;                                                            \
    }

#define MSL_BREAK_IF_IMAGE_PIXEL_CACHE_NOT_PRESENT(_image)  \
  if (!GetPixelCachePresent(_image))                                    \
    {                                                                   \
      ThrowException(msl_info->exception,OptionError,                   \
                     NoImagesDefined,(char *) name);                    \
      break;                                                            \
    }

#define MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(_image)   \
  MSL_BREAK_IF_IMAGE_NULL(_image);                    \
  MSL_BREAK_IF_IMAGE_ZERO_SIZE(_image);               \
  MSL_BREAK_IF_IMAGE_PIXEL_CACHE_NOT_PRESENT(_image)

static void
MSLStartElement(void *context,const xmlChar *name,
                const xmlChar **attributes)
{
  char
    key[MaxTextExtent],
    *value = NULL;

  const char
    *keyword;

  ExceptionInfo
    exception;

  long
    n,
    x,
    y;

  MSLInfo
    *msl_info;

  register long
    i, j;

  unsigned long
    height,
    width;

  xmlParserCtxtPtr
    parser;

  /*
    Called when an opening tag has been processed.
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                        "  SAX.startElement(%.1024s",name);
  parser=(xmlParserCtxtPtr) context;
  msl_info=(MSLInfo *) parser->_private;
  assert(msl_info->signature == MagickSignature);
  /*
    If we already have an exception at error level, then just return.
    Eventually the XML reader will stop.
  */
  if (msl_info->exception->severity >= ErrorException)
    {
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  )");
      return;
    }
  GetExceptionInfo(&exception);
  n=msl_info->n;
  keyword=(const char *) NULL;
  switch (*name)
    {
    case 'B':
    case 'b':
      {
        if (LocaleCompare((char *) name, "blur") == 0)
          {
            double  radius = 0.0,
              sigma = 1.0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'R':
                      case 'r':
                        {
                          if (LocaleCompare(keyword, "radius") == 0)
                            {
                              radius = MagickAtoF( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'S':
                      case 's':
                        {
                          if (LocaleCompare(keyword,"sigma") == 0)
                            {
                              sigma = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              blur image.
            */
            {
              Image
                *newImage;

              newImage=BlurImage(msl_info->image[n],radius,sigma,
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"border") == 0)
          {
            /* init the values */
            width = height = 6;  /* this is the value that Magick++ uses */
            x = y = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'F':
                      case'f':
                        {
                          if (LocaleCompare(keyword, "fill") == 0)
                            {
                              (void) QueryColorDatabase
                                (value,
                                 &msl_info->image[n]->border_color,
                                 msl_info->exception);
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'G':
                      case 'g':
                        {
                          if (LocaleCompare(keyword,"geometry") == 0)
                            {
                              (void) GetMagickGeometry(value,&x,&y,
                                                       &width,&height);
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'H':
                      case 'h':
                        {
                          if (LocaleCompare(keyword,"height") == 0)
                            {
                              height = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'W':
                      case 'w':
                        {
                          if (LocaleCompare(keyword,"width") == 0)
                            {
                              width = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              border image.
            */
            {
              Image
                *border_image;
              RectangleInfo
                rectInfo;

              rectInfo.height = height;
              rectInfo.width = width;
              rectInfo.x = x;
              rectInfo.y = y;

              border_image=BorderImage(msl_info->image[n],&rectInfo,
                                       msl_info->exception);
              if (border_image == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=border_image;
            }

            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'C':
    case 'c':
      {
        if (LocaleCompare((char *) name, "charcoal") == 0)
          {
            double  radius = 0.0,
              sigma = 1.0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'R':
                      case 'r':
                        {
                          if (LocaleCompare(keyword, "radius") == 0)
                            {
                              radius = MagickAtoF( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'S':
                      case 's':
                        {
                          if (LocaleCompare(keyword,"sigma") == 0)
                            {
                              sigma = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              charcoal image.
            */
            {
              Image
                *newImage;

              newImage=CharcoalImage(msl_info->image[n],radius,sigma,
                                     msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"chop") == 0)
          {
            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x = y = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          height = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          width = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'X':
                  case 'x':
                    {
                      if (LocaleCompare(keyword,"x") == 0)
                        {
                          x = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'Y':
                  case 'y':
                    {
                      if (LocaleCompare(keyword,"y") == 0)
                        {
                          y = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;
              RectangleInfo
                rectInfo;

              rectInfo.height = height;
              rectInfo.width = width;
              rectInfo.x = x;
              rectInfo.y = y;

              newImage=ChopImage(msl_info->image[n],&rectInfo,
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        else if (LocaleCompare((char *) name, "composite") == 0 )
          {
            Image *
              srcImage = (Image*)NULL;
            CompositeOperator
              compositeOp = OverCompositeOp;
            GravityType
              gravity = CenterGravity;

            x = y = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'C':
                  case 'c':
                    {
                      if (LocaleCompare(keyword, "compose") == 0)
                        {
                          compositeOp = StringToCompositeOperator(value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          gravity=ForgetGravity;
                          break;
                        }
                      else if (LocaleCompare(keyword,"gravity") == 0)
                        {
                          gravity = StringToGravityType(value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'I':
                  case 'i':
                    {
                      if (LocaleCompare(keyword,"image") == 0)
                        {
                          for (j=0; j<msl_info->n;j++)
                            {
                              const ImageAttribute *
                                theAttr =
                                GetImageAttribute(msl_info->attributes[j],
                                                  "id");
                              if (theAttr &&
                                  LocaleCompare(theAttr->value, value) == 0)
                                {
                                  srcImage = msl_info->image[j];
                                  break;
                                }
                            }
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'X':
                  case 'x':
                    {
                      if (LocaleCompare(keyword,"x") == 0)
                        {
                          x = MagickAtoI( value );
                          gravity=ForgetGravity;
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'Y':
                  case 'y':
                    {
                      if (LocaleCompare(keyword,"y") == 0)
                        {
                          y = MagickAtoI( value );
                          gravity=ForgetGravity;
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            if (srcImage != (Image*)NULL)
              {
                switch (gravity)
                  {
                  case ForgetGravity:
                    {
                      /* do nothing, since we already have explicit x,y */
                      break;
                    }
                  case NorthWestGravity:
                    {
                      x = 0;
                      y = 0;
                      break;
                    }
                  case NorthGravity:
                    {
                      x =(long) ((msl_info->image[n]->columns-
                                  srcImage->columns) >> 1);
                      y = 0;
                      break;
                    }
                  case NorthEastGravity:
                    {
                      x = (long) (msl_info->image[n]->columns -
                                  srcImage->columns);
                      y = 0;
                      break;
                    }
                  case WestGravity:
                    {
                      x = 0;
                      y = (long) ((msl_info->image[n]->rows -
                                   srcImage->rows) >> 1);
                      break;
                    }
                  case CenterGravity:
                  default:
                    {
                      x =(long) ((msl_info->image[n]->columns-
                                  srcImage->columns) >> 1);
                      y = (long) ((msl_info->image[n]->rows -
                                   srcImage->rows) >> 1);
                      break;
                    }
                  case EastGravity:
                    {
                      x = (long) (msl_info->image[n]->columns -
                                  srcImage->columns);
                      y = (long) ((msl_info->image[n]->rows -
                                   srcImage->rows) >> 1);
                      break;
                    }
                  case SouthWestGravity:
                    {
                      x = 0;
                      y = (long) (msl_info->image[n]->rows -
                                  srcImage->rows);
                      break;
                    }
                  case SouthGravity:
                    {
                      x =(long) ((msl_info->image[n]->columns -
                                  srcImage->columns) >> 1);
                      y = (long) (msl_info->image[n]->rows -
                                  srcImage->rows);
                      break;
                    }
                  case SouthEastGravity:
                    {
                      x = (long) (msl_info->image[n]->columns -
                                  srcImage->columns);
                      y = (long) (msl_info->image[n]->rows -
                                  srcImage->rows);
                      break;
                    }
                  }

                (void) CompositeImage(msl_info->image[n], compositeOp,
                                      srcImage, x, y);
                break;
              } else
              ThrowException(msl_info->exception,OptionError,
                             NoImagesDefined,(char *) name);

            break;
          }
        else if (LocaleCompare((char *) name,"crop") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x = y = 0;

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          height = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          width = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'X':
                  case 'x':
                    {
                      if (LocaleCompare(keyword,"x") == 0)
                        {
                          x = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'Y':
                  case 'y':
                    {
                      if (LocaleCompare(keyword,"y") == 0)
                        {
                          y = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;
              RectangleInfo
                rectInfo;

              rectInfo.height = height;
              rectInfo.width = width;
              rectInfo.x = x;
              rectInfo.y = y;

              newImage=CropImage(msl_info->image[n],&rectInfo,
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'D':
    case 'd':
      {
        if (LocaleCompare((char *) name, "despeckle") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=DespeckleImage(msl_info->image[n],
                                      msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'E':
    case 'e':
      {
        if (LocaleCompare((char *) name, "edge") == 0)
          {
            double  radius = 0.0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'R':
                      case 'r':
                        {
                          if (LocaleCompare(keyword, "radius") == 0)
                            {
                              radius = MagickAtoF( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              edge image.
            */
            {
              Image
                *newImage;

              newImage=EdgeImage(msl_info->image[n],radius,
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "emboss") == 0)
          {
            double  radius = 0.0,
              sigma = 1.0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'R':
                      case 'r':
                        {
                          if (LocaleCompare(keyword, "radius") == 0)
                            {
                              radius = MagickAtoF( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'S':
                      case 's':
                        {
                          if (LocaleCompare(keyword,"sigma") == 0)
                            {
                              sigma = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              emboss image.
            */
            {
              Image
                *newImage;

              newImage=EmbossImage(msl_info->image[n],radius,sigma,
                                   msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "enhance") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=EnhanceImage(msl_info->image[n],
                                    msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "equalize") == 0)
          {
            if (msl_info->image[n] == (Image *) NULL)
              {
                ThrowException(msl_info->exception,OptionError,
                               NoImagesDefined,(char *) name);
                break;
              }

            /* no attributes here */

            /* process the image */
            {
              /* why doesn't this take an exception or return the
                 changed image */
              (void) EqualizeImage(msl_info->image[n]);
              break;
            }
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'F':
    case 'f':
      {
        if (LocaleCompare((char *) name, "flatten") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=FlattenImages(msl_info->image[n],
                                     msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "flip") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=FlipImage(msl_info->image[n],
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "flop") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=FlopImage(msl_info->image[n],
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"frame") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* init the values */
            width = height = 25;  /* these are the values that Magick++ uses */
            x = y = 6;

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'F':
                      case 'f':
                        {
                          if (LocaleCompare(keyword, "fill") == 0)
                            {
                              (void) QueryColorDatabase
                                (value,
                                 &msl_info->image[n]->matte_color,
                                 msl_info->exception);
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'G':
                      case 'g':
                        {
                          if (LocaleCompare(keyword,"geometry") == 0)
                            {
                              (void) GetMagickGeometry(value,&x,&y,
                                                       &width,&height);
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'H':
                      case 'h':
                        {
                          if (LocaleCompare(keyword,"height") == 0)
                            {
                              height = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'I':
                      case 'i':
                        {
                          if (LocaleCompare(keyword,"inner") == 0)
                            {
                              y = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'O':
                      case 'o':
                        {
                          if (LocaleCompare(keyword,"outer") == 0)
                            {
                              x = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'W':
                      case 'w':
                        {
                          if (LocaleCompare(keyword,"width") == 0)
                            {
                              width = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'X':
                      case 'x':
                        {
                          if (LocaleCompare(keyword,"x") == 0)
                            {
                              x = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'Y':
                      case 'y':
                        {
                          if (LocaleCompare(keyword,"y") == 0)
                            {
                              y = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              frame image.
            */
            {
              Image
                *newImage;
              FrameInfo
                frameInfo;

              frameInfo.x = (long) width;
              frameInfo.y = (long) height;
              frameInfo.width = msl_info->image[n]->columns +
                ( frameInfo.x << 1 );
              frameInfo.height = msl_info->image[n]->rows +
                ( frameInfo.y << 1 );
              frameInfo.outer_bevel = x;
              frameInfo.inner_bevel = y;

              newImage=FrameImage(msl_info->image[n],&frameInfo,
                                  msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'G':
    case 'g':
      {
        if (LocaleCompare((char *) name, "gamma") == 0)
          {
            double
              gammaRed = 0, gammaGreen = 0, gammaBlue = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                (void) CloneString(&value,(char *) attributes[i]);
                (void) strlcpy(key,value,MaxTextExtent);
                switch (*keyword)
                  {
                  case 'B':
                  case 'b':
                    {
                      if (LocaleCompare(keyword,"blue") == 0)
                        {
                          gammaBlue = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"green") == 0)
                        {
                          gammaGreen = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'R':
                  case 'r':
                    {
                      if (LocaleCompare(keyword,"red") == 0)
                        {
                          gammaRed = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
              }

            /* process image */
            {
              char gamma[MaxTextExtent + 1];
              FormatString( gamma, "%3.6f/%3.6f/%3.6f/",
                            gammaRed, gammaGreen, gammaBlue);

              (void) GammaImage ( msl_info->image[n], gamma );
            }

            break;
          }
        else if (LocaleCompare((char *) name,"get") == 0)
          {

            MSL_BREAK_IF_IMAGE_NULL(msl_info->image[n]);
            MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                (void) CloneString(&value,(char *) attributes[i]);
                (void) strlcpy(key,value,MaxTextExtent);
                switch (*keyword)
                  {
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          FormatString(value,"%ld",msl_info->image[n]->rows);
                          (void) SetImageAttribute(msl_info->attributes[n],
                                                   key,NULL);
                          (void) SetImageAttribute(msl_info->attributes[n],
                                                   key,value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          FormatString(value,"%ld",
                                       msl_info->image[n]->columns);
                          (void) SetImageAttribute(msl_info->attributes[n],
                                                   key,NULL);
                          (void) SetImageAttribute(msl_info->attributes[n],
                                                   key,value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
              }
            break;
          }
        else if (LocaleCompare((char *) name, "group") == 0)
          {
            MSLGroupInfo *new_group_info;
            msl_info->nGroups++;
            new_group_info =
              MagickReallocateResourceLimitedClearedArray(MSLGroupInfo *,
                                                          msl_info->group_info,
                                                          (size_t)msl_info->nGroups+1,
                                                          sizeof(MSLGroupInfo));
            if (new_group_info != (MSLGroupInfo *) NULL)
              {
                msl_info->group_info = new_group_info;
              }
            else
            {
              msl_info->nGroups--;
              MagickFatalError3(ResourceLimitFatalError,
                      MemoryAllocationFailed,UnableToAllocateImage);
            }
            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'I':
    case 'i':
      {
        if (LocaleCompare((char *) name,"image") == 0)
          {
            long
              n;

            MSLPushImage(msl_info,(Image *) NULL);
            n=msl_info->n;
            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'B':
                  case 'b':
                    {
                      if (LocaleCompare(keyword,"background") == 0)
                        {
                          (void) QueryColorDatabase
                            (value,
                             &msl_info->image_info[n]->background_color,
                             msl_info->exception);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }

                  case 'C':
                  case 'c':
                    {
                      if (LocaleCompare(keyword,"color") == 0)
                        {
                          Image
                            *next_image;

                          (void) strlcpy(msl_info->image_info[n]->filename,
                                         "xc:",
                                         sizeof(msl_info->image_info[n]->filename));
                          (void) strlcat(msl_info->image_info[n]->filename,
                                         value,
                                         sizeof(msl_info->image_info[n]->filename));
                          next_image=ReadImage(msl_info->image_info[n],
                                               &exception);
                          if (exception.severity != UndefinedException)
                            CatchException(&exception);
                          if (next_image == (Image *) NULL)
                            continue;
                          if (msl_info->image[n] == (Image *) NULL)
                            msl_info->image[n]=next_image;
                          else
                            {
                              register Image
                                *p;

                              /*
                                Link image into image list.
                              */
                              p=msl_info->image[n];
                              for ( ; p->next != (Image *) NULL; p=p->next);
                              next_image->previous=p;
                              p->next=next_image;
                            }
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }

                  case 'I':
                  case 'i':
                    {
                      if (LocaleCompare(keyword,"id") == 0)
                        {
                          (void) SetImageAttribute(msl_info->attributes[n],
                                                   keyword,NULL);
                          (void) SetImageAttribute(msl_info->attributes[n],
                                                   keyword,value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'S':
                  case 's':
                    {
                      if (LocaleCompare(keyword,"size") == 0)
                        {
                          (void) CloneString(&msl_info->image_info[n]->size,
                                             value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }
            break;
          }
        else if (LocaleCompare((char *) name,"implode") == 0)
          {
            /* init the values */
            double  amount = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'A':
                  case 'a':
                    {
                      if (LocaleCompare(keyword,"amount") == 0)
                        {
                          amount = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=ImplodeImage(msl_info->image[n],amount,
                                    msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'M':
    case 'm':
      {
        if (LocaleCompare((char *) name, "magnify") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=MagnifyImage(msl_info->image[n],
                                    msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"medianfilter") == 0)
          {
            /* init the values */
            unsigned int  radius = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'R':
                  case 'r':
                    {
                      if (LocaleCompare(keyword,"radius") == 0)
                        {
                          radius = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=MedianFilterImage(msl_info->image[n], radius,
                                         msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "minify") == 0)
          {

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;

              newImage=MinifyImage(msl_info->image[n],
                                   msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name, "msl") == 0 )
          {
            /*
              This is our base element.
              at the moment we don't do anything special
              but someday we might!
            */
            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'N':
    case 'n':
      {
        if (LocaleCompare((char *) name, "normalize") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              (void) NormalizeImage(msl_info->image[n]);
              break;
            }
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'O':
    case 'o':
      {
        if (LocaleCompare((char *) name, "oilpaint") == 0)
          {
            /* init the values */
            unsigned int  radius = 3;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'R':
                  case 'r':
                    {
                      if (LocaleCompare(keyword,"radius") == 0)
                        {
                          radius = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=OilPaintImage(msl_info->image[n], radius,
                                     msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'P':
    case 'p':
      {
        if (LocaleCompare((char *) name,"print") == 0)
          {
            /* print does not require an image to be present! */

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'O':
                  case 'o':
                    {
                      if (LocaleCompare(keyword,"output") == 0)
                        {
                          (void) LogMagickEvent(CoderEvent,
                                                GetMagickModule(),"%s",value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }
            break;
          }
        else if (LocaleCompare((char *) name, "profile") == 0)
          {
            ImageInfo
              *clone_info;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            clone_info=CloneImageInfo(msl_info->image_info[n]);
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  {
                    DestroyImageInfo(clone_info);
                    MagickFatalError3(ResourceLimitFatalError,
                                      MemoryAllocationFailed,
                                      UnableToAllocateString);
                  }

                if (LocaleCompare(value,"!") == 0)
                  {
                    /*
                      Remove profile named <keyword> from the image.
                    */
                    (void) ProfileImage(msl_info->image[n],keyword,
                      (unsigned char *) NULL,0,True);
                  }
                else
                  {
                    /*
                      Add profile named <keyword> held in file <value> to the image.
                    */
                    Image
                      *profile_image;

                    ProfileInfo
                      profile_info;

                    const char
                      *profile_name;

                    size_t
                      profile_length;

                    const unsigned char *
                      profile_data;

                    ImageProfileIterator
                      profile_iterator;

                    void
                      *client_data;

                    client_data=clone_info->client_data;

                    /*
                      FIXME: Next three lines replace:
                       clone_info->client_data=(void *) &(msl_info->image[n]->iptc_profile);
                    */
                    profile_info.name="IPTC";
                    profile_info.info=(unsigned char *) GetImageProfile(msl_info->image[n],profile_info.name,
                                                                      &profile_info.length);
                    clone_info->client_data=&profile_info;

                    (void) strlcpy(clone_info->filename,value,MaxTextExtent);
                    profile_image=ReadImage(clone_info,&(msl_info->image[n]->exception));
                    if (profile_image == (Image *) NULL)
                      {
                        (void) LogMagickEvent(TransformEvent,GetMagickModule(),
                                             "Failed to load profile from file \"%s\"",
                                             clone_info->filename);
                      }
                    else
                      {
                        /*
                          Transfer profile(s) to image.
                        */
                        profile_iterator=AllocateImageProfileIterator(profile_image);
                        while(NextImageProfile(profile_iterator,&profile_name,&profile_data,
                                               &profile_length) != MagickFail)
                          {
                            (void) LogMagickEvent(TransformEvent,GetMagickModule(),
                                                 "Adding %s profile to image",profile_name);
                            if ((LocaleCompare(profile_name,"ICC") == 0) ||
                                (LocaleCompare(profile_name,"ICM") == 0))
                              (void) ProfileImage(msl_info->image[n],profile_name,(unsigned char *) profile_data,
                                                    profile_length,True);
                            else
                              (void) SetImageProfile(msl_info->image[n],profile_name,profile_data,profile_length);
                          }
                        DeallocateImageProfileIterator(profile_iterator);
                        DestroyImage(profile_image);
                        profile_image=(Image *) NULL;
                        clone_info->client_data=client_data;
                      }
                MagickFreeMemory(value);
              }
            }
            DestroyImageInfo(clone_info);
            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'R':
    case 'r':
      {
        if (LocaleCompare((char *) name,"read") == 0)
          {
            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'F':
                  case 'f':
                    {
                      if (LocaleCompare(keyword,"filename") == 0)
                        {
                          Image
                            *next_image;

                          (void) strlcpy(msl_info->image_info[n]->filename,
                                         value,
                                         sizeof(msl_info->image_info[n]->filename));
                          next_image=ReadImage(msl_info->image_info[n],
                                               &exception);
                          if (exception.severity != UndefinedException)
                            CatchException(&exception);
                          if (next_image == (Image *) NULL)
                            continue;
                          if (msl_info->image[n] == (Image *) NULL)
                            msl_info->image[n]=next_image;
                          else
                            {
                              register Image
                                *p;

                              /*
                                Link image into image list.
                              */
                              p=msl_info->image[n];
                              for ( ; p->next != (Image *) NULL; p=p->next);
                              next_image->previous=p;
                              p->next=next_image;
                            }
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'S':
                  case 's':
                    {
                      if (LocaleCompare(keyword,"size") == 0)
                        {
                          msl_info->image_info[n]->size=AllocateString(value);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }
            break;
          }
        else if (LocaleCompare((char *) name, "reducenoise") == 0 )
          {
            /* init the values */
            unsigned int  radius = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'R':
                  case 'r':
                    {
                      if (LocaleCompare(keyword,"radius") == 0)
                        {
                          radius = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=ReduceNoiseImage(msl_info->image[n], radius,
                                        msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"resize") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x=0;
            y=0;

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'B':
                  case 'b':
                    {
                      if (LocaleCompare(keyword,"blur") == 0)
                        {
                          msl_info->image[n]->blur = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'F':
                  case 'f':
                    {
                      if (LocaleCompare(keyword, "filter") == 0)
                        {
                          FilterTypes
                            newFilter;

                          newFilter=StringToFilterTypes(value);
                          msl_info->image[n]->filter = newFilter;
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          height = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          width = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              Resize image.
            */
            {
              Image
                *resize_image;

              if ((width == msl_info->image[n]->columns) &&
                  (height == msl_info->image[n]->rows))
                break;
              resize_image=ZoomImage(msl_info->image[n],width,height,
                                     msl_info->exception);
              if (resize_image == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=resize_image;
            }

            break;
          }
        else if (LocaleCompare((char *) name,"roll") == 0)
          {
            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x = y = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'X':
                  case 'x':
                    {
                      if (LocaleCompare(keyword,"x") == 0)
                        {
                          x = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'Y':
                  case 'y':
                    {
                      if (LocaleCompare(keyword,"y") == 0)
                        {
                          y = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=RollImage(msl_info->image[n], x, y,
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        else if (LocaleCompare((char *) name,"rotate") == 0)
          {
            /* init the values */
            double  degrees = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'D':
                  case 'd':
                    {
                      if (LocaleCompare(keyword,"degrees") == 0)
                        {
                          degrees = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=RotateImage(msl_info->image[n], degrees,
                                   msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'S':
    case 's':
      {
        if (LocaleCompare((char *) name,"sample") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x = y = 0;

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          height = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          width = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=SampleImage(msl_info->image[n], width, height,
                                   msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        else if (LocaleCompare((char *) name,"scale") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x = y = 0;

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          height = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          width = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=ScaleImage(msl_info->image[n], width, height,
                                  msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        else if (LocaleCompare((char *) name, "set") == 0)
          {
            MSL_BREAK_IF_IMAGE_NULL(msl_info->image[n]);
            MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'B':
                  case 'b':
                    {
                      if (LocaleCompare(keyword,"background") == 0)
                        {
                          (void) QueryColorDatabase
                            (value,
                             &msl_info->image_info[n]->background_color,
                             msl_info->exception);
                          break;
                        }
                      else if (LocaleCompare(keyword,"bordercolor") == 0)
                        {
                          (void) QueryColorDatabase
                            (value,
                             &msl_info->image_info[n]->border_color,
                             msl_info->exception);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'C':
                  case 'c':
                    {
                      if (LocaleCompare(keyword,"clip-mask") == 0)
                        {
                          for (j=0; j<msl_info->n;j++)
                            {
                              const ImageAttribute *
                                theAttr =
                                GetImageAttribute(msl_info->attributes[j],
                                                  "id");
                              if (theAttr &&
                                  LocaleCompare(theAttr->value, value) == 0)
                                {
                                  (void) SetImageClipMask(msl_info->image[n],
                                                          msl_info->image[j]);
                                  break;
                                }
                            }
                          break;
                        }
                      else if (LocaleCompare(keyword, "colorspace") == 0)
                        {
                          if (LocaleCompare(value, "CMYK") == 0)
                            (void) SetImageType( msl_info->image[n],
                                                 ColorSeparationType );
                          else if (LocaleCompare(value, "Gray") == 0)
                            (void) SetImageType( msl_info->image[n],
                                                 GrayscaleType );
                          else if (LocaleCompare(value, "RGB") == 0)
                            (void) SetImageType( msl_info->image[n],
                                                 TrueColorType );
                          else
                            ThrowException(msl_info->exception,OptionError,
                                           UnrecognizedColorspace,keyword);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'D':
                  case 'd':
                    {
                      if (LocaleCompare(keyword, "density") == 0)
                        {
                          (void) CloneString(&msl_info->image_info[n]->density,
                                             (char*)NULL);
                          (void) CloneString(&msl_info->image_info[n]->density,
                                             value);
                          (void) CloneString
                            (&msl_info->draw_info[n]->density,
                             msl_info->image_info[n]->density);
                          j=GetMagickDimension
                            (msl_info->image_info[n]->density,
                             &msl_info->image[n]->x_resolution,
                             &msl_info->image[n]->y_resolution,
                             NULL,NULL);
                          if (j != 2)
                            msl_info->image[n]->y_resolution =
                              msl_info->image[n]->x_resolution;
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'M':
                  case 'm':
                    {
                      if (LocaleCompare(keyword, "magick") == 0)
                        {
                          (void) strlcpy( msl_info->image_info[n]->magick,
                                          value,
                                          sizeof(msl_info->image_info[n]->magick) );
                          break;
                        }
                      else if (LocaleCompare(keyword,"mattecolor") == 0)
                        {
                          (void) QueryColorDatabase
                            (value,
                             &msl_info->image_info[n]->matte_color,
                             msl_info->exception);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'O':
                  case 'o':
                    {
                      if (LocaleCompare(keyword, "opacity") == 0)
                        {
                          double opac = 0.0;
                          size_t len = strlen( value );

                          if (MagickAtoFChk( value, &opac ) == MagickFail)
                            {
                              ThrowException(msl_info->exception,OptionError,
                                             UsageError,keyword);
                              break;
                            }
                          if ((opac > 0.0) && (len > 1) && value[len-1] == '%')
                            opac = (MaxRGBDouble * (opac/100.0));

                          SetImageOpacity( msl_info->image[n], (unsigned int) opac );
                          break;
                        }

                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }
            break;
          }
        else if (LocaleCompare((char *) name, "sharpen") == 0)
          {
            double  radius = 0.0,
              sigma = 1.0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes != (const xmlChar **) NULL)
              {
                for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
                  {
                    keyword=(const char *) attributes[i++];
                    MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                    value=TranslateText(msl_info->image_info[n],
                                        msl_info->attributes[n],
                                        (char *) attributes[i]);
                    if (value == NULL)
                      MagickFatalError3(ResourceLimitFatalError,
                                        MemoryAllocationFailed,
                                        UnableToAllocateString);
                    switch (*keyword)
                      {
                      case 'R':
                      case 'r':
                        {
                          if (LocaleCompare(keyword, "radius") == 0)
                            {
                              radius = MagickAtoF( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      case 'S':
                      case 's':
                        {
                          if (LocaleCompare(keyword,"sigma") == 0)
                            {
                              sigma = MagickAtoI( value );
                              break;
                            }
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      default:
                        {
                          ThrowException(msl_info->exception,OptionError,
                                         UnrecognizedAttribute,keyword);
                          break;
                        }
                      }
                    MagickFreeMemory(value);
                  }
              }

            /*
              sharpen image.
            */
            {
              Image
                *newImage;

              newImage=SharpenImage(msl_info->image[n],radius,sigma,
                                    msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"shave") == 0)
          {
            /* init the values */
            width = height = 0;
            x = y = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'G':
                  case 'g':
                    {
                      if (LocaleCompare(keyword,"geometry") == 0)
                        {
                          (void) GetMagickGeometry(value,&x,&y,&width,&height);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'H':
                  case 'h':
                    {
                      if (LocaleCompare(keyword,"height") == 0)
                        {
                          height = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'W':
                  case 'w':
                    {
                      if (LocaleCompare(keyword,"width") == 0)
                        {
                          width = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;
              RectangleInfo
                rectInfo;

              rectInfo.height = height;
              rectInfo.width = width;
              rectInfo.x = x;
              rectInfo.y = y;


              newImage=ShaveImage(msl_info->image[n], &rectInfo,
                                  msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        else if (LocaleCompare((char *) name,"shear") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* init the values */
            width=msl_info->image[n]->columns;
            height=msl_info->image[n]->rows;
            x = y = 0;

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'X':
                  case 'x':
                    {
                      if (LocaleCompare(keyword,"x") == 0)
                        {
                          x = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  case 'Y':
                  case 'y':
                    {
                      if (LocaleCompare(keyword,"y") == 0)
                        {
                          y = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=ShearImage(msl_info->image[n], x, y,
                                  msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        else if (LocaleCompare((char *) name,"solarize") == 0)
          {
            /* init the values */
            double  threshold = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'T':
                  case 't':
                    {
                      if (LocaleCompare(keyword,"threshold") == 0)
                        {
                          threshold = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              (void) SolarizeImage(msl_info->image[n], threshold);
              break;
            }
          }
        else if (LocaleCompare((char *) name,"spread") == 0)
          {
            /* init the values */
            unsigned int  radius = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'R':
                  case 'r':
                    {
                      if (LocaleCompare(keyword,"radius") == 0)
                        {
                          radius = MagickAtoI( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=SpreadImage(msl_info->image[n], radius,
                                   msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        else if (LocaleCompare((char *) name,"stegano") == 0)
          {
            Image *
              watermark = (Image*)NULL;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'I':
                  case 'i':
                    {
                      if (LocaleCompare(keyword,"image") == 0)
                        {
                          for (j=0; j<msl_info->n;j++)
                            {
                              const ImageAttribute *
                                theAttr = GetImageAttribute
                                (msl_info->attributes[j], "id");
                              if (theAttr &&
                                  LocaleCompare(theAttr->value, value) == 0)
                                {
                                  watermark = msl_info->image[j];
                                  break;
                                }
                            }
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            if ( watermark != (Image*) NULL )
              {
                Image
                  *newImage;

                newImage=SteganoImage(msl_info->image[n], watermark,
                                      msl_info->exception);
                if (newImage == (Image *) NULL)
                  break;
                DestroyImage(msl_info->image[n]);
                msl_info->image[n]=newImage;
                break;
              } else
              ThrowException(msl_info->exception,OptionError,
                             MissingAnImageFilename,keyword);
          }
        else if (LocaleCompare((char *) name,"stereo") == 0)
          {
            Image *
              stereoImage = (Image*)NULL;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'I':
                  case 'i':
                    {
                      if (LocaleCompare(keyword,"image") == 0)
                        {
                          for (j=0; j<msl_info->n;j++)
                            {
                              const ImageAttribute *
                                theAttr = GetImageAttribute
                                (msl_info->attributes[j], "id");
                              if (theAttr &&
                                  LocaleCompare(theAttr->value, value) == 0)
                                {
                                  stereoImage = msl_info->image[j];
                                  break;
                                }
                            }
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            if ( stereoImage != (Image*) NULL )
              {
                Image
                  *newImage;

                newImage=StereoImage(msl_info->image[n], stereoImage,
                                     msl_info->exception);
                if (newImage == (Image *) NULL)
                  break;
                DestroyImage(msl_info->image[n]);
                msl_info->image[n]=newImage;
                break;
              } else
              ThrowException(msl_info->exception,OptionError,
                             MissingAnImageFilename,keyword);
          }
        else if (LocaleCompare((char *) name,"swirl") == 0)
          {
            /* init the values */
            double  degrees = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'D':
                  case 'd':
                    {
                      if (LocaleCompare(keyword,"degrees") == 0)
                        {
                          degrees = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              Image
                *newImage;

              newImage=SwirlImage(msl_info->image[n], degrees,
                                  msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
            }

            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'T':
    case 't':
      {
        if (LocaleCompare((char *) name,"texture") == 0)
          {
            Image *
              textureImage = (Image*)NULL;

            /*
              if the image hasn't been initted yet, then clear it to white
            */
            if (msl_info->image[n] == (Image *) NULL)
              {
                Image
                  *next_image;

                (void) strlcpy(msl_info->image_info[n]->filename,"xc:white",
                               sizeof(msl_info->image_info[n]->filename));
                next_image=ReadImage(msl_info->image_info[n],&exception);
                if (exception.severity != UndefinedException)
                  CatchException(&exception);
                if (next_image == (Image *) NULL)
                  break;
                if (msl_info->image[n] == (Image *) NULL)
                  msl_info->image[n]=next_image;
                else
                  {
                    register Image
                      *p;

                    /*
                      Link image into image list.
                    */
                    p=msl_info->image[n];
                    for ( ; p->next != (Image *) NULL; p=p->next);
                    next_image->previous=p;
                    p->next=next_image;
                  }
              }
            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'I':
                  case 'i':
                    {
                      if (LocaleCompare(keyword,"image") == 0)
                        {
                          for (j=0; j<msl_info->n;j++)
                            {
                              const ImageAttribute *
                                theAttr = GetImageAttribute
                                (msl_info->attributes[j], "id");
                              if (theAttr &&
                                  LocaleCompare(theAttr->value, value) == 0)
                                {
                                  textureImage = msl_info->image[j];
                                  break;
                                }
                            }
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            if ( textureImage != (Image*) NULL )
              {
                (void) TextureImage(msl_info->image[n], textureImage);
                break;
              }
            else
              ThrowException(msl_info->exception,OptionError,
                             MissingAnImageFilename,keyword);
          }
        else if (LocaleCompare((char *) name,"threshold") == 0)
          {
            /* init the values */
            double  threshold = 0;

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'T':
                  case 't':
                    {
                      if (LocaleCompare(keyword,"threshold") == 0)
                        {
                          threshold = MagickAtoF( value );
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }

            /*
              process image.
            */
            {
              char thresholds[MaxTextExtent];

              FormatString(thresholds,"%g",threshold);
              (void) ChannelThresholdImage(msl_info->image[n], thresholds);
              break;
            }
          }
        else if (LocaleCompare((char *) name, "transparent") == 0)
          {

            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'C':
                  case 'c':
                    {
                      if (LocaleCompare(keyword,"color") == 0)
                        {
                          PixelPacket
                            target;

                          (void) AcquireOnePixelByReference
                            (msl_info->image[n],
                             &target,0,0,
                             &(msl_info->image[n])->exception);
                          (void) QueryColorDatabase(value,&target,msl_info->exception);
                          (void) TransparentImage(msl_info->image[n],target,
                                                  TransparentOpacity);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }
            break;
          }
        else if (LocaleCompare((char *) name, "trim") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            /* no attributes here */

            /* process the image */
            {
              Image
                *newImage;
              RectangleInfo
                rectInfo;

              /* all zeros on a crop == trim edges! */
              rectInfo.height = rectInfo.width = 0;
              rectInfo.x =  rectInfo.y = 0;

              newImage=CropImage(msl_info->image[n],&rectInfo,
                                 msl_info->exception);
              if (newImage == (Image *) NULL)
                break;
              DestroyImage(msl_info->image[n]);
              msl_info->image[n]=newImage;
              break;
            }
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    case 'W':
    case 'w':
      {
        if (LocaleCompare((char *) name,"write") == 0)
          {
            MSL_BREAK_IF_IMAGE_NOT_INSTANTIATED(msl_info->image[n]);

            if (attributes == (const xmlChar **) NULL)
              break;
            for (i=0; (attributes[i] != (const xmlChar *) NULL); i++)
              {
                keyword=(const char *) attributes[i++];
                MSL_BREAK_IF_IMAGE_NULL(msl_info->attributes[n]);
                value=TranslateText(msl_info->image_info[n],
                                    msl_info->attributes[n],
                                    (char *) attributes[i]);
                if (value == NULL)
                  MagickFatalError3(ResourceLimitFatalError,
                                    MemoryAllocationFailed,
                                    UnableToAllocateString);
                switch (*keyword)
                  {
                  case 'F':
                  case 'f':
                    {
                      if (LocaleCompare(keyword,"filename") == 0)
                        {
                          (void) strlcpy(msl_info->image[n]->filename,value,
                                         MaxTextExtent);
                          (void) WriteImage(msl_info->image_info[n],
                                            msl_info->image[n]);
                          break;
                        }
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  default:
                    {
                      ThrowException(msl_info->exception,OptionError,
                                     UnrecognizedAttribute,keyword);
                      break;
                    }
                  }
                MagickFreeMemory(value);
              }
            break;
          }
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    default:
      {
        ThrowException(msl_info->exception,OptionError,
                       UnrecognizedElement,(const char *) name);
        break;
      }
    }
  if ( value != NULL )
    MagickFreeMemory(value);
  /*
    If image-specific exception has an exception more severe than MSL
    global exception, then copy to MSL global exception.
  */
  if ((msl_info->image[n] != (Image *) NULL) &&
      (msl_info->image[n]->exception.severity > msl_info->exception->severity))
    {
      CopyException(msl_info->exception,&msl_info->image[n]->exception);
    }
  if (msl_info->exception->severity >= ErrorException)
    xmlStopParser(parser);
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  )");
}

static void
MSLEndElement(void *context,const xmlChar *name)
{
  MSLInfo
    *msl_info;

  xmlParserCtxtPtr
    parser;

  /*
    Called when the end of an element has been detected.
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                        "  SAX.endElement(%.1024s)",name);
  parser=(xmlParserCtxtPtr) context;
  msl_info=(MSLInfo *) parser->_private;
  assert(msl_info->signature == MagickSignature);
  switch (*name)
    {
    case 'G':
    case 'g':
      {
        if (LocaleCompare((char *) name, "group") == 0 )
          {
            if ((msl_info->nGroups > 0) &&
                (msl_info->group_info[msl_info->nGroups-1].numImages > 0))
              {
                long  i = (long)
                  (msl_info->group_info[msl_info->nGroups-1].numImages);

                while ( (i--) && (msl_info->n > 0) )
                  {
                    if (msl_info->image[msl_info->n] != (Image *) NULL)
                      {
                        DestroyImage(msl_info->image[msl_info->n]);
                        msl_info->image[msl_info->n]=(Image *) NULL;
                      }

                    DestroyDrawInfo(msl_info->draw_info[msl_info->n]);
                    msl_info->draw_info[msl_info->n]=(DrawInfo *) NULL;

                    DestroyImage(msl_info->attributes[msl_info->n]);
                    msl_info->attributes[msl_info->n]=(Image *) NULL;

                    DestroyImageInfo(msl_info->image_info[msl_info->n]);
                    msl_info->image_info[msl_info->n]=(ImageInfo *) NULL;

                    msl_info->n--;
                  }
              }
            msl_info->nGroups--;
          }
      }
      break;

    case 'I':
    case 'i':
      {
        if (LocaleCompare((char *) name, "image") == 0)
          MSLPopImage(msl_info);
      }
      break;

    case 'M':
    case 'm':
      {
        if (LocaleCompare((char *) name, "msl") == 0 )
          {
            /*
              This is our base element.
              at the moment we don't do anything special
              but someday we might!
            */
          }
      }
      break;

    default:
      break;
    }
}

static void
MSLCharacters(void *context,const xmlChar *c,int length)
{
  MSLInfo
    *msl_info;

  xmlParserCtxtPtr
    parser;

  ARG_NOT_USED(context);
  /*
    Receiving some characters from the parser.
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                        "  SAX.characters(%.1024s,%d)",c,length);
  parser=(xmlParserCtxtPtr) context;
  msl_info=(MSLInfo *) parser->_private;
  assert(msl_info->signature == MagickSignature);
}

static void
MSLWarning(void *context,const char *format,...) MAGICK_FUNC_PRINTF_FORMAT(2,3);

static void
MSLWarning(void *context,const char *format,...)
{
  char
    reason[MaxTextExtent];

  MSLInfo
    *msl_info;

  xmlParserCtxtPtr
    parser;

  va_list
    operands;

  /**
     Display and format a warning messages, gives file, line, position and
     extra parameters.
  */
  va_start(operands,format);
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  SAX.warning: ");
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
  parser=(xmlParserCtxtPtr) context;
  msl_info=(MSLInfo *) parser->_private;
  assert(msl_info->signature == MagickSignature);
#if !defined(HAVE_VSNPRINTF)
  (void) vsprintf(reason,format,operands);
#else
  (void) vsnprintf(reason,MaxTextExtent,format,operands);
#endif
  ThrowException2(msl_info->exception,CoderError,reason,(char *) NULL);
  va_end(operands);
}

static void
MSLError(void *context,const char *format,...)
{
  char
    reason[MaxTextExtent];

  MSLInfo
    *msl_info;

  xmlParserCtxtPtr
    parser;

  va_list
    operands;

  /*
    Display and format a error formats, gives file, line, position and
    extra parameters.
  */
  va_start(operands,format);
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"  SAX.error: ");
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),format,operands);
  parser=(xmlParserCtxtPtr) context;
  msl_info=(MSLInfo *) parser->_private;
  assert(msl_info->signature == MagickSignature);
#if defined(NDEBUG)
  (void) msl_info;
#endif
#if !defined(HAVE_VSNPRINTF)
  (void) vsprintf(reason,format,operands);
#else
  (void) vsnprintf(reason,MaxTextExtent,format,operands);
#endif
  ThrowException2(msl_info->exception,DelegateFatalError,reason,(char *) NULL);
  va_end(operands);
  xmlStopParser(parser);
}

#if defined(__cplusplus) || defined(c_plusplus)
/* } */
#endif

/*
  Note that if an image is passed in, that it is from the writer and
  should never be freed!
 */
static unsigned int
ProcessMSLScript(const ImageInfo *image_info,Image **image,
                 ExceptionInfo *exception)
{
  xmlSAXHandler
    SAXModules;

  char
    message[MaxTextExtent];

  Image
    *writer_image,
    *msl_image;

  long
    n;

  MSLInfo
    msl_info;

  MagickPassFail
    status;

  xmlSAXHandlerPtr
    SAXHandler;

  xmlParserCtxtPtr
    parser;

  /*
    Libxml initialization.  We call it here since initialization can
    be expensive and we don't know when/if libxml will be
    needed. Should normally be called at program start-up but may be
    called several times since libxml uses a flag to know if it has
    already been initialized.  When libxml2 is built to support
    threads, it tests if it is already initialized under a lock and
    holds a lock while it is being initialized so calling this
    function from multiple threads is ok.
  */
  xmlInitParser();

  /*
    Open image file.
  */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image **) NULL);
  writer_image=*image; /* Non-null if writing */
  (void) memset(&msl_info,0,sizeof(msl_info));
  msl_image=AllocateImage(image_info);
  status=OpenBlob(image_info,msl_image,ReadBinaryBlobMode,exception);
  if (status == MagickFail)
    {
      DestroyImage(msl_image);
      ThrowException(exception,FileOpenError,UnableToOpenFile,
                     image_info->filename);
      return(MagickFail);
    }

  /*
    Parse MSL file.
  */
  (void) memset(&msl_info,0,sizeof(MSLInfo));
  msl_info.exception=exception;
  msl_info.image_info=MagickAllocateMemory(ImageInfo **,sizeof(ImageInfo *));
  msl_info.draw_info=MagickAllocateMemory(DrawInfo **,sizeof(DrawInfo *));
  /* top of the stack is the MSL file itself */
  msl_info.image=MagickAllocateMemory(Image **,sizeof(Image *));
  msl_info.attributes=MagickAllocateMemory(Image **,sizeof(Image *));
  msl_info.group_info=MagickAllocateResourceLimitedClearedMemory(MSLGroupInfo *,
                                                                 sizeof(MSLGroupInfo));
  if ((msl_info.image_info == (ImageInfo **) NULL) ||
      (msl_info.draw_info == (DrawInfo **) NULL) ||
      (msl_info.image == (Image **) NULL) ||
      (msl_info.attributes == (Image **) NULL) ||
      (msl_info.group_info == (MSLGroupInfo *) NULL))
    {
      ThrowException3(exception,ResourceLimitError,
                      MemoryAllocationFailed,UnableToInterpretMSLImage);
      goto  msl_info_error;
    }
  msl_info.image_info[0]=CloneImageInfo(image_info);
  msl_info.draw_info[0]=CloneDrawInfo(image_info,(DrawInfo *) NULL);
  if (image_info->attributes)
    msl_info.attributes[0]=CloneImage(image_info->attributes,0,0,True,exception);
  else
    msl_info.attributes[0]=(Image *) NULL;
  msl_info.group_info[0].numImages=0;
  /* the first slot is used to point to the MSL file image */
  msl_info.image[0]=msl_image;
  if (writer_image != (Image *) NULL)
    MSLPushImage(&msl_info,writer_image);
  msl_info.signature=MagickSignature;

  (void) memset(&SAXModules,0,sizeof(SAXModules));

  /*
    TODO: Upgrade to SAX version 2 (startElementNs/endElementNs)
  */
  xmlSAXVersion(&SAXModules,1);
  SAXModules.startElement=MSLStartElement;
  SAXModules.endElement=MSLEndElement;
  SAXModules.reference=(referenceSAXFunc) NULL;
  SAXModules.characters=MSLCharacters;
  SAXModules.ignorableWhitespace=(ignorableWhitespaceSAXFunc) NULL;
  SAXModules.processingInstruction=(processingInstructionSAXFunc) NULL;
  SAXModules.comment=(commentSAXFunc) NULL;
  SAXModules.warning=MSLWarning;
  SAXModules.error=MSLError;
  SAXModules.fatalError=MSLError;
  SAXModules.cdataBlock=MSLCharacters;
  /*
    The following fields are extensions available only on version 2:
    startElementNsSAX2Func startElementNs;
    endElementNsSAX2Func endElementNs;
    xmlStructuredErrorFunc serror;
  */

  SAXHandler=(&SAXModules);
  parser=xmlCreatePushParserCtxt(SAXHandler, /* a SAX handler (optional) */
                                 (void *) NULL, /* user data for SAX callbacks (optional)  */
                                 (char *) NULL,/* initial chunk (optional, deprecated)  */
                                 0, /* size of initial chunk in bytes  */
                                 msl_image->filename); /* file name or URI (optional)  */
  if (parser == (xmlParserCtxtPtr) NULL)
    {
      ThrowException3(exception,ResourceLimitError,
                      MemoryAllocationFailed,UnableToInterpretMSLImage);
      goto parser_alloc_failure;
    }
  parser->_private=(MSLInfo *) &msl_info;
  while (ReadBlobString(msl_image,message) != (char *) NULL)
    {
      n=(long) strlen(message);
      if (n == 0)
        continue;
      status=xmlParseChunk(parser,message,(int) n,False); /* here */
      if (status != 0)
        break;
      status=xmlParseChunk(parser," ",1,False);
      if (status != 0)
        break;
      if (msl_info.exception->severity != UndefinedException)
        break;
    }
  if (msl_info.exception->severity == UndefinedException)
    (void) xmlParseChunk(parser," ",1,True);

  /*
    Assure that our private context is freed, even if we abort before
    seeing the document end.
  */
  if (parser->myDoc != (xmlDocPtr) NULL)
    {
      xmlFreeDoc(parser->myDoc);
      parser->myDoc = (xmlDocPtr) NULL;
    }
  /*
    Free all the memory used by a parser context. However the parsed
    document in ctxt->myDoc is not freed (so we just did that).
  */
  xmlFreeParserCtxt(parser);
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),"end SAX");

  /* xmlCleanupParser(); */

  /*   printf("ProcessMSLScript(msl_info->n=%ld\n",msl_info.n); */

 msl_info_error:

  msl_image=msl_info.image[0];

  /*
    Capture any exception which might have been reported to MSL file
    image.
  */
  if (msl_image->exception.severity > exception->severity)
    CopyException(exception,&msl_image->exception);

  /*
    Allocations from MSLPushImage().  MSLPopImage() should already do this.
  */
  if (msl_info.nGroups == 0)
    {
      while (msl_info.n > 0)
        {
          /*
            Do not destroy image which was passed in from the writer!
          */
          if (writer_image != msl_info.image[msl_info.n])
            {
              if (msl_info.image[msl_info.n]->exception.severity > exception->severity)
                CopyException(exception,&msl_info.image[msl_info.n]->exception);
              DestroyImage(msl_info.image[msl_info.n]);
              msl_info.image[msl_info.n]=(Image *) NULL;
            }

          DestroyDrawInfo(msl_info.draw_info[msl_info.n]);
          msl_info.draw_info[msl_info.n]=(DrawInfo *) NULL;

          DestroyImage(msl_info.attributes[msl_info.n]);
          msl_info.attributes[msl_info.n]=(Image *) NULL;

          DestroyImageInfo(msl_info.image_info[msl_info.n]);
          msl_info.image_info[msl_info.n]=(ImageInfo *) NULL;
          msl_info.n--;
        }
    }

 parser_alloc_failure:

  /*
    FIXME: May also need to handle group destruction similar to in
    MSLEndElement() if libxml2 does not process an end element.
  */
  DestroyDrawInfo(msl_info.draw_info[0]);
  msl_info.draw_info[0]=(DrawInfo *) NULL;

  DestroyImage(msl_info.attributes[0]);
  msl_info.attributes[0]=(Image *) NULL;

  DestroyImageInfo(msl_info.image_info[0]);
  msl_info.image_info[0]=(ImageInfo *) NULL;

  MagickFreeMemory(msl_info.image_info);
  MagickFreeMemory(msl_info.draw_info);
  MagickFreeMemory(msl_info.attributes);
  MagickFreeMemory(msl_info.image);
  MagickFreeResourceLimitedMemory(msl_info.group_info);

  CloseBlob(msl_image);
  /*
    If acting as writer, then destroy temporary msl_image, otherwise,
    return msl_image as the image which was read
  */
  if (writer_image != (Image *) NULL)
    {
      DestroyImage(msl_image);
      msl_image=(Image *) NULL;
    }
  else
    {
      if (exception->severity < ErrorException)
        {
          *image=msl_image;
        }
      else
        {
          DestroyImage(msl_image);
          msl_image=(Image *) NULL;
        }
    }

  /* FIXME: It is not clear what constitutes "success" for MSL */
  return exception->severity < ErrorException ? MagickPass : MagickFail;
}

static Image *
ReadMSLImage(const ImageInfo *image_info,ExceptionInfo *exception)
{
  Image *
    image;

  MagickPassFail
    status;

  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);

  /*
    Open image file.
  */
  image=(Image *) NULL;
  status=ProcessMSLScript(image_info,&image,exception);

  if (status == MagickFail)
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                          "ProcessMSLScript() returned MagickFail!");
  return(image);
}
#endif /* defined(HasXML) */

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e g i s t e r M S L I m a g e                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method RegisterMSLImage adds attributes for the MSL image format to
%  the list of supported formats.  The attributes include the image format
%  tag, a method to read and/or write the format, whether the format
%  supports the saving of more than one frame to the same file or blob,
%  whether the format supports native in-memory I/O, and a brief
%  description of the format.
%
%  The format of the RegisterMSLImage method is:
%
%      RegisterMSLImage(void)
%
*/
ModuleExport void
RegisterMSLImage(void)
{
#if defined(HasXML)
  MagickInfo
    *entry;

  entry=SetMagickInfo("MSL");
  entry->decoder=(DecoderHandler) ReadMSLImage;
  entry->encoder=(EncoderHandler) WriteMSLImage;
  entry->description="Magick Scripting Language";
  entry->module="MSL";
  entry->extension_treatment=IgnoreExtensionTreatment;
  (void) RegisterMagickInfo(entry);
#endif /* defined(HasXML) */
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   U n r e g i s t e r M S L I m a g e                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method UnregisterMSLImage removes format registrations made by the
%  MSL module from the list of supported formats.
%
%  The format of the UnregisterMSLImage method is:
%
%      UnregisterMSLImage(void)
%
*/
ModuleExport void
UnregisterMSLImage(void)
{
#if defined(HasXML)
  (void) UnregisterMagickInfo("MSL");
#endif /* defined(HasXML) */
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   W r i t e M S L I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Method WriteMSLImage processes the image via a MSL script.
%
%  The format of the WriteMSLImage method is:
%
%      unsigned int WriteMSLImage(const ImageInfo *image_info,Image *image)
%
%  A description of each parameter follows.
%
%    o status: Method WriteMSLImage return True if the image is written.
%      False is returned is there is a memory shortage or if the image file
%      fails to write.
%
%    o image_info: Specifies a pointer to a ImageInfo structure.
%
%    o image:  A pointer to an Image structure.
%
%
*/
#if defined(HasXML)
static unsigned int WriteMSLImage(const ImageInfo *image_info,Image *image)
{
  MagickPassFail
    status;

  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickSignature);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
  if (status == False)
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
  /* (void) ReferenceImage(image); what for? */
  status=ProcessMSLScript(image_info,&image,&image->exception);
  if (status == MagickFail)
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                          "ProcessMSLScript() returned MagickFail!");
  status &= CloseBlob(image);
  return status;
}
#endif /* defined(HasXML) */
