Search code examples
cimagemagickmagickwand

How to combine images using MagickWand C API?


I have a two images And I want to combine them together, similar command for this is convert one.png two.png +clone -combine displaceMask.png. Below is my C Code. I'm not getting the perfect result using C.

#include <stdio.h>
#include "MagickWand/MagickWand.h"
int main(int argc, const char * argv[]) {

  MagickWand *wand1, *wand2, *wand3;

  wand1 = NewMagickWand();
  wand2 = NewMagickWand();
  wand3 = NewMagickWand();

  MagickReadImage(wand1, "one.png");
  MagickReadImage(wand2, "two.png");

  // convert one.png two.png +clone -combine displaceMask.png
  wand3 = CloneMagickWand(wand2);
  MagickAddImage(wand1, wand2);
  MagickAddImage(wand1, wand3);
  MagickCombineImages(wand1,RGBColorspace);
  MagickWriteImage(wand1,"merge.png");

  if(wand1)wand1 = DestroyMagickWand(wand1);
  if(wand2)wand2 = DestroyMagickWand(wand2);
  if(wand3)wand3 = DestroyMagickWand(wand3);
  MagickWandTerminus();

  return 0;
}

These are the images.

one.png

enter image description here two.png

enter image description here finalResultUsingCMd.png

enter image description here

merge.png (This image I'm getting using C code. But I want a above image.) enter image description here


Solution

  • Updated Answer

    In addition to capturing combine results, you'll need to reset the wand iterator before applying the MagickCombineImages. This is because each time you invoke MagickAddImage the internal linked list is pointing to the newly added node. (Hope I explained that clearly.)

    Quoting some documents...

    After using any images added to the wand using MagickAddImage() or MagickReadImage() will be prepended before any image in the wand.

    Also the current image has been set to the first image (if any) in the Magick Wand. Using MagickNextImage() will then set teh current image to the second image in the list (if present).

    This operation is similar to MagickResetIterator() but differs in how MagickAddImage(), MagickReadImage(), and MagickNextImage() behaves afterward.

    So your example code should look like ...

    #include "MagickWand/MagickWand.h"
    int main(int argc, const char * argv[]) {
    
      MagickWand
          *wand1,
          *wand2,
          *wand3,
          *result;
    
      wand1 = NewMagickWand();
      wand2 = NewMagickWand();
    
      MagickReadImage(wand1, "one.png");
      MagickReadImage(wand2, "two.png");
    
      // convert one.png two.png +clone -combine displaceMask.png
      wand3 = CloneMagickWand(wand2);
      MagickAddImage(wand1, wand2);
      MagickAddImage(wand1, wand3);
      MagickSetFirstIterator(wand1);
      result = MagickCombineImages(wand1, MagickGetImageColorspace(wand1));
      MagickWriteImage(result,"merge.png");
    
      wand1 = DestroyMagickWand(wand1);
      wand2 = DestroyMagickWand(wand2);
      wand3 = DestroyMagickWand(wand3);
      result = DestroyMagickWand(result);
      MagickWandTerminus();
    
      return 0;
    }
    

    copy of merge.png

    Original Answer

    The MagickCombineImages method should return a pointer MagickWand * containing the result of the combine action. The behavior of this method has changed between version of IM 6 & IM 7, so it's more than possible that a bug exists, or implementation has adjusted. I'm not around IM 7 to verify at the moment, but here's a work around.

    // convert one.png two.png +clone -combine displaceMask.png
    wand3 = CloneMagickWand(wand2);
    MagickCompositeImage(wand1, wand2, CopyGreenCompositeOp, MagickTrue, 0, 0);
    MagickCompositeImage(wand1, wand3, CopyBlueCompositeOp,  MagickTrue, 0, 0);
    MagickWriteImage(wand1, "merge.png");
    

    merge.png