/*
   Implementation of a CLI command using a MagickWand API

     magick -size 100x100 xc:red \
            \( rose: -rotate -90 \) \
            +append   show:


   Compile with ImageMagick-devlop installed...

     gcc -lMagickWand -lMagickCore wand.c -o wand

   Compile and run directly from Source Directory...

     IM_PROG=api_examples/wand
     gcc -I`pwd` -LMagickWand/.libs -LMagickCore/.libs \
       -lMagickWand -lMagickCore  $IM_PROG.c -o $IM_PROG

     sh ./magick.sh    $IM_PROG

*/
#include <stdio.h>
#include "MagickWand/MagickWand.h"

/* Simplify the exception handling
 * technically we should abort the program if
 *      severity >= ErrorException
 */
void ThrowWandException(MagickWand *wand)
{ char
  *description;

  ExceptionType
  severity;

  description=MagickGetException(wand,&severity);
  (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description);
  description=(char *) MagickRelinquishMemory(description);
}

/* useful function especially after appending two wands together */
#define SwapWands(a,b) { MagickWand *tmp=a; a=b; b=tmp; }

int main(int argc, char *argv[])
{
    MagickWand
      *red,     /* red image wand */
      *rose,    /* rose image wand */
      *output;  /* the appended output image */

    PixelWand
      *color;

    MagickBooleanType
      status;

    MagickWandGenesis();

    /* read in the red image */
    red = NewMagickWand();
    MagickSetSize(red,100,100);
    status = MagickReadImage(red, "xc:red" );
    if (status == MagickFalse)
      ThrowWandException(red);
    /* NOTE ABOUT MagickReadImage()
     * Unless the wand is empty set the first/last iterator to determine
     * if the read image(s) are to be prepend/append into that wand image
     * list.
     *
     * Setting a specific index always 'inserts' before that image.
     */

    /* read in the rose image */
    rose = NewMagickWand();
    status = MagickReadImage(rose, "rose:" );
    if (status == MagickFalse)
      ThrowWandException(rose);

    /* rotate the rose image - one image only */
    color=NewPixelWand();
    PixelSetColor(color, "white");
    status = MagickRotateImage(rose,color,-90.0);
    if (status == MagickFalse)
      ThrowWandException(rose);
    color = DestroyPixelWand(color);

    /* append rose image into the red image wand */
    MagickSetLastIterator(red);
    MagickAddImage(red,rose);
    rose = DestroyMagickWand(rose);  /* finished with 'rose' wand */
    /* NOTE ABOUT MagickAddImage()
     *
     * Always set the first/last image in the destination wand so that
     * IM knows if you want to prepend/append the images into that wands
     * image list.
     *
     * Setting a specific index always 'inserts' before that image.
     */

    /* append all images together to create the output wand */
    MagickSetFirstIterator(red);
    output = MagickAppendImages(red,MagickFalse);
    red = DestroyMagickWand(red);  /* finished with 'red' wand */
    /* NOTE ABOUT MagickAppendImages()
     *
     * It is important to either 'set first' or 'reset' the iterator before
     * appending images, as only images from current image onward are
     * appended together.
     *
     * Also note how a new wand is created by this operation, and that new
     * wand does not inherit any settings from the previous wand (at least not
     * at this time).
     */

    /* Final output */
    status = MagickWriteImage(output,"show:");
    if (status == MagickFalse)
      ThrowWandException(output);

    output = DestroyMagickWand(output);

    MagickWandTerminus();
}

/*
 * The above can be simplified further, though that is not what "magick"
 * command would do which we are simulating.
 *
 * Specifically you can read the 'rose' image directly on the end of of
 * 'red' image wand.  Then process just that rose image, even though it is
 * sharing the same wand as another image.
 *
 * Remember in MagickWand, simple image operators are only applied to the
 * current image in the wand an to no other image!  To apply a simple image
 * operator (like MagickRotateImage()) to all the images in a wand you must
 * iterate over all the images yourself.
 */