mpr: within -draw

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

mpr: within -draw

Post by rmabry »

Hi folks,
I'm compositing a large number of small images onto various positions of a large image and I'm running into memory issues and inefficiency. The number of composites is in the thousands, but the actual number of files generating the small images is relatively small. Each small image is resized via the size specified within the -draw string (e.g., to size 60x60 here:)

Code: Select all

 -draw "image Darken 100,100 60,60 'tile117.jpg'"
Thousands of similar draw strings are stored in a file "drawstrings.txt" and I execute a command like

Code: Select all

convert -size 6000,8175 xc:white -draw @drawstrings.txt out.png
This leads to an unnecessarily large number of resize operations, because there are only a few hundred images involved (tile001.jpg, tile002.jpg, etc.)

I could use virtual images via mpr: but that doesn't seem permissible (or is it?) within a -draw string, which seems to accept only a filename.

Any ideas? (I'll be working on a Perl script in the meantime, but it would be nice to have such options on the command line.)

Thanks,

Rick
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: mpr: within -draw

Post by magick »

The -draw image primitive accepts any / all image types supported by ImageMagick including MPR and inline images (i.e. starts with DATA: and includes a base64-encoded string). You could get some speed up if the tile is used often at a particular dimension and it pre-resized. The best solution is probably to implement this using one of the ImageMagick API's (e.g. MagickWand) or scripting language (e.g. PerlMagick). Our recommendation is the Pixel View methods of MagickWand. It runs in parallel so if you have a dual-core or quad-core processor you can get a 2-4x speed-up.
User avatar
rmabry
Posts: 148
Joined: 2004-04-13T11:25:27-07:00

Re: mpr: within -draw

Post by rmabry »

Thanks for the (as usual) speedy reply.

> The -draw image primitive accepts any / all image types supported by ImageMagick including MPR

Yup -- it was a string quoting-within-quotes issue. Sorry for the bother.

> inline images (i.e. starts with DATA: and includes a base64-encoded string)

Now that is very cool --- it gets Magicker and Magicker.

I appreciate the other advice and I'll look into using MagickWand, which is still magick to me. I'm still using the old API.

Rick
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: mpr: within -draw

Post by magick »

We have a sample program that utilizes the pixel view API which is way cool. It removes most of the complication when dealing with image pixels. To composite tiles, use TransferPixelViewIterator() which permits you to read pixels from one magick wand (the tile) and place it anywhere on the destination wand.

Save the code as sigmoidal-contrast.c and build with this command:
  • cc `MagickWand-config --cflags --cppflags` -o sigmoidal-contrast sigmoidal-contrast.c `MagickWand-config --ldflags --libs`

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <wand/MagickWand.h>

static MagickBooleanType SigmoidalContrast(PixelView *pixel_view,
  void *context)
{
#define QuantumScale  ((MagickRealType) 1.0/(MagickRealType) QuantumRange)
#define SigmoidalContrast(x) \
  (QuantumRange*(1.0/(1+exp(10.0*(0.5-QuantumScale*x)))-0.0066928509)*1.0092503)

  MagickPixelPacket
    pixel;

  PixelWand
    **pixels;

  register long
    x;

  pixels=GetPixelViewPixels(contrast_view);
  for (x=0; x < (long) GetPixelViewWidth(contrast_view); x++)
  {
    PixelGetMagickColor(pixels[x],&pixel);
    pixel.red=SigmoidalContrast(pixel.red);
    pixel.green=SigmoidalContrast(pixel.green);
    pixel.blue=SigmoidalContrast(pixel.blue);
    pixel.index=SigmoidalContrast(pixel.index);
    PixelSetMagickColor(contrast_pixels[x],&pixel);
  }
  return(MagickTrue);
}

int main(int argc,char **argv)
{
#define ThrowWandException(wand) \
{ \
  char \
    *description; \
 \
  ExceptionType \
    severity; \
 \
  description=MagickGetException(wand,&severity); \
  (void) fprintf(stderr,"%s %s %lu %s\n",GetMagickModule(),description); \
  description=(char *) MagickRelinquishMemory(description); \
  exit(-1); \
}

  MagickBooleanType
    status;

  MagickPixelPacket
    pixel;

  MagickWand
    *contrast_wand;

  PixelView
    *contrast_view;

  if (argc != 3)
    {
      (void) fprintf(stdout,"Usage: %s image sigmoidal-image\n",argv[0]);
      exit(0);
    }
  /*
    Read an image.
  */
  MagickWandGenesis();
  contrast_wand=NewMagickWand();
  status=MagickReadImage(contrast_wand,argv[1]);
  if (status == MagickFalse)
    ThrowWandException(contrast_wand);
  /*
    Sigmoidal non-linearity contrast control.
  */
  contrast_view=NewPixelView(contrast_wand);
  if (contrast_view == (PixelView *) NULL)
    ThrowWandException(contrast_wand);
  status=UpdatePixelViewIterator(contrast_view,SigmoidalContrast,(void *) NULL);
  if (status == MagickFalse)
    ThrowWandException(contrast_wand);
  contrast_view=DestroyPixelView(contrast_view);
  /*
    Write the image then destroy it.
  */
  status=MagickWriteImages(contrast_wand,argv[2],MagickTrue);
  if (status == MagickFalse)
    ThrowWandException(contrast_wand);
  contrast_wand=DestroyMagickWand(contrast_wand);
  MagickWandTerminus();
  return(0);
}
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: mpr: within -draw

Post by anthony »

magick wrote:Inline images (i.e. starts with DATA: and includes a base64-encoded string).
Now THAT is cool. and one I did not know about!!!
An no wonder it isn't listed by

Code: Select all

convert -list format
That would be more useful for reading images from MVG files, as rmabry is doing and for ImageMagick API's than command line use, otherwise command line limits could start to overflow shell limits.

Hopefully the IM v7 idea for 'streaming' options would be able to make more use of this.

Now for a small example for IM examples!
If I can get it working.

Hmmm. this fails...

Code: Select all

convert data:`convert -size 4x4 xc:red -depth 8 ppm:- | gmime-uuencode --base64 - | sed '$d; 1d;' | tr -d ' \012'` x:
convert: unable to open image `data:UDYKNCA0CjI1NQr/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAA=': No such file or directory.
convert: missing an image filename `x:'.
I don't think it is even recognizing 'data'.

Suggestions about using data: is it restricted to MVG only?
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: mpr: within -draw

Post by magick »

We added inline: as a supported format. Will need a day or to ensure it actually works.
Post Reply