Cloning and the MagickWand API

Questions and postings pertaining to the development of ImageMagick, feature enhancements, and ImageMagick internals. ImageMagick source code and algorithms are discussed here. Usage questions which are too arcane for the normal user list should also be posted here.
Post Reply
rmagick
Posts: 245
Joined: 2006-03-16T17:30:48-07:00
Location: Durham, NC, USA

Cloning and the MagickWand API

Post by rmagick »

I've been looking at the MagickWand API and I have two questions.

1. I see the CloneMagickWand method makes an exact copy of a wand. Given a wand with several images, how would I go about creating a new wand that contains a subset of those images? For example, given wand A containing 4 images, create wand B that is otherwise-identical but contains only images 2 and 3.

2. My memory is that a cloned image shares the pixel cache with the original image until one of the images tries to modify a pixel, at which point the cache is duplicated. That is, the pixel cache has copy-on-write semantics. Is that correct?

Where I'm going with this is that I'd like to be able to read a multi-image file into a wand, select one or more of the images into a new wand, and then do some operations on the new wand. It would be useful if there was only one copy of the pixel data as long as neither wand modifies the pixels.
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Cloning and the MagickWand API

Post by magick »

As you mentioned, cloning is light weight. Each clone increments the reference count to the original pixel cache and a new cache is created only when you signal your intention to update the pixels.

You can create a subset of images from a wand using existing methods shown in wandtest.c:

Code: Select all

  (void) fprintf(stdout,"Iterate forward...\n");
  MagickResetIterator(magick_wand);
  while (MagickNextImage(magick_wand) != MagickFalse)
    (void) fprintf(stdout,"index %ld scene %lu\n",
      MagickGetIteratorIndex(magick_wand),MagickGetImageScene(magick_wand));
  (void) fprintf(stdout,"Iterate reverse...\n");
  while (MagickPreviousImage(magick_wand) != MagickFalse)
    (void) fprintf(stdout,"index %ld scene %lu\n",
      MagickGetIteratorIndex(magick_wand),MagickGetImageScene(magick_wand));
  (void) fprintf(stdout,"Remove scene 1...\n");
  (void) MagickSetIteratorIndex(magick_wand,1);
  clone_wand=MagickGetImage(magick_wand);
  status=MagickRemoveImage(magick_wand);
  if (status == MagickFalse)
    ThrowAPIException(magick_wand);
  MagickResetIterator(magick_wand);
  while (MagickNextImage(magick_wand) != MagickFalse)
    (void) fprintf(stdout,"index %ld scene %lu\n",
      MagickGetIteratorIndex(magick_wand),MagickGetImageScene(magick_wand));
  (void) fprintf(stdout,"Insert scene 1 back in sequence...\n");
  (void) MagickSetIteratorIndex(magick_wand,0);
  status=MagickAddImage(magick_wand,clone_wand);
  if (status == MagickFalse)
    ThrowAPIException(magick_wand);
  while (MagickNextImage(magick_wand) != MagickFalse)
    (void) fprintf(stdout,"index %ld scene %lu\n",
      MagickGetIteratorIndex(magick_wand),MagickGetImageScene(magick_wand));
  (void) fprintf(stdout,"Set scene 2 to scene 1...\n");
  (void) MagickSetIteratorIndex(magick_wand,2);
  status=MagickSetImage(magick_wand,clone_wand);
  clone_wand=DestroyMagickWand(clone_wand);
  if (status == MagickFalse)
    ThrowAPIException(magick_wand);
  MagickResetIterator(magick_wand);
  while (MagickNextImage(magick_wand) != MagickFalse)
    (void) fprintf(stdout,"index %ld scene %lu\n",
      MagickGetIteratorIndex(magick_wand),MagickGetImageScene(magick_wand));
We could create a convenience method but by using the existing methods as shown above your code will be backwards compatible.
rmagick
Posts: 245
Joined: 2006-03-16T17:30:48-07:00
Location: Durham, NC, USA

Re: Cloning and the MagickWand API

Post by rmagick »

Perfect. Thanks! I agree, this code is better than a convenience method.
Post Reply