Ejemplo n.º 1
0
MagickExport Image *ChannelFxImage(const Image *image,const char *expression,
  ExceptionInfo *exception)
{
#define ChannelFxImageTag  "ChannelFx/Image"

  ChannelFx
    channel_op;

  ChannelType
    channel_mask;

  char
    token[MaxTextExtent];

  const char
    *p;

  const Image
    *source_image;

  double
    pixel;

  Image
    *destination_image;

  MagickBooleanType
    status;

  PixelChannel
    source_channel,
    destination_channel;

  ssize_t
    channels;

  assert(image != (Image *) NULL);
  assert(image->signature == MagickSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickSignature);
  source_image=image;
  destination_image=CloneImage(source_image,0,0,MagickTrue,exception);
  if (destination_image == (Image *) NULL)
    return((Image *) NULL);
  if (expression == (const char *) NULL)
    return(destination_image);
  destination_channel=RedPixelChannel;
  channel_mask=UndefinedChannel;
  pixel=0.0;
  p=(char *) expression;
  GetMagickToken(p,&p,token);
  channel_op=ExtractChannelOp;
  for (channels=0; *token != '\0'; )
  {
    ssize_t
      i;

    /*
      Interpret channel expression.
    */
    switch (*token)
    {
      case ',':
      {
        GetMagickToken(p,&p,token);
        break;
      }
      case '|':
      {
        if (GetNextImageInList(source_image) != (Image *) NULL)
          source_image=GetNextImageInList(source_image);
        else
          source_image=GetFirstImageInList(source_image);
        GetMagickToken(p,&p,token);
        break;
      }
      case ';':
      {
        Image
          *canvas;

        SetPixelChannelMask(destination_image,channel_mask);
        if ((channel_op == ExtractChannelOp) && (channels == 1))
          (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
        status=SetImageStorageClass(destination_image,DirectClass,exception);
        if (status == MagickFalse)
          {
            destination_image=DestroyImageList(destination_image);
            return(destination_image);
          }
        canvas=CloneImage(source_image,0,0,MagickTrue,exception);
        if (canvas == (Image *) NULL)
          {
            destination_image=DestroyImageList(destination_image);
            return(destination_image);
          }
        AppendImageToList(&destination_image,canvas);
        destination_image=GetLastImageInList(destination_image);
        GetMagickToken(p,&p,token);
        channels=0;
        destination_channel=RedPixelChannel;
        channel_mask=UndefinedChannel;
        break;
      }
      default:
        break;
    }
    i=ParsePixelChannelOption(token);
    if (i < 0)
      {
        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
          "UnrecognizedChannelType","`%s'",token);
        destination_image=DestroyImageList(destination_image);
        return(destination_image);
      }
    source_channel=(PixelChannel) i;
    channel_op=ExtractChannelOp;
    GetMagickToken(p,&p,token);
    if (*token == '<')
      {
        channel_op=ExchangeChannelOp;
        GetMagickToken(p,&p,token);
      }
    if (*token == '=')
      {
        if (channel_op != ExchangeChannelOp)
          channel_op=AssignChannelOp;
        GetMagickToken(p,&p,token);
      }
    if (*token == '>')
      {
        if (channel_op != ExchangeChannelOp)
          channel_op=TransferChannelOp;
        GetMagickToken(p,&p,token);
      }
    switch (channel_op)
    {
      case AssignChannelOp:
      {
        pixel=StringToDoubleInterval(token,(double) QuantumRange+1.0);
        GetMagickToken(p,&p,token);
        break;
      }
      case ExchangeChannelOp:
      case TransferChannelOp:
      {
        i=ParsePixelChannelOption(token);
        if (i < 0)
          {
            (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
              "UnrecognizedChannelType","`%s'",token);
            destination_image=DestroyImageList(destination_image);
            return(destination_image);
          }
        destination_channel=(PixelChannel) i;
        switch (destination_channel)
        {
          case RedPixelChannel:
          case GreenPixelChannel:
          case BluePixelChannel:
          case BlackPixelChannel:
          case IndexPixelChannel:
            break;
          case AlphaPixelChannel:
          {
            destination_image->alpha_trait=BlendPixelTrait;
            break;
          }
          case ReadMaskPixelChannel:
          {
            destination_image->read_mask=MagickTrue;
            break;
          }
          case WriteMaskPixelChannel:
          {
            destination_image->write_mask=MagickTrue;
            break;
          }
          case MetaPixelChannel:
          default:
          {
            (void) SetPixelMetaChannels(destination_image,(size_t) (i-
              GetPixelChannels(destination_image)+1),exception);
            break;
          }
        }
        channel_mask=(ChannelType) (channel_mask | ParseChannelOption(token));
        if (((channels >= 1)  || (destination_channel >= 1)) &&
            (IsGrayColorspace(destination_image->colorspace) != MagickFalse))
          (void) SetImageColorspace(destination_image,sRGBColorspace,exception);
        GetMagickToken(p,&p,token);
        break;
      }
      default:
        break;
    }
    status=ChannelImage(destination_image,destination_channel,channel_op,
      source_image,source_channel,ClampToQuantum(pixel),exception);
    if (status == MagickFalse)
      {
        destination_image=DestroyImageList(destination_image);
        break;
      }
    channels++;
    if (channel_op == ExchangeChannelOp)
      {
        status=ChannelImage(destination_image,source_channel,channel_op,
          source_image,destination_channel,ClampToQuantum(pixel),exception);
        if (status == MagickFalse)
          {
            destination_image=DestroyImageList(destination_image);
            break;
          }
        channels++;
      }
    switch (channel_op)
    {
      case ExtractChannelOp:
      {
        channel_mask=(ChannelType) (channel_mask | (1 << destination_channel));
        destination_channel=(PixelChannel) (destination_channel+1);
        break;
      }
      default:
        break;
    }
    status=SetImageProgress(source_image,ChannelFxImageTag,p-expression,
      strlen(expression));
    if (status == MagickFalse)
      break;
  }
  SetPixelChannelMask(destination_image,channel_mask);
  if ((channel_op == ExtractChannelOp) && (channels == 1))
    (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
  status=SetImageStorageClass(destination_image,DirectClass,exception);
  if (status == MagickFalse)
    {
      destination_image=GetLastImageInList(destination_image);
      return((Image *) NULL);
    }
  return(GetFirstImageInList(destination_image));
}
Ejemplo n.º 2
0
WandExport MagickBooleanType CompareImagesCommand(ImageInfo *image_info,
  int argc,char **argv,char **metadata,ExceptionInfo *exception)
{
#define CompareEpsilon  (1.0e-06)
#define DefaultDissimilarityThreshold  0.31830988618379067154
#define DefaultSimilarityThreshold  (-1.0)
#define DestroyCompare() \
{ \
  if (similarity_image != (Image *) NULL) \
    similarity_image=DestroyImageList(similarity_image); \
  if (difference_image != (Image *) NULL) \
    difference_image=DestroyImageList(difference_image); \
  DestroyImageStack(); \
  for (i=0; i < (ssize_t) argc; i++) \
    argv[i]=DestroyString(argv[i]); \
  argv=(char **) RelinquishMagickMemory(argv); \
}
#define ThrowCompareException(asperity,tag,option) \
{ \
  if (exception->severity < (asperity)) \
    (void) ThrowMagickException(exception,GetMagickModule(),asperity,tag, \
      "`%s'",option); \
  DestroyCompare(); \
  return(MagickFalse); \
}
#define ThrowCompareInvalidArgumentException(option,argument) \
{ \
  (void) ThrowMagickException(exception,GetMagickModule(),OptionError, \
    "InvalidArgument","'%s': %s",option,argument); \
  DestroyCompare(); \
  return(MagickFalse); \
}

  char
    *filename,
    *option;

  const char
    *format;

  double
    dissimilarity_threshold,
    distortion,
    similarity_metric,
    similarity_threshold;

  Image
    *difference_image,
    *image,
    *reconstruct_image,
    *similarity_image;

  ImageStack
    image_stack[MaxImageStackDepth+1];

  MagickBooleanType
    fire,
    pend,
    respect_parenthesis,
    subimage_search;

  MagickStatusType
    status;

  MetricType
    metric;

  RectangleInfo
    offset;

  register ssize_t
    i;

  ssize_t
    j,
    k;

  /*
    Set defaults.
  */
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(exception != (ExceptionInfo *) NULL);
  if (argc == 2)
    {
      option=argv[1];
      if ((LocaleCompare("version",option+1) == 0) ||
          (LocaleCompare("-version",option+1) == 0))
        {
          ListMagickVersion(stdout);
          return(MagickFalse);
        }
    }
  if (argc < 3)
    return(CompareUsage());
  difference_image=NewImageList();
  similarity_image=NewImageList();
  dissimilarity_threshold=DefaultDissimilarityThreshold;
  similarity_threshold=DefaultSimilarityThreshold;
  distortion=0.0;
  format=(char *) NULL;
  j=1;
  k=0;
  metric=UndefinedErrorMetric;
  NewImageStack();
  option=(char *) NULL;
  pend=MagickFalse;
  reconstruct_image=NewImageList();
  respect_parenthesis=MagickFalse;
  status=MagickTrue;
  subimage_search=MagickFalse;
  /*
    Compare an image.
  */
  ReadCommandlLine(argc,&argv);
  status=ExpandFilenames(&argc,&argv);
  if (status == MagickFalse)
    ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
      GetExceptionMessage(errno));
  for (i=1; i < (ssize_t) (argc-1); i++)
  {
    option=argv[i];
    if (LocaleCompare(option,"(") == 0)
      {
        FireImageStack(MagickTrue,MagickTrue,pend);
        if (k == MaxImageStackDepth)
          ThrowCompareException(OptionError,"ParenthesisNestedTooDeeply",
            option);
        PushImageStack();
        continue;
      }
    if (LocaleCompare(option,")") == 0)
      {
        FireImageStack(MagickTrue,MagickTrue,MagickTrue);
        if (k == 0)
          ThrowCompareException(OptionError,"UnableToParseExpression",option);
        PopImageStack();
        continue;
      }
    if (IsCommandOption(option) == MagickFalse)
      {
        Image
          *images;

        /*
          Read input image.
        */
        FireImageStack(MagickFalse,MagickFalse,pend);
        filename=argv[i];
        if ((LocaleCompare(filename,"--") == 0) && (i < (ssize_t) (argc-1)))
          filename=argv[++i];
        images=ReadImages(image_info,filename,exception);
        status&=(images != (Image *) NULL) &&
          (exception->severity < ErrorException);
        if (images == (Image *) NULL)
          continue;
        AppendImageStack(images);
        continue;
      }
    pend=image != (Image *) NULL ? MagickTrue : MagickFalse;
    switch (*(option+1))
    {
      case 'a':
      {
        if (LocaleCompare("alpha",option+1) == 0)
          {
            ssize_t
              type;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            type=ParseCommandOption(MagickAlphaChannelOptions,MagickFalse,argv[i]);
            if (type < 0)
              ThrowCompareException(OptionError,"UnrecognizedAlphaChannelOption",
                argv[i]);
            break;
          }
        if (LocaleCompare("authenticate",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option);
      }
      case 'c':
      {
        if (LocaleCompare("cache",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("channel",option+1) == 0)
          {
            ssize_t
              channel;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            channel=ParseChannelOption(argv[i]);
            if (channel < 0)
              ThrowCompareException(OptionError,"UnrecognizedChannelType",
                argv[i]);
            (void) SetPixelChannelMask(image,(ChannelType) channel);
            break;
          }
        if (LocaleCompare("colorspace",option+1) == 0)
          {
            ssize_t
              colorspace;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            colorspace=ParseCommandOption(MagickColorspaceOptions,MagickFalse,
              argv[i]);
            if (colorspace < 0)
              ThrowCompareException(OptionError,"UnrecognizedColorspace",
                argv[i]);
            break;
          }
        if (LocaleCompare("compose",option+1) == 0)
          {
            ssize_t
              compose;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            compose=ParseCommandOption(MagickComposeOptions,MagickFalse,
              argv[i]);
            if (compose < 0)
              ThrowCompareException(OptionError,"UnrecognizedComposeOperator",
                argv[i]);
            break;
          }
        if (LocaleCompare("compress",option+1) == 0)
          {
            ssize_t
              compress;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            compress=ParseCommandOption(MagickCompressOptions,MagickFalse,
              argv[i]);
            if (compress < 0)
              ThrowCompareException(OptionError,"UnrecognizedImageCompression",
                argv[i]);
            break;
          }
        if (LocaleCompare("concurrent",option+1) == 0)
          break;
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'd':
      {
        if (LocaleCompare("debug",option+1) == 0)
          {
            LogEventType
              event_mask;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            event_mask=SetLogEventMask(argv[i]);
            if (event_mask == UndefinedEvents)
              ThrowCompareException(OptionError,"UnrecognizedEventType",
                argv[i]);
            break;
          }
        if (LocaleCompare("decipher",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        if (LocaleCompare("define",option+1) == 0)
          {
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (*option == '+')
              {
                const char
                  *define;

                define=GetImageOption(image_info,argv[i]);
                if (define == (const char *) NULL)
                  ThrowCompareException(OptionError,"NoSuchOption",argv[i]);
                break;
              }
            break;
          }
        if (LocaleCompare("density",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("depth",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("dissimilarity-threshold",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            if (*option == '+')
              dissimilarity_threshold=DefaultDissimilarityThreshold;
            else
              dissimilarity_threshold=StringToDouble(argv[i],(char **) NULL);
            break;
          }
        if (LocaleCompare("duration",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'e':
      {
        if (LocaleCompare("encipher",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        if (LocaleCompare("extract",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'f':
      {
        if (LocaleCompare("format",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            format=argv[i];
            break;
          }
        if (LocaleCompare("fuzz",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'h':
      {
        if ((LocaleCompare("help",option+1) == 0) ||
            (LocaleCompare("-help",option+1) == 0))
          return(CompareUsage());
        if (LocaleCompare("highlight-color",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'i':
      {
        if (LocaleCompare("identify",option+1) == 0)
          break;
        if (LocaleCompare("interlace",option+1) == 0)
          {
            ssize_t
              interlace;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            interlace=ParseCommandOption(MagickInterlaceOptions,MagickFalse,
              argv[i]);
            if (interlace < 0)
              ThrowCompareException(OptionError,"UnrecognizedInterlaceType",
                argv[i]);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'l':
      {
        if (LocaleCompare("limit",option+1) == 0)
          {
            char
              *p;

            double
              value;

            ssize_t
              resource;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            resource=ParseCommandOption(MagickResourceOptions,MagickFalse,
              argv[i]);
            if (resource < 0)
              ThrowCompareException(OptionError,"UnrecognizedResourceType",
                argv[i]);
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            value=StringToDouble(argv[i],&p);
            (void) value;
            if ((p == argv[i]) && (LocaleCompare("unlimited",argv[i]) != 0))
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("list",option+1) == 0)
          {
            ssize_t
              list;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            list=ParseCommandOption(MagickListOptions,MagickFalse,argv[i]);
            if (list < 0)
              ThrowCompareException(OptionError,"UnrecognizedListType",argv[i]);
            status=MogrifyImageInfo(image_info,(int) (i-j+1),(const char **)
              argv+j,exception);
            DestroyCompare();
            return(status == 0 ? MagickTrue : MagickFalse);
          }
        if (LocaleCompare("log",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if ((i == (ssize_t) argc) || (strchr(argv[i],'%') == (char *) NULL))
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        if (LocaleCompare("lowlight-color",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'm':
      {
        if (LocaleCompare("matte",option+1) == 0)
          break;
        if (LocaleCompare("metric",option+1) == 0)
          {
            ssize_t
              type;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            type=ParseCommandOption(MagickMetricOptions,MagickTrue,argv[i]);
            if (type < 0)
              ThrowCompareException(OptionError,"UnrecognizedMetricType",
                argv[i]);
            metric=(MetricType) type;
            break;
          }
        if (LocaleCompare("monitor",option+1) == 0)
          break;
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'p':
      {
        if (LocaleCompare("profile",option+1) == 0)
          {
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'q':
      {
        if (LocaleCompare("quality",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("quantize",option+1) == 0)
          {
            ssize_t
              colorspace;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            colorspace=ParseCommandOption(MagickColorspaceOptions,
              MagickFalse,argv[i]);
            if (colorspace < 0)
              ThrowCompareException(OptionError,"UnrecognizedColorspace",
                argv[i]);
            break;
          }
        if (LocaleCompare("quiet",option+1) == 0)
          break;
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'r':
      {
        if (LocaleCompare("regard-warnings",option+1) == 0)
          break;
        if (LocaleNCompare("respect-parentheses",option+1,17) == 0)
          {
            respect_parenthesis=(*option == '-') ? MagickTrue : MagickFalse;
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 's':
      {
        if (LocaleCompare("sampling-factor",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("seed",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("set",option+1) == 0)
          {
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        if (LocaleCompare("similarity-threshold",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            if (*option == '+')
              similarity_threshold=DefaultSimilarityThreshold;
            else
              similarity_threshold=StringToDouble(argv[i],(char **) NULL);
            break;
          }
        if (LocaleCompare("size",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            if (IsGeometry(argv[i]) == MagickFalse)
              ThrowCompareInvalidArgumentException(option,argv[i]);
            break;
          }
        if (LocaleCompare("subimage-search",option+1) == 0)
          {
            if (*option == '+')
              {
                subimage_search=MagickFalse;
                break;
              }
            subimage_search=MagickTrue;
            break;
          }
        if (LocaleCompare("synchronize",option+1) == 0)
          break;
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 't':
      {
        if (LocaleCompare("taint",option+1) == 0)
          break;
        if (LocaleCompare("transparent-color",option+1) == 0)
          {
            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            break;
          }
        if (LocaleCompare("type",option+1) == 0)
          {
            ssize_t
              type;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            type=ParseCommandOption(MagickTypeOptions,MagickFalse,argv[i]);
            if (type < 0)
              ThrowCompareException(OptionError,"UnrecognizedImageType",
                argv[i]);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case 'v':
      {
        if (LocaleCompare("verbose",option+1) == 0)
          break;
        if ((LocaleCompare("version",option+1) == 0) ||
            (LocaleCompare("-version",option+1) == 0))
          {
            ListMagickVersion(stdout);
            break;
          }
        if (LocaleCompare("virtual-pixel",option+1) == 0)
          {
            ssize_t
              method;

            if (*option == '+')
              break;
            i++;
            if (i == (ssize_t) argc)
              ThrowCompareException(OptionError,"MissingArgument",option);
            method=ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,
              argv[i]);
            if (method < 0)
              ThrowCompareException(OptionError,
                "UnrecognizedVirtualPixelMethod",argv[i]);
            break;
          }
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
      }
      case '?':
        break;
      default:
        ThrowCompareException(OptionError,"UnrecognizedOption",option)
    }
    fire=(GetCommandOptionFlags(MagickCommandOptions,MagickFalse,option) &
      FireOptionFlag) == 0 ?  MagickFalse : MagickTrue;
    if (fire != MagickFalse)
      FireImageStack(MagickTrue,MagickTrue,MagickTrue);
  }
  if (k != 0)
    ThrowCompareException(OptionError,"UnbalancedParenthesis",argv[i]);
  if (i-- != (ssize_t) (argc-1))
    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  FinalizeImageSettings(image_info,image,MagickTrue);
  if ((image == (Image *) NULL) || (GetImageListLength(image) < 2))
    ThrowCompareException(OptionError,"MissingAnImageFilename",argv[i]);
  image=GetImageFromList(image,0);
  reconstruct_image=GetImageFromList(image,1);
  offset.x=0;
  offset.y=0;
  if (subimage_search != MagickFalse)
    {
      similarity_image=SimilarityImage(image,reconstruct_image,metric,
        similarity_threshold,&offset,&similarity_metric,exception);
      if (similarity_metric > dissimilarity_threshold)
        ThrowCompareException(ImageError,"ImagesTooDissimilar",image->filename);
    }
  if ((reconstruct_image->columns == image->columns) &&
       (reconstruct_image->rows == image->rows))
    difference_image=CompareImages(image,reconstruct_image,metric,&distortion,
      exception);
  else
    if (similarity_image == (Image *) NULL)
      {
        if (metric == PerceptualHashErrorMetric)
          difference_image=CompareImages(image,reconstruct_image,metric,
            &distortion,exception);
        else
          ThrowCompareException(OptionError,"ImageWidthsOrHeightsDiffer",
            image->filename);
      }
    else
      {
        Image
          *composite_image;

        /*
          Determine if reconstructed image is a subimage of the image.
        */
        composite_image=CloneImage(image,0,0,MagickTrue,exception);
        if (composite_image == (Image *) NULL)
          difference_image=CompareImages(image,reconstruct_image,metric,
            &distortion,exception);
        else
          {
            Image
              *distort_image;

            RectangleInfo
              page;

            (void) CompositeImage(composite_image,reconstruct_image,
              CopyCompositeOp,MagickTrue,offset.x,offset.y,exception);
            difference_image=CompareImages(image,composite_image,metric,
              &distortion,exception);
            if (difference_image != (Image *) NULL)
              {
                difference_image->page.x=offset.x;
                difference_image->page.y=offset.y;
              }
            composite_image=DestroyImage(composite_image);
            page.width=reconstruct_image->columns;
            page.height=reconstruct_image->rows;
            page.x=offset.x;
            page.y=offset.y;
            distort_image=CropImage(image,&page,exception);
            if (distort_image != (Image *) NULL)
              {
                Image
                  *sans_image;

                sans_image=CompareImages(distort_image,reconstruct_image,metric,
                  &distortion,exception);
                distort_image=DestroyImage(distort_image);
                if (sans_image != (Image *) NULL)
                  sans_image=DestroyImage(sans_image);
              }
          }
        if (difference_image != (Image *) NULL)
          {
            AppendImageToList(&difference_image,similarity_image);
            similarity_image=(Image *) NULL;
          }
      }
  if (difference_image == (Image *) NULL)
    status=0;
  else
    {
      if (image_info->verbose != MagickFalse)
        (void) SetImageColorMetric(image,reconstruct_image,exception);
      if (*difference_image->magick == '\0')
        (void) CopyMagickString(difference_image->magick,image->magick,
          MagickPathExtent);
      if (image_info->verbose == MagickFalse)
        {
          switch (metric)
          {
            case FuzzErrorMetric:
            case MeanAbsoluteErrorMetric:
            case MeanSquaredErrorMetric:
            case PeakAbsoluteErrorMetric:
            case RootMeanSquaredErrorMetric:
            {
              (void) FormatLocaleFile(stderr,"%g (%g)",QuantumRange*distortion,
                (double) distortion);
              break;
            }
            case AbsoluteErrorMetric:
            case NormalizedCrossCorrelationErrorMetric:
            case PeakSignalToNoiseRatioErrorMetric:
            case PerceptualHashErrorMetric:
            {
              (void) FormatLocaleFile(stderr,"%g",distortion);
              break;
            }
            case MeanErrorPerPixelErrorMetric:
            {
              (void) FormatLocaleFile(stderr,"%g (%g, %g)",distortion,
                image->error.normalized_mean_error,
                image->error.normalized_maximum_error);
              break;
            }
            case UndefinedErrorMetric:
              break;
          }
          if (subimage_search != MagickFalse)
            (void) FormatLocaleFile(stderr," @ %.20g,%.20g",(double)
              difference_image->page.x,(double) difference_image->page.y);
        }
      else
        {
          double
            *channel_distortion;

          channel_distortion=GetImageDistortions(image,reconstruct_image,
            metric,exception);
          (void) FormatLocaleFile(stderr,"Image: %s\n",image->filename);
          if ((reconstruct_image->columns != image->columns) ||
              (reconstruct_image->rows != image->rows))
            (void) FormatLocaleFile(stderr,"Offset: %.20g,%.20g\n",(double)
              difference_image->page.x,(double) difference_image->page.y);
          (void) FormatLocaleFile(stderr,"  Channel distortion: %s\n",
            CommandOptionToMnemonic(MagickMetricOptions,(ssize_t) metric));
          switch (metric)
          {
            case FuzzErrorMetric:
            case MeanAbsoluteErrorMetric:
            case MeanSquaredErrorMetric:
            case PeakAbsoluteErrorMetric:
            case RootMeanSquaredErrorMetric:
            {
              switch (image->colorspace)
              {
                case RGBColorspace:
                default:
                {
                  (void) FormatLocaleFile(stderr,"    red: %g (%g)\n",
                    QuantumRange*channel_distortion[RedPixelChannel],
                    channel_distortion[RedPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    green: %g (%g)\n",
                    QuantumRange*channel_distortion[GreenPixelChannel],
                    channel_distortion[GreenPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    blue: %g (%g)\n",
                    QuantumRange*channel_distortion[BluePixelChannel],
                    channel_distortion[BluePixelChannel]);
                  if (image->alpha_trait != UndefinedPixelTrait)
                    (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
                      QuantumRange*channel_distortion[AlphaPixelChannel],
                      channel_distortion[AlphaPixelChannel]);
                  break;
                }
                case CMYKColorspace:
                {
                  (void) FormatLocaleFile(stderr,"    cyan: %g (%g)\n",
                    QuantumRange*channel_distortion[CyanPixelChannel],
                    channel_distortion[CyanPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    magenta: %g (%g)\n",
                    QuantumRange*channel_distortion[MagentaPixelChannel],
                    channel_distortion[MagentaPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    yellow: %g (%g)\n",
                    QuantumRange*channel_distortion[YellowPixelChannel],
                    channel_distortion[YellowPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    black: %g (%g)\n",
                    QuantumRange*channel_distortion[BlackPixelChannel],
                    channel_distortion[BlackPixelChannel]);
                  if (image->alpha_trait != UndefinedPixelTrait)
                    (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
                      QuantumRange*channel_distortion[AlphaPixelChannel],
                      channel_distortion[AlphaPixelChannel]);
                  break;
                }
                case GRAYColorspace:
                {
                  (void) FormatLocaleFile(stderr,"    gray: %g (%g)\n",
                    QuantumRange*channel_distortion[GrayPixelChannel],
                    channel_distortion[GrayPixelChannel]);
                  if (image->alpha_trait != UndefinedPixelTrait)
                    (void) FormatLocaleFile(stderr,"    alpha: %g (%g)\n",
                      QuantumRange*channel_distortion[AlphaPixelChannel],
                      channel_distortion[AlphaPixelChannel]);
                  break;
                }
              }
              (void) FormatLocaleFile(stderr,"    all: %g (%g)\n",
                QuantumRange*channel_distortion[MaxPixelChannels],
                channel_distortion[MaxPixelChannels]);
              break;
            }
            case AbsoluteErrorMetric:
            case NormalizedCrossCorrelationErrorMetric:
            case PeakSignalToNoiseRatioErrorMetric:
            case PerceptualHashErrorMetric:
            {
              switch (image->colorspace)
              {
                case RGBColorspace:
                default:
                {
                  (void) FormatLocaleFile(stderr,"    red: %g\n",
                    channel_distortion[RedPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    green: %g\n",
                    channel_distortion[GreenPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    blue: %g\n",
                    channel_distortion[BluePixelChannel]);
                  if (image->alpha_trait != UndefinedPixelTrait)
                    (void) FormatLocaleFile(stderr,"    alpha: %g\n",
                      channel_distortion[AlphaPixelChannel]);
                  break;
                }
                case CMYKColorspace:
                {
                  (void) FormatLocaleFile(stderr,"    cyan: %g\n",
                    channel_distortion[CyanPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    magenta: %g\n",
                    channel_distortion[MagentaPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    yellow: %g\n",
                    channel_distortion[YellowPixelChannel]);
                  (void) FormatLocaleFile(stderr,"    black: %g\n",
                    channel_distortion[BlackPixelChannel]);
                  if (image->alpha_trait != UndefinedPixelTrait)
                    (void) FormatLocaleFile(stderr,"    alpha: %g\n",
                      channel_distortion[AlphaPixelChannel]);
                  break;
                }
                case GRAYColorspace:
                {
                  (void) FormatLocaleFile(stderr,"    gray: %g\n",
                    channel_distortion[GrayPixelChannel]);
                  if (image->alpha_trait != UndefinedPixelTrait)
                    (void) FormatLocaleFile(stderr,"    alpha: %g\n",
                      channel_distortion[AlphaPixelChannel]);
                  break;
                }
              }
              (void) FormatLocaleFile(stderr,"    all: %g\n",
                channel_distortion[MaxPixelChannels]);
              break;
            }
            case MeanErrorPerPixelErrorMetric:
            {
              (void) FormatLocaleFile(stderr,"    %g (%g, %g)\n",
                channel_distortion[MaxPixelChannels],
                image->error.normalized_mean_error,
                image->error.normalized_maximum_error);
              break;
            }
            case UndefinedErrorMetric:
              break;
          }
          channel_distortion=(double *) RelinquishMagickMemory(
            channel_distortion);
          if (subimage_search != MagickFalse)
            (void) FormatLocaleFile(stderr,"   Offset: %.20g,%.20g\n",(double)
              difference_image->page.x,(double) difference_image->page.y);
        }
      status&=WriteImages(image_info,difference_image,argv[argc-1],exception);
      if ((metadata != (char **) NULL) && (format != (char *) NULL))
        {
          char
            *text;

          text=InterpretImageProperties(image_info,difference_image,format,
            exception);
          if (text == (char *) NULL)
            ThrowCompareException(ResourceLimitError,"MemoryAllocationFailed",
              GetExceptionMessage(errno));
          (void) ConcatenateString(&(*metadata),text);
          text=DestroyString(text);
        }
      difference_image=DestroyImageList(difference_image);
    }
  DestroyCompare();
  if ((metric == NormalizedCrossCorrelationErrorMetric) ||
      (metric == UndefinedErrorMetric))
    {
      if (fabs(distortion-1.0) > CompareEpsilon)
        (void) SetImageOption(image_info,"compare:dissimilar","true");
    }
  else
    if (fabs(distortion) > CompareEpsilon)
      (void) SetImageOption(image_info,"compare:dissimilar","true");
  return(status != 0 ? MagickTrue : MagickFalse);
}
Ejemplo n.º 3
0
MagickExport Image *MontageImageList(const ImageInfo *image_info,
  const MontageInfo *montage_info,const Image *images,ExceptionInfo *exception)
{
#define MontageImageTag  "Montage/Image"
#define TileImageTag  "Tile/Image"

  char
    tile_geometry[MagickPathExtent],
    *title;

  const char
    *value;

  DrawInfo
    *draw_info;

  FrameInfo
    frame_info;

  Image
    *image,
    **image_list,
    **master_list,
    *montage,
    *texture,
    *tile_image,
    *thumbnail;

  ImageInfo
    *clone_info;

  MagickBooleanType
    concatenate,
    proceed,
    status;

  MagickOffsetType
    tiles;

  MagickProgressMonitor
    progress_monitor;

  MagickStatusType
    flags;

  register ssize_t
    i;

  RectangleInfo
    bounds,
    geometry,
    extract_info;

  size_t
    border_width,
    extent,
    height,
    images_per_page,
    max_height,
    number_images,
    number_lines,
    sans,
    tiles_per_column,
    tiles_per_page,
    tiles_per_row,
    title_offset,
    total_tiles,
    width;

  ssize_t
    bevel_width,
    tile,
    x,
    x_offset,
    y,
    y_offset;

  TypeMetric
    metrics;

  /*
    Create image tiles.
  */
  assert(images != (Image *) NULL);
  assert(images->signature == MagickCoreSignature);
  if (images->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
  assert(montage_info != (MontageInfo *) NULL);
  assert(montage_info->signature == MagickCoreSignature);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  number_images=GetImageListLength(images);
  master_list=ImageListToArray(images,exception);
  image_list=master_list;
  image=image_list[0];
  if (master_list == (Image **) NULL)
    ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
  thumbnail=NewImageList();
  for (i=0; i < (ssize_t) number_images; i++)
  {
    image=CloneImage(image_list[i],0,0,MagickTrue,exception);
    if (image == (Image *) NULL)
      break;
    (void) ParseAbsoluteGeometry("0x0+0+0",&image->page);
    progress_monitor=SetImageProgressMonitor(image,(MagickProgressMonitor) NULL,
      image->client_data);
    flags=ParseRegionGeometry(image,montage_info->geometry,&geometry,exception);
    thumbnail=ThumbnailImage(image,geometry.width,geometry.height,exception);
    if (thumbnail == (Image *) NULL)
      break;
    image_list[i]=thumbnail;
    (void) SetImageProgressMonitor(image,progress_monitor,image->client_data);
    proceed=SetImageProgress(image,TileImageTag,(MagickOffsetType) i,
      number_images);
    if (proceed == MagickFalse)
      break;
    image=DestroyImage(image);
  }
  if (i < (ssize_t) number_images)
    {
      if (thumbnail == (Image *) NULL)
        i--;
      for (tile=0; (ssize_t) tile <= i; tile++)
        if (image_list[tile] != (Image *) NULL)
          image_list[tile]=DestroyImage(image_list[tile]);
      master_list=(Image **) RelinquishMagickMemory(master_list);
      return((Image *) NULL);
    }
  /*
    Sort image list by increasing tile number.
  */
  for (i=0; i < (ssize_t) number_images; i++)
    if (image_list[i]->scene == 0)
      break;
  if (i == (ssize_t) number_images)
    qsort((void *) image_list,(size_t) number_images,sizeof(*image_list),
      SceneCompare);
  /*
    Determine tiles per row and column.
  */
  tiles_per_column=(size_t) sqrt((double) number_images);
  tiles_per_row=(size_t) ceil((double) number_images/tiles_per_column);
  x_offset=0;
  y_offset=0;
  if (montage_info->tile != (char *) NULL)
    GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
      &tiles_per_column,&tiles_per_row);
  /*
    Determine tile sizes.
  */
  concatenate=MagickFalse;
  SetGeometry(image_list[0],&extract_info);
  extract_info.x=(ssize_t) montage_info->border_width;
  extract_info.y=(ssize_t) montage_info->border_width;
  if (montage_info->geometry != (char *) NULL)
    {
      /*
        Initialize tile geometry.
      */
      flags=GetGeometry(montage_info->geometry,&extract_info.x,&extract_info.y,
        &extract_info.width,&extract_info.height);
      concatenate=((flags & RhoValue) == 0) && ((flags & SigmaValue) == 0) ?
        MagickTrue : MagickFalse;
    }
  border_width=montage_info->border_width;
  bevel_width=0;
  (void) ResetMagickMemory(&frame_info,0,sizeof(frame_info));
  if (montage_info->frame != (char *) NULL)
    {
      char
        absolute_geometry[MagickPathExtent];

      frame_info.width=extract_info.width;
      frame_info.height=extract_info.height;
      (void) FormatLocaleString(absolute_geometry,MagickPathExtent,"%s!",
        montage_info->frame);
      flags=ParseMetaGeometry(absolute_geometry,&frame_info.outer_bevel,
        &frame_info.inner_bevel,&frame_info.width,&frame_info.height);
      if ((flags & HeightValue) == 0)
        frame_info.height=frame_info.width;
      if ((flags & XiValue) == 0)
        frame_info.outer_bevel=(ssize_t) frame_info.width/2-1;
      if ((flags & PsiValue) == 0)
        frame_info.inner_bevel=frame_info.outer_bevel;
      frame_info.x=(ssize_t) frame_info.width;
      frame_info.y=(ssize_t) frame_info.height;
      bevel_width=(ssize_t) MagickMax(frame_info.inner_bevel,
        frame_info.outer_bevel);
      border_width=(size_t) MagickMax((ssize_t) frame_info.width,
        (ssize_t) frame_info.height);
    }
  for (i=0; i < (ssize_t) number_images; i++)
  {
    if (image_list[i]->columns > extract_info.width)
      extract_info.width=image_list[i]->columns;
    if (image_list[i]->rows > extract_info.height)
      extract_info.height=image_list[i]->rows;
  }
  /*
    Initialize draw attributes.
  */
  clone_info=CloneImageInfo(image_info);
  clone_info->background_color=montage_info->background_color;
  clone_info->border_color=montage_info->border_color;
  draw_info=CloneDrawInfo(clone_info,(DrawInfo *) NULL);
  if (montage_info->font != (char *) NULL)
    (void) CloneString(&draw_info->font,montage_info->font);
  if (montage_info->pointsize != 0.0)
    draw_info->pointsize=montage_info->pointsize;
  draw_info->gravity=CenterGravity;
  draw_info->stroke=montage_info->stroke;
  draw_info->fill=montage_info->fill;
  draw_info->text=AcquireString("");
  (void) GetTypeMetrics(image_list[0],draw_info,&metrics,exception);
  texture=NewImageList();
  if (montage_info->texture != (char *) NULL)
    {
      (void) CopyMagickString(clone_info->filename,montage_info->texture,
        MagickPathExtent);
      texture=ReadImage(clone_info,exception);
    }
  /*
    Determine the number of lines in an next label.
  */
  title=InterpretImageProperties(clone_info,image_list[0],montage_info->title,
    exception);
  title_offset=0;
  if (montage_info->title != (char *) NULL)
    title_offset=(size_t) (2*(metrics.ascent-metrics.descent)*
      MultilineCensus(title)+2*extract_info.y);
  number_lines=0;
  for (i=0; i < (ssize_t) number_images; i++)
  {
    value=GetImageProperty(image_list[i],"label",exception);
    if (value == (const char *) NULL)
      continue;
    if (MultilineCensus(value) > number_lines)
      number_lines=MultilineCensus(value);
  }
  /*
    Allocate next structure.
  */
  tile_image=AcquireImage((ImageInfo *) NULL,exception);
  montage=AcquireImage(clone_info,exception);
  montage->background_color=montage_info->background_color;
  montage->scene=0;
  images_per_page=(number_images-1)/(tiles_per_row*tiles_per_column)+1;
  tiles=0;
  total_tiles=(size_t) number_images;
  for (i=0; i < (ssize_t) images_per_page; i++)
  {
    /*
      Determine bounding box.
    */
    tiles_per_page=tiles_per_row*tiles_per_column;
    x_offset=0;
    y_offset=0;
    if (montage_info->tile != (char *) NULL)
      GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
        &sans,&sans);
    tiles_per_page=tiles_per_row*tiles_per_column;
    y_offset+=(ssize_t) title_offset;
    max_height=0;
    bounds.width=0;
    bounds.height=0;
    width=0;
    for (tile=0; tile < (ssize_t) tiles_per_page; tile++)
    {
      if (tile < (ssize_t) number_images)
        {
          width=concatenate != MagickFalse ? image_list[tile]->columns :
            extract_info.width;
          if (image_list[tile]->rows > max_height)
            max_height=image_list[tile]->rows;
        }
      x_offset+=(ssize_t) (width+2*(extract_info.x+border_width));
      if (x_offset > (ssize_t) bounds.width)
        bounds.width=(size_t) x_offset;
      if (((tile+1) == (ssize_t) tiles_per_page) ||
          (((tile+1) % tiles_per_row) == 0))
        {
          x_offset=0;
          if (montage_info->tile != (char *) NULL)
            GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y,
              &sans,&sans);
          height=concatenate != MagickFalse ? max_height : extract_info.height;
          y_offset+=(ssize_t) (height+(extract_info.y+(ssize_t) border_width)*2+
            (metrics.ascent-metrics.descent+4)*number_lines+
            (montage_info->shadow != MagickFalse ? 4 : 0));
          if (y_offset > (ssize_t) bounds.height)
            bounds.height=(size_t) y_offset;
          max_height=0;
        }
    }
    if (montage_info->shadow != MagickFalse)
      bounds.width+=4;
    /*
      Initialize montage image.
    */
    (void) CopyMagickString(montage->filename,montage_info->filename,
      MagickPathExtent);
    montage->columns=(size_t) MagickMax((ssize_t) bounds.width,1);
    montage->rows=(size_t) MagickMax((ssize_t) bounds.height,1);
    (void) SetImageBackgroundColor(montage,exception);
    /*
      Set montage geometry.
    */
    montage->montage=AcquireString((char *) NULL);
    tile=0;
    extent=1;
    while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images))
    {
      extent+=strlen(image_list[tile]->filename)+1;
      tile++;
    }
    montage->directory=(char *) AcquireQuantumMemory(extent,
      sizeof(*montage->directory));
    if ((montage->montage == (char *) NULL) ||
        (montage->directory == (char *) NULL))
      {
        if (montage->montage != (char *) NULL)
          montage->montage=(char *) RelinquishMagickMemory(montage->montage);
        if (montage->directory != (char *) NULL)
          montage->directory=(char *) RelinquishMagickMemory(
            montage->directory);
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      }
    x_offset=0;
    y_offset=0;
    if (montage_info->tile != (char *) NULL)
      GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
        &sans,&sans);
    y_offset+=(ssize_t) title_offset;
    (void) FormatLocaleString(montage->montage,MagickPathExtent,
      "%.20gx%.20g%+.20g%+.20g",(double) (extract_info.width+
      (extract_info.x+border_width)*2),(double) (extract_info.height+
      (extract_info.y+border_width)*2+(double) ((metrics.ascent-
      metrics.descent+4)*number_lines+(montage_info->shadow != MagickFalse ? 4 :
      0))),(double) x_offset,(double) y_offset);
    *montage->directory='\0';
    tile=0;
    while (tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images))
    {
      (void) ConcatenateMagickString(montage->directory,
        image_list[tile]->filename,extent);
      (void) ConcatenateMagickString(montage->directory,"\n",extent);
      tile++;
    }
    progress_monitor=SetImageProgressMonitor(montage,(MagickProgressMonitor)
      NULL,montage->client_data);
    if (texture != (Image *) NULL)
      (void) TextureImage(montage,texture,exception);
    if (montage_info->title != (char *) NULL)
      {
        DrawInfo
          *draw_clone_info;

        TypeMetric
          tile_metrics;

        /*
          Annotate composite image with title.
        */
        draw_clone_info=CloneDrawInfo(image_info,draw_info);
        draw_clone_info->gravity=CenterGravity;
        draw_clone_info->pointsize*=2.0;
        (void) GetTypeMetrics(image_list[0],draw_clone_info,&tile_metrics,
          exception);
        (void) FormatLocaleString(tile_geometry,MagickPathExtent,
          "%.20gx%.20g%+.20g%+.20g",(double) montage->columns,(double)
          (tile_metrics.ascent-tile_metrics.descent),0.0,
          (double) extract_info.y+4);
        (void) CloneString(&draw_clone_info->geometry,tile_geometry);
        (void) CloneString(&draw_clone_info->text,title);
        (void) AnnotateImage(montage,draw_clone_info,exception);
        draw_clone_info=DestroyDrawInfo(draw_clone_info);
      }
    (void) SetImageProgressMonitor(montage,progress_monitor,
      montage->client_data);
    /*
      Copy tile to the composite.
    */
    x_offset=0;
    y_offset=0;
    if (montage_info->tile != (char *) NULL)
      GetMontageGeometry(montage_info->tile,number_images,&x_offset,&y_offset,
        &sans,&sans);
    x_offset+=extract_info.x;
    y_offset+=(ssize_t) title_offset+extract_info.y;
    max_height=0;
    status=MagickTrue;
    for (tile=0; tile < MagickMin((ssize_t) tiles_per_page,(ssize_t) number_images); tile++)
    {
      /*
        Copy this tile to the composite.
      */
      image=CloneImage(image_list[tile],0,0,MagickTrue,exception);
      if (image == (Image *) NULL)
        ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
      progress_monitor=SetImageProgressMonitor(image,
        (MagickProgressMonitor) NULL,image->client_data);
      width=concatenate != MagickFalse ? image->columns : extract_info.width;
      if (image->rows > max_height)
        max_height=image->rows;
      height=concatenate != MagickFalse ? max_height : extract_info.height;
      if (border_width != 0)
        {
          Image
            *border_image;

          RectangleInfo
            border_info;

          /*
            Put a border around the image.
          */
          border_info.width=border_width;
          border_info.height=border_width;
          if (montage_info->frame != (char *) NULL)
            {
              border_info.width=(width-image->columns+1)/2;
              border_info.height=(height-image->rows+1)/2;
            }
          border_image=BorderImage(image,&border_info,image->compose,exception);
          if (border_image != (Image *) NULL)
            {
              image=DestroyImage(image);
              image=border_image;
            }
          if ((montage_info->frame != (char *) NULL) &&
              (image->compose == DstOutCompositeOp))
            {
              (void) SetPixelChannelMask(image,AlphaChannel);
              (void) NegateImage(image,MagickFalse,exception);
              (void) SetPixelChannelMask(image,DefaultChannels);
            }
        }
      /*
        Gravitate as specified by the tile gravity.
      */
      tile_image->columns=width;
      tile_image->rows=height;
      tile_image->gravity=montage_info->gravity;
      if (image->gravity != UndefinedGravity)
        tile_image->gravity=image->gravity;
      (void) FormatLocaleString(tile_geometry,MagickPathExtent,
        "%.20gx%.20g+0+0",(double) image->columns,(double) image->rows);
      flags=ParseGravityGeometry(tile_image,tile_geometry,&geometry,exception);
      x=(ssize_t) (geometry.x+border_width);
      y=(ssize_t) (geometry.y+border_width);
      if ((montage_info->frame != (char *) NULL) && (bevel_width > 0))
        {
          FrameInfo
            frame_clone;

          Image
            *frame_image;

          /*
            Put an ornamental border around this tile.
          */
          frame_clone=frame_info;
          frame_clone.width=width+2*frame_info.width;
          frame_clone.height=height+2*frame_info.height;
          value=GetImageProperty(image,"label",exception);
          if (value != (const char *) NULL)
            frame_clone.height+=(size_t) ((metrics.ascent-metrics.descent+4)*
              MultilineCensus(value));
          frame_image=FrameImage(image,&frame_clone,image->compose,exception);
          if (frame_image != (Image *) NULL)
            {
              image=DestroyImage(image);
              image=frame_image;
            }
          x=0;
          y=0;
        }
      if (LocaleCompare(image->magick,"NULL") != 0)
        {
          /*
            Composite background with tile.
          */
          if (montage_info->shadow != MagickFalse)
            {
              Image
                *shadow_image;

              /*
                Shadow image.
              */
              (void) QueryColorCompliance("#0000",AllCompliance,
                &image->background_color,exception);
              shadow_image=ShadowImage(image,80.0,2.0,5,5,exception);
              if (shadow_image != (Image *) NULL)
                {
                  (void) CompositeImage(shadow_image,image,OverCompositeOp,
                    MagickTrue,0,0,exception);
                  image=DestroyImage(image);
                  image=shadow_image;
                }
          }
          (void) CompositeImage(montage,image,image->compose,MagickTrue,
            x_offset+x,y_offset+y,exception);
          value=GetImageProperty(image,"label",exception);
          if (value != (const char *) NULL)
            {
              /*
                Annotate composite tile with label.
              */
              (void) FormatLocaleString(tile_geometry,MagickPathExtent,
                "%.20gx%.20g%+.20g%+.20g",(double) ((montage_info->frame ?
                image->columns : width)-2*border_width),(double)
                (metrics.ascent-metrics.descent+4)*MultilineCensus(value),
                (double) (x_offset+border_width),(double)
                ((montage_info->frame ? y_offset+height+border_width+4 :
                y_offset+extract_info.height+border_width+
                (montage_info->shadow != MagickFalse ? 4 : 0))+bevel_width));
              (void) CloneString(&draw_info->geometry,tile_geometry);
              (void) CloneString(&draw_info->text,value);
              (void) AnnotateImage(montage,draw_info,exception);
            }
        }
      x_offset+=(ssize_t) (width+2*(extract_info.x+border_width));
      if (((tile+1) == (ssize_t) tiles_per_page) ||
          (((tile+1) % tiles_per_row) == 0))
        {
          x_offset=extract_info.x;
          y_offset+=(ssize_t) (height+(extract_info.y+border_width)*2+
            (metrics.ascent-metrics.descent+4)*number_lines+
            (montage_info->shadow != MagickFalse ? 4 : 0));
          max_height=0;
        }
      if (images->progress_monitor != (MagickProgressMonitor) NULL)
        {
          proceed=SetImageProgress(image,MontageImageTag,tiles,total_tiles);
          if (proceed == MagickFalse)
            status=MagickFalse;
        }
      image_list[tile]=DestroyImage(image_list[tile]);
      image=DestroyImage(image);
      tiles++;
    }
    (void) status;
    if ((i+1) < (ssize_t) images_per_page)
      {
        /*
          Allocate next image structure.
        */
        AcquireNextImage(clone_info,montage,exception);
        if (GetNextImageInList(montage) == (Image *) NULL)
          {
            montage=DestroyImageList(montage);
            return((Image *) NULL);
          }
        montage=GetNextImageInList(montage);
        montage->background_color=montage_info->background_color;
        image_list+=tiles_per_page;
        number_images-=tiles_per_page;
      }
  }
  tile_image=DestroyImage(tile_image);
  if (texture != (Image *) NULL)
    texture=DestroyImage(texture);
  title=DestroyString(title);
  master_list=(Image **) RelinquishMagickMemory(master_list);
  draw_info=DestroyDrawInfo(draw_info);
  clone_info=DestroyImageInfo(clone_info);
  return(GetFirstImageInList(montage));
}
Ejemplo n.º 4
0
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
  const AlphaChannelOption alpha_type,ExceptionInfo *exception)
{
  CacheView
    *image_view;

  MagickBooleanType
    status;

  ssize_t
    y;

  assert(image != (Image *) NULL);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  assert(image->signature == MagickCoreSignature);
  status=MagickTrue;
  switch (alpha_type)
  {
    case ActivateAlphaChannel:
    {
      image->alpha_trait=BlendPixelTrait;
      break;
    }
    case AssociateAlphaChannel:
    {
      /*
        Associate alpha.
      */
      status=SetImageStorageClass(image,DirectClass,exception);
      if (status == MagickFalse)
        break;
      image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
      #pragma omp parallel for schedule(static,4) shared(status) \
        magick_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register Quantum
          *magick_restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (Quantum *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          double
            gamma;
  
          register ssize_t
            i;
  
          if (GetPixelReadMask(image,q) == 0)
            {
              q+=GetPixelChannels(image);
              continue;
            }
          gamma=QuantumScale*GetPixelAlpha(image,q);
          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
          {
            PixelChannel channel=GetPixelChannelChannel(image,i);
            PixelTrait traits=GetPixelChannelTraits(image,channel);
            if (channel == AlphaPixelChannel)
              continue;
            if ((traits & UpdatePixelTrait) == 0)
              continue;
            q[i]=ClampToQuantum(gamma*q[i]);
          }
          q+=GetPixelChannels(image);
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
      image->alpha_trait=CopyPixelTrait;
      return(status);
    }
    case BackgroundAlphaChannel:
    {
      /*
        Set transparent pixels to background color.
      */
      if (image->alpha_trait == UndefinedPixelTrait)
        break;
      status=SetImageStorageClass(image,DirectClass,exception);
      if (status == MagickFalse)
        break;
      image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
      #pragma omp parallel for schedule(static,4) shared(status) \
        magick_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register Quantum
          *magick_restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (Quantum *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          if (GetPixelAlpha(image,q) == TransparentAlpha)
            {
              SetPixelViaPixelInfo(image,&image->background_color,q);
              SetPixelChannel(image,AlphaPixelChannel,TransparentAlpha,q);
            }
          q+=GetPixelChannels(image);
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
      return(status);
    }
    case CopyAlphaChannel:
    case ShapeAlphaChannel:
    {
      /*
        Copy pixel intensity to the alpha channel.
      */
      image->alpha_trait=UpdatePixelTrait;
      status=CompositeImage(image,image,IntensityCompositeOp,MagickTrue,0,0,
        exception);
      if (alpha_type == ShapeAlphaChannel)
        (void) LevelImageColors(image,&image->background_color,
          &image->background_color,MagickTrue,exception);
      break;
    }
    case DeactivateAlphaChannel:
    {
      if (image->alpha_trait == UndefinedPixelTrait)
        status=SetImageAlpha(image,OpaqueAlpha,exception);
      image->alpha_trait=CopyPixelTrait;
      break;
    }
    case DisassociateAlphaChannel:
    {
      /*
        Disassociate alpha.
      */
      status=SetImageStorageClass(image,DirectClass,exception);
      if (status == MagickFalse)
        break;
      image->alpha_trait=BlendPixelTrait;
      image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
      #pragma omp parallel for schedule(static,4) shared(status) \
        magick_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register Quantum
          *magick_restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (Quantum *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          double
            gamma, 
            Sa;

          register ssize_t
            i;

          if (GetPixelReadMask(image,q) == 0)
            {
              q+=GetPixelChannels(image);
              continue;
            }
          Sa=QuantumScale*GetPixelAlpha(image,q);
          gamma=PerceptibleReciprocal(Sa);
          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
          {
            PixelChannel channel=GetPixelChannelChannel(image,i);
            PixelTrait traits=GetPixelChannelTraits(image,channel);
            if (channel == AlphaPixelChannel)
              continue;
            if ((traits & UpdatePixelTrait) == 0)
              continue;
            q[i]=ClampToQuantum(gamma*q[i]);
          }
          q+=GetPixelChannels(image);
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
      image->alpha_trait=UndefinedPixelTrait;
      return(status);
    }
    case DiscreteAlphaChannel:
    {
      if (image->alpha_trait == UndefinedPixelTrait)
        status=SetImageAlpha(image,OpaqueAlpha,exception);
      image->alpha_trait=UpdatePixelTrait;
      break;
    }
    case ExtractAlphaChannel:
    {
      status=CompositeImage(image,image,AlphaCompositeOp,MagickTrue,0,0,
        exception);
      image->alpha_trait=UndefinedPixelTrait;
      break;
    }
    case OffAlphaChannel:
    {
      image->alpha_trait=UndefinedPixelTrait;
      break;
    }
    case OnAlphaChannel:
    {
      if (image->alpha_trait == UndefinedPixelTrait)
        status=SetImageAlpha(image,OpaqueAlpha,exception);
      image->alpha_trait=BlendPixelTrait;
      break;
    }
    case OpaqueAlphaChannel:
    {
      status=SetImageAlpha(image,OpaqueAlpha,exception);
      break;
    }
    case RemoveAlphaChannel:
    {
      /*
        Remove transparency.
      */
      if (image->alpha_trait == UndefinedPixelTrait)
        break;
      status=SetImageStorageClass(image,DirectClass,exception);
      if (status == MagickFalse)
        break;
      image_view=AcquireAuthenticCacheView(image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
      #pragma omp parallel for schedule(static,4) shared(status) \
        magick_threads(image,image,image->rows,1)
#endif
      for (y=0; y < (ssize_t) image->rows; y++)
      {
        register Quantum
          *magick_restrict q;

        register ssize_t
          x;

        if (status == MagickFalse)
          continue;
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
          exception);
        if (q == (Quantum *) NULL)
          {
            status=MagickFalse;
            continue;
          }
        for (x=0; x < (ssize_t) image->columns; x++)
        {
          FlattenPixelInfo(image,&image->background_color,
            image->background_color.alpha,q,(double)
            GetPixelAlpha(image,q),q);
          q+=GetPixelChannels(image);
        }
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
          status=MagickFalse;
      }
      image_view=DestroyCacheView(image_view);
      image->alpha_trait=image->background_color.alpha_trait;
      break;
    }
    case SetAlphaChannel:
    {
      if (image->alpha_trait == UndefinedPixelTrait)
        status=SetImageAlpha(image,OpaqueAlpha,exception);
      break;
    }
    case TransparentAlphaChannel:
    {
      status=SetImageAlpha(image,TransparentAlpha,exception);
      break;
    }
    case UndefinedAlphaChannel:
      break;
  }
  if (status == MagickFalse)
    return(status);
  (void) SetPixelChannelMask(image,image->channel_mask);
  return(SyncImagePixelCache(image,exception));
}