root / ImageMagick / branches / ImageMagick-6.3.5 / magick / fx.c

Revision 8050, 137.5 kB (checked in by cristy, 14 months ago)
<
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                                 FFFFF  X   X                                %
7%                                 F       X X                                 %
8%                                 FFF      X                                  %
9%                                 F       X X                                 %
10%                                 F      X   X                                %
11%                                                                             %
12%                                                                             %
13%                  ImageMagick Image Special Effects Methods                  %
14%                                                                             %
15%                               Software Design                               %
16%                                 John Cristy                                 %
17%                                 October 1996                                %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/annotate.h"
45#include "magick/cache.h"
46#include "magick/cache-view.h"
47#include "magick/color.h"
48#include "magick/color-private.h"
49#include "magick/composite.h"
50#include "magick/decorate.h"
51#include "magick/draw.h"
52#include "magick/effect.h"
53#include "magick/enhance.h"
54#include "magick/exception.h"
55#include "magick/exception-private.h"
56#include "magick/fx.h"
57#include "magick/fx-private.h"
58#include "magick/gem.h"
59#include "magick/geometry.h"
60#include "magick/list.h"
61#include "magick/log.h"
62#include "magick/image.h"
63#include "magick/image-private.h"
64#include "magick/memory_.h"
65#include "magick/monitor.h"
66#include "magick/option.h"
67#include "magick/pixel-private.h"
68#include "magick/property.h"
69#include "magick/quantum.h"
70#include "magick/random_.h"
71#include "magick/resample.h"
72#include "magick/resize.h"
73#include "magick/shear.h"
74#include "magick/splay-tree.h"
75#include "magick/statistic.h"
76#include "magick/string_.h"
77#include "magick/transform.h"
78#include "magick/utility.h"
79
80/*
81  Define declarations.
82*/
83#define LeftShiftOperator 0xf5
84#define RightShiftOperator 0xf6
85#define LessThanEqualOperator 0xf7
86#define GreaterThanEqualOperator 0xf8
87#define EqualOperator 0xf9
88#define NotEqualOperator 0xfa
89#define LogicalAndOperator 0xfb
90#define LogicalOrOperator 0xfc
91
92struct _FxInfo
93{
94  const Image
95    *images;
96
97  MagickBooleanType
98    matte;
99
100  char
101    *expression;
102
103  SplayTreeInfo
104    *colors,
105    *symbols;
106
107  ExceptionInfo
108    *exception;
109};
110
111/*
112%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113%                                                                             %
114%                                                                             %
115%                                                                             %
116+   A c q u i r e F x I n f o                                                 %
117%                                                                             %
118%                                                                             %
119%                                                                             %
120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121%
122%  AcquireFxInfo() allocates the FxInfo structure.
123%
124%  The format of the AcquireFxInfo method is:
125%
126%      FxInfo *AcquireFxInfo(Image *image,const char *expression)
127%  A description of each parameter follows:
128%
129%    o image: The image.
130%
131%    o expression: The expression.
132%
133*/
134MagickExport FxInfo *AcquireFxInfo(const Image *image,const char *expression)
135{
136  char
137    fx_op[2];
138
139  FxInfo
140    *fx_info;
141
142  fx_info=(FxInfo *) AcquireMagickMemory(sizeof(*fx_info));
143  if (fx_info == (FxInfo *) NULL)
144    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
145  (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info));
146  fx_info->exception=AcquireExceptionInfo();
147  fx_info->images=image;
148  fx_info->matte=image->matte;
149  fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
150    RelinquishMagickMemory);
151  fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
152    RelinquishMagickMemory);
153  if (*expression != '@')
154    fx_info->expression=AcquireString(expression);
155  else
156    fx_info->expression=FileToString(expression+1,~0,fx_info->exception);
157  (void) SubstituteString(&fx_info->expression," ","");
158  fx_op[1]='\0';
159  *fx_op=(char) LeftShiftOperator;
160  (void) SubstituteString(&fx_info->expression,"<<",fx_op);
161  *fx_op=(char) RightShiftOperator;
162  (void) SubstituteString(&fx_info->expression,">>",fx_op);
163  *fx_op=(char) LessThanEqualOperator;
164  (void) SubstituteString(&fx_info->expression,"<=",fx_op);
165  *fx_op=(char) GreaterThanEqualOperator;
166  (void) SubstituteString(&fx_info->expression,">=",fx_op);
167  *fx_op=(char) EqualOperator;
168  (void) SubstituteString(&fx_info->expression,"==",fx_op);
169  *fx_op=(char) NotEqualOperator;
170  (void) SubstituteString(&fx_info->expression,"!=",fx_op);
171  *fx_op=(char) LogicalAndOperator;
172  (void) SubstituteString(&fx_info->expression,"&&",fx_op);
173  *fx_op=(char) LogicalOrOperator;
174  (void) SubstituteString(&fx_info->expression,"||",fx_op);
175  return(fx_info);
176}
177
178/*
179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180%                                                                             %
181%                                                                             %
182%                                                                             %
183%     C h a r c o a l I m a g e                                               %
184%                                                                             %
185%                                                                             %
186%                                                                             %
187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188%
189%  CharcoalImage() creates a new image that is a copy of an existing one with
190%  the edge highlighted.  It allocates the memory necessary for the new Image
191%  structure and returns a pointer to the new image.
192%
193%  The format of the CharcoalImage method is:
194%
195%      Image *CharcoalImage(const Image *image,const double radius,
196%        const double sigma,ExceptionInfo *exception)
197%
198%  A description of each parameter follows:
199%
200%    o image: The image.
201%
202%    o radius: the radius of the pixel neighborhood.
203%
204%    o sigma: The standard deviation of the Gaussian, in pixels.
205%
206%    o exception: Return any errors or warnings in this structure.
207%
208*/
209MagickExport Image *CharcoalImage(const Image *image,const double radius,
210  const double sigma,ExceptionInfo *exception)
211{
212  Image
213    *charcoal_image,
214    *clone_image,
215    *edge_image;
216
217  assert(image != (Image *) NULL);
218  assert(image->signature == MagickSignature);
219  if (image->debug != MagickFalse)
220    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
221  assert(exception != (ExceptionInfo *) NULL);
222  assert(exception->signature == MagickSignature);
223  clone_image=CloneImage(image,0,0,MagickTrue,exception);
224  if (clone_image == (Image *) NULL)
225    return((Image *) NULL);
226  (void) SetImageType(clone_image,GrayscaleType);
227  edge_image=EdgeImage(clone_image,radius,exception);
228  clone_image=DestroyImage(clone_image);
229  if (edge_image == (Image *) NULL)
230    return((Image *) NULL);
231  charcoal_image=BlurImage(edge_image,radius,sigma,exception);
232  edge_image=DestroyImage(edge_image);
233  if (charcoal_image == (Image *) NULL)
234    return((Image *) NULL);
235  (void) NormalizeImage(charcoal_image);
236  (void) NegateImage(charcoal_image,MagickFalse);
237  (void) SetImageType(charcoal_image,GrayscaleType);
238  return(charcoal_image);
239}
240
241/*
242%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243%                                                                             %
244%                                                                             %
245%                                                                             %
246%     C o l o r i z e I m a g e                                               %
247%                                                                             %
248%                                                                             %
249%                                                                             %
250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251%
252%  ColorizeImage() blends the fill color with each pixel in the image.
253%  A percentage blend is specified with opacity.  Control the application
254%  of different color components by specifying a different percentage for
255%  each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
256%
257%  The format of the ColorizeImage method is:
258%
259%      Image *ColorizeImage(const Image *image,const char *opacity,
260%        const PixelPacket colorize,ExceptionInfo *exception)
261%
262%  A description of each parameter follows:
263%
264%    o image: The image.
265%
266%    o opacity:  A character string indicating the level of opacity as a
267%      percentage.
268%
269%    o colorize: A color value.
270%
271%    o exception: Return any errors or warnings in this structure.
272%
273*/
274MagickExport Image *ColorizeImage(const Image *image,const char *opacity,
275  const PixelPacket colorize,ExceptionInfo *exception)
276{
277#define ColorizeImageTag  "Colorize/Image"
278
279  GeometryInfo
280    geometry_info;
281
282  Image
283    *colorize_image;
284
285  long
286    y;
287
288  MagickBooleanType
289    status;
290
291  MagickPixelPacket
292    pixel;
293
294  MagickStatusType
295    flags;
296
297  register const PixelPacket
298    *p;
299
300  register long
301    x;
302
303  register PixelPacket
304    *q;
305
306  /*
307    Allocate colorized image.
308  */
309  assert(image != (const Image *) NULL);
310  assert(image->signature == MagickSignature);
311  if (image->debug != MagickFalse)
312    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
313  assert(exception != (ExceptionInfo *) NULL);
314  assert(exception->signature == MagickSignature);
315  colorize_image=CloneImage(image,0,0,MagickTrue,exception);
316  if (colorize_image == (Image *) NULL)
317    return((Image *) NULL);
318  if (SetImageStorageClass(colorize_image,DirectClass) == MagickFalse)
319    {
320      InheritException(exception,&colorize_image->exception);
321      colorize_image=DestroyImage(colorize_image);
322      return((Image *) NULL);
323    }
324  if (opacity == (const char *) NULL)
325    return(colorize_image);
326  /*
327    Determine RGB values of the pen color.
328  */
329  flags=ParseGeometry(opacity,&geometry_info);
330  pixel.red=geometry_info.rho;
331  if ((flags & SigmaValue) != 0)
332    pixel.green=geometry_info.sigma;
333  else
334    pixel.green=pixel.red;
335  if ((flags & XiValue) != 0)
336    pixel.blue=geometry_info.xi;
337  else
338    pixel.blue=pixel.red;
339  if ((flags & PsiValue) != 0)
340    pixel.opacity=geometry_info.psi;
341  else
342    pixel.opacity=(MagickRealType) OpaqueOpacity;
343  /*
344    Colorize DirectClass image.
345  */
346  for (y=0; y < (long) image->rows; y++)
347  {
348    p=AcquireImagePixels(image,0,y,image->columns,1,exception);
349    q=GetImagePixels(colorize_image,0,y,colorize_image->columns,1);
350    if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
351      break;
352    for (x=0; x < (long) image->columns; x++)
353    {
354      q->red=(Quantum) ((p->red*(100.0-pixel.red)+
355        colorize.red*pixel.red)/100.0);
356      q->green=(Quantum) ((p->green*(100.0-pixel.green)+
357        colorize.green*pixel.green)/100.0);
358      q->blue=(Quantum) ((p->blue*(100.0-pixel.blue)+
359        colorize.blue*pixel.blue)/100.0);
360      q->opacity=(Quantum) ((p->opacity*(100.0-pixel.opacity)+
361        colorize.opacity*pixel.opacity)/100.0);
362      p++;
363      q++;
364    }
365    if (SyncImagePixels(colorize_image) == MagickFalse)
366      break;
367    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
368        (QuantumTick(y,image->rows) != MagickFalse))
369      {
370        status=image->progress_monitor(ColorizeImageTag,y,image->rows,
371          image->client_data);
372        if (status == MagickFalse)
373          break;
374      }
375  }
376  return(colorize_image);
377}
378
379/*
380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381%                                                                             %
382%                                                                             %
383%                                                                             %
384%     C o n v o l v e I m a g e                                               %
385%                                                                             %
386%                                                                             %
387%                                                                             %
388%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389%
390%  ConvolveImage() applies a custom convolution kernel to the image.
391%
392%  The format of the ConvolveImage method is:
393%
394%      Image *ConvolveImage(const Image *image,const unsigned long order,
395%        const double *kernel,ExceptionInfo *exception)
396%      Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
397%        const unsigned long order,const double *kernel,
398%        ExceptionInfo *exception)
399%
400%  A description of each parameter follows:
401%
402%    o image: The image.
403%
404%    o channel: The channel type.
405%
406%    o order: The number of columns and rows in the filter kernel.
407%
408%    o kernel: An array of double representing the convolution kernel.
409%
410%    o exception: Return any errors or warnings in this structure.
411%
412*/
413
414MagickExport Image *ConvolveImage(const Image *image,const unsigned long order,
415  const double *kernel,ExceptionInfo *exception)
416{
417  Image
418    *convolve_image;
419
420  convolve_image=ConvolveImageChannel(image,DefaultChannels,order,kernel,
421    exception);
422  return(convolve_image);
423}
424
425MagickExport Image *ConvolveImageChannel(const Image *image,
426  const ChannelType channel,const unsigned long order,const double *kernel,
427  ExceptionInfo *exception)
428{
429#define ConvolveImageTag  "Convolve/Image"
430
431  Image
432    *convolve_image;
433
434  long
435    j,
436    u,
437    v,
438    y;
439
440  MagickBooleanType
441    status;
442
443  MagickPixelPacket
444    pixel;
445
446  MagickRealType
447    alpha,
448    gamma;
449
450  register const double
451    *k;
452  register const IndexPacket
453    *indexes;
454
455  register const PixelPacket
456    *pixels;
457
458  register IndexPacket
459    *convolve_indexes;
460
461  register long
462    x;
463
464  register PixelPacket
465    *convolve_pixels;
466
467  unsigned long
468    width;
469
470  /*
471    Initialize convolve image attributes.
472  */
473  assert(image != (Image *) NULL);
474  assert(image->signature == MagickSignature);
475  if (image->debug != MagickFalse)
476    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
477  assert(exception != (ExceptionInfo *) NULL);
478  assert(exception->signature == MagickSignature);
479  width=order;
480  if ((width % 2) == 0)
481    ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
482  convolve_image=CloneImage(image,0,0,MagickTrue,exception);
483  if (convolve_image == (Image *) NULL)
484    return((Image *) NULL);
485  if (SetImageStorageClass(convolve_image,DirectClass) == MagickFalse)
486    {
487      InheritException(exception,&convolve_image->exception);
488      convolve_image=DestroyImage(convolve_image);
489      return((Image *) NULL);
490    }
491  /*
492    Convolve image.
493  */
494  if (image->debug != MagickFalse)
495    {
496      char
497        format[MaxTextExtent],
498        *message;
499
500      (void) LogMagickEvent(TransformEvent,GetMagickModule(),
501        "  ConvolveImage with %ldx%ld kernel:",width,width);
502      message=AcquireString("");
503      k=kernel;
504      for (v=0; v < (long) width; v++)
505      {
506        *message='\0';
507        (void) FormatMagickString(format,MaxTextExtent,"%ld: ",v);
508        (void) ConcatenateString(&message,format);
509        for (u=0; u < (long) width; u++)
510        {
511          (void) FormatMagickString(format,MaxTextExtent,"%+f ",*k++);
512          (void) ConcatenateString(&message,format);
513        }
514        (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
515      }
516      message=DestroyString(message);
517    }
518  for (y=0; y < (long) convolve_image->rows; y++)
519  {
520    pixels=AcquireImagePixels(image,-((long) width/2L),y-(long) (width/2L),
521      image->columns+width,width,exception);
522    convolve_pixels=GetImagePixels(convolve_image,0,y,convolve_image->columns,
523      1);
524    if ((pixels == (const PixelPacket *) NULL) ||
525        (convolve_pixels == (PixelPacket *) NULL))
526      break;
527    indexes=AcquireIndexes(image);
528    convolve_indexes=GetIndexes(convolve_image);
529    #pragma omp parallel for private(alpha, gamma, j, k, pixel, u, v)
530    for (x=0; x < (long) convolve_image->columns; x++)
531    {
532      GetMagickPixelPacket(image,&pixel);
533      gamma=0.0;
534      k=kernel;
535      j=0;
536      for (v=0; v < (long) width; v++)
537      {
538        for (u=0; u < (long) width; u++)
539        {
540          alpha=1.0;
541          if (((channel & OpacityChannel) != 0) &&
542              (image->matte != MagickFalse))
543            alpha=((MagickRealType) QuantumRange-pixels[x+u+j].opacity)/
544              (MagickRealType) QuantumRange;
545          if ((channel & RedChannel) != 0)
546            pixel.red+=(*k)*alpha*pixels[x+u+j].red;
547          if ((channel & GreenChannel) != 0)
548            pixel.green+=(*k)*alpha*pixels[x+u+j].green;
549          if ((channel & BlueChannel) != 0)
550            pixel.blue+=(*k)*alpha*pixels[x+u+j].blue;
551          if ((channel & OpacityChannel) != 0)
552            pixel.opacity+=(*k)*pixels[x+u+j].opacity;
553          if (((channel & IndexChannel) != 0) &&
554              (image->colorspace == CMYKColorspace))
555            pixel.index+=(*k)*alpha*indexes[x+u+j];
556          gamma+=(*k)*alpha;
557          k++;
558        }
559        j+=image->columns+width;
560      }
561      gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
562      if ((channel & RedChannel) != 0)
563        convolve_pixels[x].red=RoundToQuantum(gamma*pixel.red+image->bias);
564      if ((channel & GreenChannel) != 0)
565        convolve_pixels[x].green=RoundToQuantum(gamma*pixel.green+image->bias);
566      if ((channel & BlueChannel) != 0)
567        convolve_pixels[x].blue=RoundToQuantum(gamma*pixel.blue+image->bias);
568      if ((channel & OpacityChannel) != 0)
569        convolve_pixels[x].opacity=RoundToQuantum(pixel.opacity+image->bias);
570      if (((channel & IndexChannel) != 0) &&
571          (image->colorspace == CMYKColorspace))
572        convolve_indexes[x]=RoundToQuantum(gamma*pixel.index+image->bias);
573    }
574    if (SyncImagePixels(convolve_image) == MagickFalse)
575      break;
576    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
577        (QuantumTick(y,image->rows) != MagickFalse))
578      {
579        status=image->progress_monitor(ConvolveImageTag,y,image->rows,
580          image->client_data);
581        if (status == MagickFalse)
582          break;
583      }
584  }
585  return(convolve_image);
586}
587
588/*
589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590%                                                                             %
591%                                                                             %
592%                                                                             %
593+   D e s t r o y F x I n f o                                                 %
594%                                                                             %
595%                                                                             %
596%                                                                             %
597%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598%
599%  DestroyImageInfo() deallocates memory associated with an FxInfo structure.
600%
601%  The format of the DestroyImageInfo method is:
602%
603%      ImageInfo *DestroyImageInfo(ImageInfo *fx_info)
604%
605%  A description of each parameter follows:
606%
607%    o fx_info: The fx info.
608%
609*/
610MagickExport FxInfo *DestroyFxInfo(FxInfo *fx_info)
611{
612  fx_info->exception=DestroyExceptionInfo(fx_info->exception);
613  fx_info->expression=DestroyString(fx_info->expression);
614  fx_info->symbols=DestroySplayTree(fx_info->symbols);
615  fx_info->colors=DestroySplayTree(fx_info->colors);
616  fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
617  return(fx_info);
618}
619
620/*
621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622%                                                                             %
623%                                                                             %
624%                                                                             %
625%     E v a l u a t e I m a g e                                               %
626%                                                                             %
627%                                                                             %
628%                                                                             %
629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630%
631%  EvaluateImage() applies a value to the image with an arithmetic, relational,
632%  or logical operator to an image. Use these operations to lighten or darken
633%  an image, to increase or decrease contrast in an image, or to produce the
634%  "negative" of an image.
635%
636%  The format of the EvaluateImageChannel method is:
637%
638%      MagickBooleanType EvaluateImage(Image *image,
639%        const MagickEvaluateOperator op,const double value,
640%        ExceptionInfo *exception)
641%      MagickBooleanType EvaluateImageChannel(Image *image,
642%        const ChannelType channel,const MagickEvaluateOperator op,
643%        const double value,ExceptionInfo *exception)
644%
645%  A description of each parameter follows:
646%
647%    o image: The image.
648%
649%    o channel: The channel.
650%
651%    o op: A channel op.
652%
653%    o value: A value value.
654%
655%    o exception: Return any errors or warnings in this structure.
656%
657*/
658
659static inline double MagickMax(const double x,const double y)
660{
661  if (x > y)
662    return(x);
663  return(y);
664}
665
666static inline double MagickMin(const double x,const double y)
667{
668  if (x < y)
669    return(x);
670  return(y);
671}
672
673static inline Quantum ApplyEvaluateOperator(Quantum pixel,
674  const MagickEvaluateOperator op,const MagickRealType value)
675{
676  double
677    result;
678
679  result=0.0;
680  switch(op)
681  {
682    case UndefinedEvaluateOperator:
683      break;
684    case AddEvaluateOperator:
685    {
686      result=pixel+value;
687      break;
688    }
689    case AndEvaluateOperator:
690    {
691      result=(MagickRealType) ((unsigned long) pixel & (unsigned long)
692        (value+0.5));
693      break;
694    }
695    case DivideEvaluateOperator:
696    {
697      result=pixel/(value == 0.0 ? 1.0 : value);
698      break;
699    }
700    case LeftShiftEvaluateOperator:
701    {
702      result=(MagickRealType) ((unsigned long) pixel << (unsigned long)
703        (value+0.5));
704      break;
705    }
706    case MaxEvaluateOperator:
707    {
708      result=MagickMax((double) pixel,value);
709      break;
710    }
711    case MinEvaluateOperator:
712    {
713      result=MagickMin((double) pixel,value);
714      break;
715    }
716    case MultiplyEvaluateOperator:
717    {
718      result=pixel*value;
719      break;
720    }
721    case OrEvaluateOperator:
722    {
723      result=(MagickRealType) ((unsigned long) pixel | (unsigned long)
724        (value+0.5));
725      break;
726    }
727    case RightShiftEvaluateOperator:
728    {
729      result=(MagickRealType) ((unsigned long) pixel >> (unsigned long)
730        (value+0.5));
731      break;
732    }
733    case SetEvaluateOperator:
734    {
735      result=value;
736      break;
737    }
738    case SubtractEvaluateOperator:
739    {
740      result=pixel-value;
741      break;
742    }
743    case XorEvaluateOperator:
744    {
745      result=(MagickRealType) ((unsigned long) pixel ^ (unsigned long)
746        (value+0.5));
747      break;
748    }
749  }
750  return(RoundToQuantum(result));
751}
752
753MagickExport MagickBooleanType EvaluateImage(Image *image,
754  const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
755{
756  MagickBooleanType
757    status;
758
759  status=EvaluateImageChannel(image,AllChannels,op,value,exception);
760  return(status);
761}
762
763MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
764  const ChannelType channel,const MagickEvaluateOperator op,const double value,
765  ExceptionInfo *exception)
766{
767#define EvaluateImageTag  "Constant/Image "
768
769  IndexPacket
770    *indexes;
771
772  long
773    y;
774
775  MagickBooleanType
776    status;
777
778  register long
779    x;
780
781  register PixelPacket
782    *q;
783
784  assert(image != (Image *) NULL);
785  assert(image->signature == MagickSignature);
786  if (image->debug != MagickFalse)
787    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
788  assert(exception != (ExceptionInfo *) NULL);
789  assert(exception->signature == MagickSignature);
790  if (SetImageStorageClass(image,DirectClass) == MagickFalse)
791    {
792      InheritException(exception,&image->exception);
793      return(MagickFalse);
794    }
795  for (y=0; y < (long) image->rows; y++)
796  {
797    q=GetImagePixels(image,0,y,image->columns,1);
798    if (q == (PixelPacket *) NULL)
799      break;
800    indexes=GetIndexes(image);
801    for (x=0; x < (long) image->columns; x++)
802    {
803      if ((channel & RedChannel) != 0)
804        q->red=ApplyEvaluateOperator(q->red,op,value);
805      if ((channel & GreenChannel) != 0)
806        q->green=ApplyEvaluateOperator(q->green,op,value);
807      if ((channel & BlueChannel) != 0)
808        q->blue=ApplyEvaluateOperator(q->blue,op,value);
809      if ((channel & OpacityChannel) != 0)
810        {
811          if (image->matte == MagickFalse)
812            q->opacity=ApplyEvaluateOperator(q->opacity,op,value);
813          else
814            q->opacity=(Quantum) QuantumRange-ApplyEvaluateOperator(
815              (Quantum) QuantumRange-q->opacity,op,value);
816        }
817      if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
818        indexes[x]=(IndexPacket) ApplyEvaluateOperator(indexes[x],op,value);
819      q++;
820    }
821    if (SyncImagePixels(image) == MagickFalse)
822      break;
823    if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
824        (QuantumTick(y,image->rows) != MagickFalse))
825      {
826        status=image->progress_monitor(EvaluateImageTag,y,image->rows,
827          image->client_data);
828        if (status == MagickFalse)
829          break;
830      }
831  }
832  return(y == (long) image->rows ? MagickTrue : MagickFalse);
833}
834
835/*
836%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
837%                                                                             %
838%                                                                             %
839%                                                                             %
840+     F x E v a l u a t e C h a n n e l E x p r e s s i o n                   %
841%                                                                             %
842%                                                                             %
843%                                                                             %
844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
845%
846%  FxEvaluateChannelExpression() evaluates an expression and returns the
847%  results.
848%
849%  The format of the FxEvaluateExpression method is:
850%
851%      MagickRealType FxEvaluateChannelExpression(FxInfo *fx_info,
852%        const ChannelType channel,const long x,const long y,
853%        MagickRealType *alpha,Exceptioninfo *exception)
854%      MagickRealType FxEvaluateExpression(FxInfo *fx_info,
855%        MagickRealType *alpha,Exceptioninfo *exception)
856%
857%  A description of each parameter follows:
858%
859%    o fx_info: The fx info.
860%
861%    o channel: The channel.
862%
863%    o x,y: the pixel position.
864%
865%    o alpha: the result.
866%
867%    o exception: Return any errors or warnings in this structure.
868%
869*/
870
871static MagickRealType
872  FxEvaluateSubexpression(FxInfo *,const ChannelType,const long,const long,
873    const char *,MagickRealType *,ExceptionInfo *);
874
875static inline MagickRealType FxMax(FxInfo *fx_info,const ChannelType channel,
876  const long x,const long y,const char *expression,ExceptionInfo *exception)
877{
878  MagickRealType
879    alpha,
880    beta;
881
882  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
883  return((MagickRealType) MagickMax((double) alpha,(double) beta));
884}
885
886static inline MagickRealType FxMin(FxInfo *fx_info,ChannelType channel,
887  const long x,const long y,const char *expression,ExceptionInfo *exception)
888{
889  MagickRealType
890    alpha,
891    beta;
892
893  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
894  return((MagickRealType) MagickMin((double) alpha,(double) beta));
895}
896
897static inline const char *FxSubexpression(const char *expression,
898  ExceptionInfo *exception)
899{
900  const char
901    *subexpression;
902
903  register long
904    level;
905
906  level=0;
907  subexpression=expression;
908  while ((*subexpression != '\0') &&
909         ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
910  {
911    if (strchr("(",(int) *subexpression) != (char *) NULL)
912      level++;
913    else
914      if (strchr(")",(int) *subexpression) != (char *) NULL)
915        level--;
916    subexpression++;
917  }
918  if (*subexpression == '\0')
919    (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
920      "UnbalancedParenthesis","`%s'",expression);
921  return(subexpression);
922}
923
924static MagickRealType FxGetSymbol(FxInfo *fx_info,const ChannelType channel,
925  const long x,const long y,const char *expression,ExceptionInfo *exception)
926{
927  char
928    *q,
929    subexpression[MaxTextExtent],
930    symbol[MaxTextExtent];
931
932  const char
933    *p,
934    *value;
935
936  Image
937    *image;
938
939  MagickPixelPacket
940    pixel;
941
942  MagickRealType
943    alpha,
944    beta;
945
946  PointInfo
947    point;
948
949  register long
950    i;
951
952  ResampleFilter
953    *resample_filter;
954
955  unsigned long
956    level;
957
958  p=expression;
959  i=GetImageIndexInList(fx_info->images);
960  level=0;
961  point.x=(double) x;
962  point.y=(double) y;
963  if (isalpha((int) *(p+1)) == 0)
964    {
965      if (strchr("suv",(int) *p) != (char *) NULL)
966        {
967          switch (*p)
968          {
969            case 's':
970            default:
971            {
972              i=GetImageIndexInList(fx_info->images);
973              break;
974            }
975            case 'u': i=0; break;
976            case 'v': i=1; break;
977          }
978          p++;