1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%        CCCC   OOO   M   M  PPPP    OOO   SSSSS  IIIII  TTTTT  EEEEE         %
7%       C      O   O  MM MM  P   P  O   O  SS       I      T    E             %
8%       C      O   O  M M M  PPPP   O   O   SSS     I      T    EEE           %
9%       C      O   O  M   M  P      O   O     SS    I      T    E             %
10%        CCCC   OOO   M   M  P       OOO   SSSSS  IIIII    T    EEEEE         %
11%                                                                             %
12%                                                                             %
13%                     MagickCore Image Composite Methods                      %
14%                                                                             %
15%                              Software Design                                %
16%                                   Cristy                                    %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2016 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 "MagickCore/studio.h"
44#include "MagickCore/artifact.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/cache-private.h"
47#include "MagickCore/cache-view.h"
48#include "MagickCore/channel.h"
49#include "MagickCore/client.h"
50#include "MagickCore/color.h"
51#include "MagickCore/color-private.h"
52#include "MagickCore/colorspace.h"
53#include "MagickCore/colorspace-private.h"
54#include "MagickCore/composite.h"
55#include "MagickCore/composite-private.h"
56#include "MagickCore/constitute.h"
57#include "MagickCore/draw.h"
58#include "MagickCore/fx.h"
59#include "MagickCore/gem.h"
60#include "MagickCore/geometry.h"
61#include "MagickCore/image.h"
62#include "MagickCore/image-private.h"
63#include "MagickCore/list.h"
64#include "MagickCore/log.h"
65#include "MagickCore/monitor.h"
66#include "MagickCore/monitor-private.h"
67#include "MagickCore/memory_.h"
68#include "MagickCore/option.h"
69#include "MagickCore/pixel-accessor.h"
70#include "MagickCore/property.h"
71#include "MagickCore/quantum.h"
72#include "MagickCore/resample.h"
73#include "MagickCore/resource_.h"
74#include "MagickCore/string_.h"
75#include "MagickCore/thread-private.h"
76#include "MagickCore/threshold.h"
77#include "MagickCore/token.h"
78#include "MagickCore/utility.h"
79#include "MagickCore/utility-private.h"
80#include "MagickCore/version.h"
81
82/*
83%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84%                                                                             %
85%                                                                             %
86%                                                                             %
87%   C o m p o s i t e I m a g e                                               %
88%                                                                             %
89%                                                                             %
90%                                                                             %
91%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92%
93%  CompositeImage() returns the second image composited onto the first
94%  at the specified offset, using the specified composite method.
95%
96%  The format of the CompositeImage method is:
97%
98%      MagickBooleanType CompositeImage(Image *image,
99%        const Image *source_image,const CompositeOperator compose,
100%        const MagickBooleanType clip_to_self,const ssize_t x_offset,
101%        const ssize_t y_offset,ExceptionInfo *exception)
102%
103%  A description of each parameter follows:
104%
105%    o image: the canvas image, modified by he composition
106%
107%    o source_image: the source image.
108%
109%    o compose: This operator affects how the composite is applied to
110%      the image.  The operators and how they are utilized are listed here
111%      http://www.w3.org/TR/SVG12/#compositing.
112%
113%    o clip_to_self: set to MagickTrue to limit composition to area composed.
114%
115%    o x_offset: the column offset of the composited image.
116%
117%    o y_offset: the row offset of the composited image.
118%
119%  Extra Controls from Image meta-data in 'image' (artifacts)
120%
121%    o "compose:args"
122%        A string containing extra numerical arguments for specific compose
123%        methods, generally expressed as a 'geometry' or a comma separated list
124%        of numbers.
125%
126%        Compose methods needing such arguments include "BlendCompositeOp" and
127%        "DisplaceCompositeOp".
128%
129%    o exception: return any errors or warnings in this structure.
130%
131*/
132
133/*
134   Composition based on the SVG specification:
135
136   A Composition is defined by...
137      Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
138      Blending areas :  X = 1     for area of overlap, ie: f(Sc,Dc)
139                        Y = 1     for source preserved
140                        Z = 1     for canvas preserved
141
142   Conversion to transparency (then optimized)
143      Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
144      Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
145
146   Where...
147      Sca = Sc*Sa     normalized Source color divided by Source alpha
148      Dca = Dc*Da     normalized Dest color divided by Dest alpha
149      Dc' = Dca'/Da'  the desired color value for this channel.
150
151   Da' in in the follow formula as 'gamma'  The resulting alpla value.
152
153   Most functions use a blending mode of over (X=1,Y=1,Z=1) this results in
154   the following optimizations...
155      gamma = Sa+Da-Sa*Da;
156      gamma = 1 - QuantiumScale*alpha * QuantiumScale*beta;
157      opacity = QuantiumScale*alpha*beta;  // over blend, optimized 1-Gamma
158
159   The above SVG definitions also definate that Mathematical Composition
160   methods should use a 'Over' blending mode for Alpha Channel.
161   It however was not applied for composition modes of 'Plus', 'Minus',
162   the modulus versions of 'Add' and 'Subtract'.
163
164   Mathematical operator changes to be applied from IM v6.7...
165
166    1) Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
167       'ModulusAdd' and 'ModulusSubtract' for clarity.
168
169    2) All mathematical compositions work as per the SVG specification
170       with regard to blending.  This now includes 'ModulusAdd' and
171       'ModulusSubtract'.
172
173    3) When the special channel flag 'sync' (syncronize channel updates)
174       is turned off (enabled by default) then mathematical compositions are
175       only performed on the channels specified, and are applied
176       independantally of each other.  In other words the mathematics is
177       performed as 'pure' mathematical operations, rather than as image
178       operations.
179*/
180
181static void HCLComposite(const MagickRealType hue,const MagickRealType chroma,
182  const MagickRealType luma,MagickRealType *red,MagickRealType *green,
183  MagickRealType *blue)
184{
185  MagickRealType
186    b,
187    c,
188    g,
189    h,
190    m,
191    r,
192    x;
193
194  /*
195    Convert HCL to RGB colorspace.
196  */
197  assert(red != (MagickRealType *) NULL);
198  assert(green != (MagickRealType *) NULL);
199  assert(blue != (MagickRealType *) NULL);
200  h=6.0*hue;
201  c=chroma;
202  x=c*(1.0-fabs(fmod(h,2.0)-1.0));
203  r=0.0;
204  g=0.0;
205  b=0.0;
206  if ((0.0 <= h) && (h < 1.0))
207    {
208      r=c;
209      g=x;
210    }
211  else
212    if ((1.0 <= h) && (h < 2.0))
213      {
214        r=x;
215        g=c;
216      }
217    else
218      if ((2.0 <= h) && (h < 3.0))
219        {
220          g=c;
221          b=x;
222        }
223      else
224        if ((3.0 <= h) && (h < 4.0))
225          {
226            g=x;
227            b=c;
228          }
229        else
230          if ((4.0 <= h) && (h < 5.0))
231            {
232              r=x;
233              b=c;
234            }
235          else
236            if ((5.0 <= h) && (h < 6.0))
237              {
238                r=c;
239                b=x;
240              }
241  m=luma-(0.298839*r+0.586811*g+0.114350*b);
242  *red=QuantumRange*(r+m);
243  *green=QuantumRange*(g+m);
244  *blue=QuantumRange*(b+m);
245}
246
247static void CompositeHCL(const MagickRealType red,const MagickRealType green,
248  const MagickRealType blue,MagickRealType *hue,MagickRealType *chroma,
249  MagickRealType *luma)
250{
251  MagickRealType
252    b,
253    c,
254    g,
255    h,
256    max,
257    r;
258
259  /*
260    Convert RGB to HCL colorspace.
261  */
262  assert(hue != (MagickRealType *) NULL);
263  assert(chroma != (MagickRealType *) NULL);
264  assert(luma != (MagickRealType *) NULL);
265  r=red;
266  g=green;
267  b=blue;
268  max=MagickMax(r,MagickMax(g,b));
269  c=max-(MagickRealType) MagickMin(r,MagickMin(g,b));
270  h=0.0;
271  if (c == 0)
272    h=0.0;
273  else
274    if (red == max)
275      h=fmod((g-b)/c+6.0,6.0);
276    else
277      if (green == max)
278        h=((b-r)/c)+2.0;
279      else
280        if (blue == max)
281          h=((r-g)/c)+4.0;
282  *hue=(h/6.0);
283  *chroma=QuantumScale*c;
284  *luma=QuantumScale*(0.298839*r+0.586811*g+0.114350*b);
285}
286
287static MagickBooleanType CompositeOverImage(Image *image,
288  const Image *source_image,const MagickBooleanType clip_to_self,
289  const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
290{
291#define CompositeImageTag  "Composite/Image"
292
293  CacheView
294    *image_view,
295    *source_view;
296
297  const char
298    *value;
299
300  MagickBooleanType
301    clamp,
302    status;
303
304  MagickOffsetType
305    progress;
306
307  ssize_t
308    y;
309
310  /*
311    Composite image.
312  */
313  status=MagickTrue;
314  progress=0;
315  clamp=MagickTrue;
316  value=GetImageArtifact(image,"compose:clamp");
317  if (value != (const char *) NULL)
318    clamp=IsStringTrue(value);
319  source_view=AcquireVirtualCacheView(source_image,exception);
320  image_view=AcquireAuthenticCacheView(image,exception);
321#if defined(MAGICKCORE_OPENMP_SUPPORT)
322  #pragma omp parallel for schedule(static,4) shared(progress,status) \
323    magick_threads(source_image,image,image->rows,1)
324#endif
325  for (y=0; y < (ssize_t) image->rows; y++)
326  {
327    const Quantum
328      *pixels;
329
330    register const Quantum
331      *magick_restrict p;
332
333    register Quantum
334      *magick_restrict q;
335
336    register ssize_t
337      x;
338
339    size_t
340      channels;
341
342    if (status == MagickFalse)
343      continue;
344    if (clip_to_self != MagickFalse)
345      {
346        if (y < y_offset)
347          continue;
348        if ((y-y_offset) >= (ssize_t) source_image->rows)
349          continue;
350      }
351    /*
352      If pixels is NULL, y is outside overlay region.
353    */
354    pixels=(Quantum *) NULL;
355    p=(Quantum *) NULL;
356    if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
357      {
358        p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
359          source_image->columns,1,exception);
360        if (p == (const Quantum *) NULL)
361          {
362            status=MagickFalse;
363            continue;
364          }
365        pixels=p;
366        if (x_offset < 0)
367          p-=x_offset*GetPixelChannels(source_image);
368      }
369    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
370    if (q == (Quantum *) NULL)
371      {
372        status=MagickFalse;
373        continue;
374      }
375    for (x=0; x < (ssize_t) image->columns; x++)
376    {
377      MagickRealType
378        Da,
379        Dc,
380        Dca,
381        gamma,
382        Sa,
383        Sc,
384        Sca;
385
386      register ssize_t
387        i;
388
389      if (clip_to_self != MagickFalse)
390        {
391          if (x < x_offset)
392            {
393              q+=GetPixelChannels(image);
394              continue;
395            }
396          if ((x-x_offset) >= (ssize_t) source_image->columns)
397            break;
398        }
399      if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
400          ((x-x_offset) >= (ssize_t) source_image->columns))
401        {
402          Quantum
403            source[MaxPixelChannels];
404
405          /*
406            Virtual composite:
407              Sc: source color.
408              Dc: canvas color.
409          */
410          if (GetPixelReadMask(image,q) == 0)
411            {
412              q+=GetPixelChannels(image);
413              continue;
414            }
415          (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,
416            source,exception);
417          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
418          {
419            PixelChannel channel=GetPixelChannelChannel(image,i);
420            PixelTrait traits=GetPixelChannelTraits(image,channel);
421            PixelTrait source_traits=GetPixelChannelTraits(source_image,
422              channel);
423            if ((traits == UndefinedPixelTrait) ||
424                (source_traits == UndefinedPixelTrait))
425              continue;
426            q[i]=source[channel];
427          }
428          q+=GetPixelChannels(image);
429          continue;
430        }
431      /*
432        Authentic composite:
433          Sa:  normalized source alpha.
434          Da:  normalized canvas alpha.
435      */
436      if (GetPixelReadMask(source_image,p) == 0)
437        {
438          p+=GetPixelChannels(source_image);
439          channels=GetPixelChannels(source_image);
440          if (p >= (pixels+channels*source_image->columns))
441            p=pixels;
442          q+=GetPixelChannels(image);
443          continue;
444        }
445      Sa=QuantumScale*GetPixelAlpha(source_image,p);
446      Da=QuantumScale*GetPixelAlpha(image,q);
447      gamma=Sa+Da-Sa*Da;
448      gamma=PerceptibleReciprocal(gamma);
449      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
450      {
451        PixelChannel channel=GetPixelChannelChannel(image,i);
452        PixelTrait traits=GetPixelChannelTraits(image,channel);
453        PixelTrait source_traits=GetPixelChannelTraits(source_image,
454          channel);
455        if ((traits == UndefinedPixelTrait) ||
456            (source_traits == UndefinedPixelTrait))
457          continue;
458        if ((traits & CopyPixelTrait) != 0)
459          {
460            /*
461              Copy channel.
462            */
463            q[i]=GetPixelChannel(source_image,channel,p);
464            continue;
465          }
466        if (channel == AlphaPixelChannel)
467          {
468            /*
469              Set alpha channel.
470            */
471            q[i]=clamp != MagickFalse ?
472              ClampPixel(QuantumRange*(Sa+Da-Sa*Da)) :
473              ClampToQuantum(QuantumRange*(Sa+Da-Sa*Da));
474            continue;
475          }
476        /*
477          Sc: source color.
478          Dc: canvas color.
479        */
480        Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
481        Dc=(MagickRealType) q[i];
482        Sca=QuantumScale*Sa*Sc;
483        Dca=QuantumScale*Da*Dc;
484        q[i]=clamp != MagickFalse ?
485          ClampPixel(gamma*QuantumRange*(Sca+Dca*(1.0-Sa))) :
486          ClampToQuantum(gamma*QuantumRange*(Sca+Dca*(1.0-Sa)));
487      }
488      p+=GetPixelChannels(source_image);
489      channels=GetPixelChannels(source_image);
490      if (p >= (pixels+channels*source_image->columns))
491        p=pixels;
492      q+=GetPixelChannels(image);
493    }
494    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
495      status=MagickFalse;
496    if (image->progress_monitor != (MagickProgressMonitor) NULL)
497      {
498        MagickBooleanType
499          proceed;
500
501#if defined(MAGICKCORE_OPENMP_SUPPORT)
502        #pragma omp critical (MagickCore_CompositeImage)
503#endif
504        proceed=SetImageProgress(image,CompositeImageTag,progress++,
505          image->rows);
506        if (proceed == MagickFalse)
507          status=MagickFalse;
508      }
509  }
510  source_view=DestroyCacheView(source_view);
511  image_view=DestroyCacheView(image_view);
512  return(status);
513}
514
515MagickExport MagickBooleanType CompositeImage(Image *image,
516  const Image *composite,const CompositeOperator compose,
517  const MagickBooleanType clip_to_self,const ssize_t x_offset,
518  const ssize_t y_offset,ExceptionInfo *exception)
519{
520#define CompositeImageTag  "Composite/Image"
521
522  CacheView
523    *source_view,
524    *image_view;
525
526  const char
527    *value;
528
529  GeometryInfo
530    geometry_info;
531
532  Image
533    *canvas_image,
534    *source_image;
535
536  MagickBooleanType
537    clamp,
538    status;
539
540  MagickOffsetType
541    progress;
542
543  MagickRealType
544    amount,
545    canvas_dissolve,
546    midpoint,
547    percent_luma,
548    percent_chroma,
549    source_dissolve,
550    threshold;
551
552  MagickStatusType
553    flags;
554
555  ssize_t
556    y;
557
558  assert(image != (Image *) NULL);
559  assert(image->signature == MagickCoreSignature);
560  if (image->debug != MagickFalse)
561    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
562  assert(composite!= (Image *) NULL);
563  assert(composite->signature == MagickCoreSignature);
564  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
565    return(MagickFalse);
566  source_image=CloneImage(composite,0,0,MagickTrue,exception);
567  if (source_image == (const Image *) NULL)
568    return(MagickFalse);
569  if (IsGrayColorspace(image->colorspace) != MagickFalse)
570    (void) SetImageColorspace(image,sRGBColorspace,exception);
571  (void) SetImageColorspace(source_image,image->colorspace,exception);
572  if ((image->alpha_trait != UndefinedPixelTrait) &&
573      (source_image->alpha_trait == UndefinedPixelTrait))
574    (void) SetImageAlphaChannel(source_image,SetAlphaChannel,exception);
575  if ((compose == OverCompositeOp) || (compose == SrcOverCompositeOp))
576    {
577      status=CompositeOverImage(image,source_image,clip_to_self,x_offset,
578        y_offset,exception);
579      source_image=DestroyImage(source_image);
580      return(status);
581    }
582  amount=0.5;
583  canvas_image=(Image *) NULL;
584  canvas_dissolve=1.0;
585  clamp=MagickTrue;
586  value=GetImageArtifact(image,"compose:clamp");
587  if (value != (const char *) NULL)
588    clamp=IsStringTrue(value);
589  SetGeometryInfo(&geometry_info);
590  percent_luma=100.0;
591  percent_chroma=100.0;
592  source_dissolve=1.0;
593  threshold=0.05f;
594  switch (compose)
595  {
596    case CopyCompositeOp:
597    {
598      if ((x_offset < 0) || (y_offset < 0))
599        break;
600      if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
601        break;
602      if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
603        break;
604      status=MagickTrue;
605      source_view=AcquireVirtualCacheView(source_image,exception);
606      image_view=AcquireAuthenticCacheView(image,exception);
607#if defined(MAGICKCORE_OPENMP_SUPPORT)
608      #pragma omp parallel for schedule(static,4) shared(status) \
609        magick_threads(source_image,image,source_image->rows,1)
610#endif
611      for (y=0; y < (ssize_t) source_image->rows; y++)
612      {
613        MagickBooleanType
614          sync;
615
616        register const Quantum
617          *p;
618
619        register Quantum
620          *q;
621
622        register ssize_t
623          x;
624
625        if (status == MagickFalse)
626          continue;
627        p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
628          exception);
629        q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
630          source_image->columns,1,exception);
631        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
632          {
633            status=MagickFalse;
634            continue;
635          }
636        for (x=0; x < (ssize_t) source_image->columns; x++)
637        {
638          register ssize_t
639            i;
640
641          if (GetPixelReadMask(source_image,p) == 0)
642            {
643              p+=GetPixelChannels(source_image);
644              q+=GetPixelChannels(image);
645              continue;
646            }
647          for (i=0; i < (ssize_t) GetPixelChannels(source_image); i++)
648          {
649            PixelChannel channel=GetPixelChannelChannel(source_image,i);
650            PixelTrait source_traits=GetPixelChannelTraits(source_image,
651              channel);
652            PixelTrait traits=GetPixelChannelTraits(image,channel);
653            if ((traits == UndefinedPixelTrait) ||
654                (source_traits == UndefinedPixelTrait))
655              continue;
656            SetPixelChannel(image,channel,p[i],q);
657          }
658          p+=GetPixelChannels(source_image);
659          q+=GetPixelChannels(image);
660        }
661        sync=SyncCacheViewAuthenticPixels(image_view,exception);
662        if (sync == MagickFalse)
663          status=MagickFalse;
664        if (image->progress_monitor != (MagickProgressMonitor) NULL)
665          {
666            MagickBooleanType
667              proceed;
668
669#if defined(MAGICKCORE_OPENMP_SUPPORT)
670            #pragma omp critical (MagickCore_CompositeImage)
671#endif
672            proceed=SetImageProgress(image,CompositeImageTag,
673              (MagickOffsetType) y,image->rows);
674            if (proceed == MagickFalse)
675              status=MagickFalse;
676          }
677      }
678      source_view=DestroyCacheView(source_view);
679      image_view=DestroyCacheView(image_view);
680      source_image=DestroyImage(source_image);
681      return(status);
682    }
683    case IntensityCompositeOp:
684    {
685      if ((x_offset < 0) || (y_offset < 0))
686        break;
687      if ((x_offset+(ssize_t) source_image->columns) > (ssize_t) image->columns)
688        break;
689      if ((y_offset+(ssize_t) source_image->rows) > (ssize_t) image->rows)
690        break;
691      status=MagickTrue;
692      source_view=AcquireVirtualCacheView(source_image,exception);
693      image_view=AcquireAuthenticCacheView(image,exception);
694#if defined(MAGICKCORE_OPENMP_SUPPORT)
695      #pragma omp parallel for schedule(static,4) shared(status) \
696        magick_threads(source_image,image,source_image->rows,1)
697#endif
698      for (y=0; y < (ssize_t) source_image->rows; y++)
699      {
700        MagickBooleanType
701          sync;
702
703        register const Quantum
704          *p;
705
706        register Quantum
707          *q;
708
709        register ssize_t
710          x;
711
712        if (status == MagickFalse)
713          continue;
714        p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
715          exception);
716        q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
717          source_image->columns,1,exception);
718        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
719          {
720            status=MagickFalse;
721            continue;
722          }
723        for (x=0; x < (ssize_t) source_image->columns; x++)
724        {
725          if (GetPixelReadMask(source_image,p) == 0)
726            {
727              p+=GetPixelChannels(source_image);
728              q+=GetPixelChannels(image);
729              continue;
730            }
731          SetPixelAlpha(image,clamp != MagickFalse ?
732            ClampPixel(GetPixelIntensity(source_image,p)) :
733            ClampToQuantum(GetPixelIntensity(source_image,p)),q);
734          p+=GetPixelChannels(source_image);
735          q+=GetPixelChannels(image);
736        }
737        sync=SyncCacheViewAuthenticPixels(image_view,exception);
738        if (sync == MagickFalse)
739          status=MagickFalse;
740        if (image->progress_monitor != (MagickProgressMonitor) NULL)
741          {
742            MagickBooleanType
743              proceed;
744
745#if defined(MAGICKCORE_OPENMP_SUPPORT)
746            #pragma omp critical (MagickCore_CompositeImage)
747#endif
748            proceed=SetImageProgress(image,CompositeImageTag,
749              (MagickOffsetType) y,image->rows);
750            if (proceed == MagickFalse)
751              status=MagickFalse;
752          }
753      }
754      source_view=DestroyCacheView(source_view);
755      image_view=DestroyCacheView(image_view);
756      source_image=DestroyImage(source_image);
757      return(status);
758    }
759    case CopyAlphaCompositeOp:
760    case ChangeMaskCompositeOp:
761    {
762      /*
763        Modify canvas outside the overlaid region and require an alpha
764        channel to exist, to add transparency.
765      */
766      if (image->alpha_trait == UndefinedPixelTrait)
767        (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
768      break;
769    }
770    case BlurCompositeOp:
771    {
772      CacheView
773        *canvas_view;
774
775      MagickRealType
776        angle_range,
777        angle_start,
778        height,
779        width;
780
781      PixelInfo
782        pixel;
783
784      ResampleFilter
785        *resample_filter;
786
787      SegmentInfo
788        blur;
789
790      /*
791        Blur Image by resampling.
792
793        Blur Image dictated by an overlay gradient map: X = red_channel;
794          Y = green_channel; compose:args =  x_scale[,y_scale[,angle]].
795      */
796      canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
797        exception);
798      if (canvas_image == (Image *) NULL)
799        {
800          source_image=DestroyImage(source_image);
801          return(MagickFalse);
802        }
803      /*
804        Gather the maximum blur sigma values from user.
805      */
806      flags=NoValue;
807      value=GetImageArtifact(image,"compose:args");
808      if (value != (const char *) NULL)
809        flags=ParseGeometry(value,&geometry_info);
810      if ((flags & WidthValue) == 0)
811        {
812          (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
813            "InvalidSetting","'%s' '%s'","compose:args",value);
814          source_image=DestroyImage(source_image);
815          canvas_image=DestroyImage(canvas_image);
816          return(MagickFalse);
817        }
818      /*
819        Users input sigma now needs to be converted to the EWA ellipse size.
820        The filter defaults to a sigma of 0.5 so to make this match the
821        users input the ellipse size needs to be doubled.
822      */
823      width=height=geometry_info.rho*2.0;
824      if ((flags & HeightValue) != 0 )
825        height=geometry_info.sigma*2.0;
826      /*
827        Default the unrotated ellipse width and height axis vectors.
828      */
829      blur.x1=width;
830      blur.x2=0.0;
831      blur.y1=0.0;
832      blur.y2=height;
833      /* rotate vectors if a rotation angle is given */
834      if ((flags & XValue) != 0 )
835        {
836          MagickRealType
837            angle;
838
839          angle=DegreesToRadians(geometry_info.xi);
840          blur.x1=width*cos(angle);
841          blur.x2=width*sin(angle);
842          blur.y1=(-height*sin(angle));
843          blur.y2=height*cos(angle);
844        }
845      /* Otherwise lets set a angle range and calculate in the loop */
846      angle_start=0.0;
847      angle_range=0.0;
848      if ((flags & YValue) != 0 )
849        {
850          angle_start=DegreesToRadians(geometry_info.xi);
851          angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
852        }
853      /*
854        Set up a gaussian cylindrical filter for EWA Bluring.
855
856        As the minimum ellipse radius of support*1.0 the EWA algorithm
857        can only produce a minimum blur of 0.5 for Gaussian (support=2.0)
858        This means that even 'No Blur' will be still a little blurry!
859
860        The solution (as well as the problem of preventing any user
861        expert filter settings, is to set our own user settings, then
862        restore them afterwards.
863      */
864      resample_filter=AcquireResampleFilter(image,exception);
865      SetResampleFilter(resample_filter,GaussianFilter);
866
867      /* do the variable blurring of each pixel in image */
868      GetPixelInfo(image,&pixel);
869      source_view=AcquireVirtualCacheView(source_image,exception);
870      canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
871      for (y=0; y < (ssize_t) source_image->rows; y++)
872      {
873        MagickBooleanType
874          sync;
875
876        register const Quantum
877          *magick_restrict p;
878
879        register Quantum
880          *magick_restrict q;
881
882        register ssize_t
883          x;
884
885        if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
886          continue;
887        p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
888          exception);
889        q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
890          exception);
891        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
892          break;
893        for (x=0; x < (ssize_t) source_image->columns; x++)
894        {
895          if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
896            {
897              p+=GetPixelChannels(source_image);
898              continue;
899            }
900          if (fabs((double) angle_range) > MagickEpsilon)
901            {
902              MagickRealType
903                angle;
904
905              angle=angle_start+angle_range*QuantumScale*
906                GetPixelBlue(source_image,p);
907              blur.x1=width*cos(angle);
908              blur.x2=width*sin(angle);
909              blur.y1=(-height*sin(angle));
910              blur.y2=height*cos(angle);
911            }
912#if 0
913          if ( x == 10 && y == 60 ) {
914            (void) fprintf(stderr, "blur.x=%lf,%lf, blur.y=%lf,%lf\n",blur.x1,
915              blur.x2,blur.y1, blur.y2);
916            (void) fprintf(stderr, "scaled by=%lf,%lf\n",QuantumScale*
917              GetPixelRed(p),QuantumScale*GetPixelGreen(p));
918#endif
919          ScaleResampleFilter(resample_filter,
920            blur.x1*QuantumScale*GetPixelRed(source_image,p),
921            blur.y1*QuantumScale*GetPixelGreen(source_image,p),
922            blur.x2*QuantumScale*GetPixelRed(source_image,p),
923            blur.y2*QuantumScale*GetPixelGreen(source_image,p) );
924          (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
925            (double) y_offset+y,&pixel,exception);
926          SetPixelViaPixelInfo(canvas_image,&pixel,q);
927          p+=GetPixelChannels(source_image);
928          q+=GetPixelChannels(canvas_image);
929        }
930        sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
931        if (sync == MagickFalse)
932          break;
933      }
934      resample_filter=DestroyResampleFilter(resample_filter);
935      source_view=DestroyCacheView(source_view);
936      canvas_view=DestroyCacheView(canvas_view);
937      source_image=DestroyImage(source_image);
938      source_image=canvas_image;
939      break;
940    }
941    case DisplaceCompositeOp:
942    case DistortCompositeOp:
943    {
944      CacheView
945        *canvas_view;
946
947      MagickRealType
948        horizontal_scale,
949        vertical_scale;
950
951      PixelInfo
952        pixel;
953
954      PointInfo
955        center,
956        offset;
957
958      /*
959        Displace/Distort based on overlay gradient map:
960          X = red_channel;  Y = green_channel;
961          compose:args = x_scale[,y_scale[,center.x,center.y]]
962      */
963      canvas_image=CloneImage(image,image->columns,image->rows,MagickTrue,
964        exception);
965      if (canvas_image == (Image *) NULL)
966        {
967          source_image=DestroyImage(source_image);
968          return(MagickFalse);
969        }
970      SetGeometryInfo(&geometry_info);
971      flags=NoValue;
972      value=GetImageArtifact(image,"compose:args");
973      if (value != (char *) NULL)
974        flags=ParseGeometry(value,&geometry_info);
975      if ((flags & (WidthValue | HeightValue)) == 0 )
976        {
977          if ((flags & AspectValue) == 0)
978            {
979              horizontal_scale=(MagickRealType) (source_image->columns-1)/2.0;
980              vertical_scale=(MagickRealType) (source_image->rows-1)/2.0;
981            }
982          else
983            {
984              horizontal_scale=(MagickRealType) (image->columns-1)/2.0;
985              vertical_scale=(MagickRealType) (image->rows-1)/2.0;
986            }
987        }
988      else
989        {
990          horizontal_scale=geometry_info.rho;
991          vertical_scale=geometry_info.sigma;
992          if ((flags & PercentValue) != 0)
993            {
994              if ((flags & AspectValue) == 0)
995                {
996                  horizontal_scale*=(source_image->columns-1)/200.0;
997                  vertical_scale*=(source_image->rows-1)/200.0;
998                }
999              else
1000                {
1001                  horizontal_scale*=(image->columns-1)/200.0;
1002                  vertical_scale*=(image->rows-1)/200.0;
1003                }
1004            }
1005          if ((flags & HeightValue) == 0)
1006            vertical_scale=horizontal_scale;
1007        }
1008      /*
1009        Determine fixed center point for absolute distortion map
1010         Absolute distort ==
1011           Displace offset relative to a fixed absolute point
1012           Select that point according to +X+Y user inputs.
1013           default = center of overlay image
1014           arg flag '!' = locations/percentage relative to background image
1015      */
1016      center.x=(MagickRealType) x_offset;
1017      center.y=(MagickRealType) y_offset;
1018      if (compose == DistortCompositeOp)
1019        {
1020          if ((flags & XValue) == 0)
1021            if ((flags & AspectValue) != 0)
1022              center.x=(MagickRealType) ((image->columns-1)/2.0);
1023            else
1024              center.x=(MagickRealType) (x_offset+(source_image->columns-1)/
1025                2.0);
1026          else
1027            if ((flags & AspectValue) != 0)
1028              center.x=geometry_info.xi;
1029            else
1030              center.x=(MagickRealType) (x_offset+geometry_info.xi);
1031          if ((flags & YValue) == 0)
1032            if ((flags & AspectValue) != 0)
1033              center.y=(MagickRealType) ((image->rows-1)/2.0);
1034            else
1035              center.y=(MagickRealType) (y_offset+(source_image->rows-1)/2.0);
1036          else
1037            if ((flags & AspectValue) != 0)
1038              center.y=geometry_info.psi;
1039            else
1040              center.y=(MagickRealType) (y_offset+geometry_info.psi);
1041        }
1042      /*
1043        Shift the pixel offset point as defined by the provided,
1044        displacement/distortion map.  -- Like a lens...
1045      */
1046      GetPixelInfo(image,&pixel);
1047      image_view=AcquireVirtualCacheView(image,exception);
1048      source_view=AcquireVirtualCacheView(source_image,exception);
1049      canvas_view=AcquireAuthenticCacheView(canvas_image,exception);
1050      for (y=0; y < (ssize_t) source_image->rows; y++)
1051      {
1052        MagickBooleanType
1053          sync;
1054
1055        register const Quantum
1056          *magick_restrict p;
1057
1058        register Quantum
1059          *magick_restrict q;
1060
1061        register ssize_t
1062          x;
1063
1064        if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1065          continue;
1066        p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
1067          exception);
1068        q=QueueCacheViewAuthenticPixels(canvas_view,0,y,canvas_image->columns,1,
1069          exception);
1070        if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1071          break;
1072        for (x=0; x < (ssize_t) source_image->columns; x++)
1073        {
1074          if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1075            {
1076              p+=GetPixelChannels(source_image);
1077              continue;
1078            }
1079          /*
1080            Displace the offset.
1081          */
1082          offset.x=(double) (horizontal_scale*(GetPixelRed(source_image,p)-
1083            (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1084            QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
1085            x : 0);
1086          offset.y=(double) (vertical_scale*(GetPixelGreen(source_image,p)-
1087            (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
1088            QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
1089            y : 0);
1090          (void) InterpolatePixelInfo(image,image_view,
1091            UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
1092            &pixel,exception);
1093          /*
1094            Mask with the 'invalid pixel mask' in alpha channel.
1095          */
1096          pixel.alpha=(MagickRealType) QuantumRange*(QuantumScale*pixel.alpha)*
1097            (QuantumScale*GetPixelAlpha(source_image,p));
1098          SetPixelViaPixelInfo(canvas_image,&pixel,q);
1099          p+=GetPixelChannels(source_image);
1100          q+=GetPixelChannels(canvas_image);
1101        }
1102        sync=SyncCacheViewAuthenticPixels(canvas_view,exception);
1103        if (sync == MagickFalse)
1104          break;
1105      }
1106      canvas_view=DestroyCacheView(canvas_view);
1107      source_view=DestroyCacheView(source_view);
1108      image_view=DestroyCacheView(image_view);
1109      source_image=DestroyImage(source_image);
1110      source_image=canvas_image;
1111      break;
1112    }
1113    case DissolveCompositeOp:
1114    {
1115      /*
1116        Geometry arguments to dissolve factors.
1117      */
1118      value=GetImageArtifact(image,"compose:args");
1119      if (value != (char *) NULL)
1120        {
1121          flags=ParseGeometry(value,&geometry_info);
1122          source_dissolve=geometry_info.rho/100.0;
1123          canvas_dissolve=1.0;
1124          if ((source_dissolve-MagickEpsilon) < 0.0)
1125            source_dissolve=0.0;
1126          if ((source_dissolve+MagickEpsilon) > 1.0)
1127            {
1128              canvas_dissolve=2.0-source_dissolve;
1129              source_dissolve=1.0;
1130            }
1131          if ((flags & SigmaValue) != 0)
1132            canvas_dissolve=geometry_info.sigma/100.0;
1133          if ((canvas_dissolve-MagickEpsilon) < 0.0)
1134            canvas_dissolve=0.0;
1135        }
1136      break;
1137    }
1138    case BlendCompositeOp:
1139    {
1140      value=GetImageArtifact(image,"compose:args");
1141      if (value != (char *) NULL)
1142        {
1143          flags=ParseGeometry(value,&geometry_info);
1144          source_dissolve=geometry_info.rho/100.0;
1145          canvas_dissolve=1.0-source_dissolve;
1146          if ((flags & SigmaValue) != 0)
1147            canvas_dissolve=geometry_info.sigma/100.0;
1148        }
1149      break;
1150    }
1151    case MathematicsCompositeOp:
1152    {
1153      /*
1154        Just collect the values from "compose:args", setting.
1155        Unused values are set to zero automagically.
1156
1157        Arguments are normally a comma separated list, so this probably should
1158        be changed to some 'general comma list' parser, (with a minimum
1159        number of values)
1160      */
1161      SetGeometryInfo(&geometry_info);
1162      value=GetImageArtifact(image,"compose:args");
1163      if (value != (char *) NULL)
1164        (void) ParseGeometry(value,&geometry_info);
1165      break;
1166    }
1167    case ModulateCompositeOp:
1168    {
1169      /*
1170        Determine the luma and chroma scale.
1171      */
1172      value=GetImageArtifact(image,"compose:args");
1173      if (value != (char *) NULL)
1174        {
1175          flags=ParseGeometry(value,&geometry_info);
1176          percent_luma=geometry_info.rho;
1177          if ((flags & SigmaValue) != 0)
1178            percent_chroma=geometry_info.sigma;
1179        }
1180      break;
1181    }
1182    case ThresholdCompositeOp:
1183    {
1184      /*
1185        Determine the amount and threshold.
1186      */
1187      value=GetImageArtifact(image,"compose:args");
1188      if (value != (char *) NULL)
1189        {
1190          flags=ParseGeometry(value,&geometry_info);
1191          amount=geometry_info.rho;
1192          threshold=geometry_info.sigma;
1193          if ((flags & SigmaValue) == 0)
1194            threshold=0.05f;
1195        }
1196      threshold*=QuantumRange;
1197      break;
1198    }
1199    default:
1200      break;
1201  }
1202  /*
1203    Composite image.
1204  */
1205  status=MagickTrue;
1206  progress=0;
1207  midpoint=((MagickRealType) QuantumRange+1.0)/2;
1208  source_view=AcquireVirtualCacheView(source_image,exception);
1209  image_view=AcquireAuthenticCacheView(image,exception);
1210#if defined(MAGICKCORE_OPENMP_SUPPORT)
1211  #pragma omp parallel for schedule(static,4) shared(progress,status) \
1212    magick_threads(source_image,image,image->rows,1)
1213#endif
1214  for (y=0; y < (ssize_t) image->rows; y++)
1215  {
1216    const Quantum
1217      *pixels;
1218
1219    MagickRealType
1220      blue,
1221      chroma,
1222      green,
1223      hue,
1224      luma,
1225      red;
1226
1227    PixelInfo
1228      canvas_pixel,
1229      source_pixel;
1230
1231    register const Quantum
1232      *magick_restrict p;
1233
1234    register Quantum
1235      *magick_restrict q;
1236
1237    register ssize_t
1238      x;
1239
1240    if (status == MagickFalse)
1241      continue;
1242    if (clip_to_self != MagickFalse)
1243      {
1244        if (y < y_offset)
1245          continue;
1246        if ((y-y_offset) >= (ssize_t) source_image->rows)
1247          continue;
1248      }
1249    /*
1250      If pixels is NULL, y is outside overlay region.
1251    */
1252    pixels=(Quantum *) NULL;
1253    p=(Quantum *) NULL;
1254    if ((y >= y_offset) && ((y-y_offset) < (ssize_t) source_image->rows))
1255      {
1256        p=GetCacheViewVirtualPixels(source_view,0,y-y_offset,
1257          source_image->columns,1,exception);
1258        if (p == (const Quantum *) NULL)
1259          {
1260            status=MagickFalse;
1261            continue;
1262          }
1263        pixels=p;
1264        if (x_offset < 0)
1265          p-=x_offset*GetPixelChannels(source_image);
1266      }
1267    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1268    if (q == (Quantum *) NULL)
1269      {
1270        status=MagickFalse;
1271        continue;
1272      }
1273    hue=0.0;
1274    chroma=0.0;
1275    luma=0.0;
1276    GetPixelInfo(image,&canvas_pixel);
1277    GetPixelInfo(source_image,&source_pixel);
1278    for (x=0; x < (ssize_t) image->columns; x++)
1279    {
1280      double
1281        gamma;
1282
1283      MagickRealType
1284        alpha,
1285        Da,
1286        Dc,
1287        Dca,
1288        Sa,
1289        Sc,
1290        Sca;
1291
1292      register ssize_t
1293        i;
1294
1295      size_t
1296        channels;
1297
1298      if (clip_to_self != MagickFalse)
1299        {
1300          if (x < x_offset)
1301            {
1302              q+=GetPixelChannels(image);
1303              continue;
1304            }
1305          if ((x-x_offset) >= (ssize_t) source_image->columns)
1306            break;
1307        }
1308      if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
1309          ((x-x_offset) >= (ssize_t) source_image->columns))
1310        {
1311          Quantum
1312            source[MaxPixelChannels];
1313
1314          /*
1315            Virtual composite:
1316              Sc: source color.
1317              Dc: canvas color.
1318          */
1319          (void) GetOneVirtualPixel(source_image,x-x_offset,y-y_offset,source,
1320            exception);
1321          if (GetPixelReadMask(image,q) == 0)
1322            {
1323              q+=GetPixelChannels(image);
1324              continue;
1325            }
1326          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1327          {
1328            MagickRealType
1329              pixel;
1330
1331            PixelChannel channel=GetPixelChannelChannel(image,i);
1332            PixelTrait traits=GetPixelChannelTraits(image,channel);
1333            PixelTrait source_traits=GetPixelChannelTraits(source_image,
1334              channel);
1335            if ((traits == UndefinedPixelTrait) ||
1336                (source_traits == UndefinedPixelTrait))
1337              continue;
1338            switch (compose)
1339            {
1340              case AlphaCompositeOp:
1341              case ChangeMaskCompositeOp:
1342              case CopyAlphaCompositeOp:
1343              case DstAtopCompositeOp:
1344              case DstInCompositeOp:
1345              case InCompositeOp:
1346              case OutCompositeOp:
1347              case SrcInCompositeOp:
1348              case SrcOutCompositeOp:
1349              {
1350                if (channel == AlphaPixelChannel)
1351                  pixel=(MagickRealType) TransparentAlpha;
1352                else
1353                  pixel=(MagickRealType) q[i];
1354                break;
1355              }
1356              case ClearCompositeOp:
1357              case CopyCompositeOp:
1358              case ReplaceCompositeOp:
1359              case SrcCompositeOp:
1360              {
1361                if (channel == AlphaPixelChannel)
1362                  pixel=(MagickRealType) TransparentAlpha;
1363                else
1364                  pixel=0.0;
1365                break;
1366              }
1367              case BlendCompositeOp:
1368              case DissolveCompositeOp:
1369              {
1370                if (channel == AlphaPixelChannel)
1371                  pixel=canvas_dissolve*GetPixelAlpha(source_image,source);
1372                else
1373                  pixel=(MagickRealType) source[channel];
1374                break;
1375              }
1376              default:
1377              {
1378                pixel=(MagickRealType) source[channel];
1379                break;
1380              }
1381            }
1382            q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1383              ClampToQuantum(pixel);
1384          }
1385          q+=GetPixelChannels(image);
1386          continue;
1387        }
1388      /*
1389        Authentic composite:
1390          Sa:  normalized source alpha.
1391          Da:  normalized canvas alpha.
1392      */
1393      Sa=QuantumScale*GetPixelAlpha(source_image,p);
1394      Da=QuantumScale*GetPixelAlpha(image,q);
1395      switch (compose)
1396      {
1397        case BumpmapCompositeOp:
1398        {
1399          alpha=GetPixelIntensity(source_image,p)*Sa;
1400          break;
1401        }
1402        case ColorBurnCompositeOp:
1403        case ColorDodgeCompositeOp:
1404        case DarkenCompositeOp:
1405        case DifferenceCompositeOp:
1406        case DivideDstCompositeOp:
1407        case DivideSrcCompositeOp:
1408        case ExclusionCompositeOp:
1409        case HardLightCompositeOp:
1410        case HardMixCompositeOp:
1411        case LinearBurnCompositeOp:
1412        case LinearDodgeCompositeOp:
1413        case LinearLightCompositeOp:
1414        case LightenCompositeOp:
1415        case MathematicsCompositeOp:
1416        case MinusDstCompositeOp:
1417        case MinusSrcCompositeOp:
1418        case ModulusAddCompositeOp:
1419        case ModulusSubtractCompositeOp:
1420        case MultiplyCompositeOp:
1421        case OverlayCompositeOp:
1422        case PegtopLightCompositeOp:
1423        case PinLightCompositeOp:
1424        case ScreenCompositeOp:
1425        case SoftLightCompositeOp:
1426        case VividLightCompositeOp:
1427        {
1428          alpha=RoundToUnity(Sa+Da-Sa*Da);
1429          break;
1430        }
1431        case DstAtopCompositeOp:
1432        case DstInCompositeOp:
1433        case InCompositeOp:
1434        case SrcInCompositeOp:
1435        {
1436          alpha=Sa*Da;
1437          break;
1438        }
1439        case DissolveCompositeOp:
1440        {
1441          alpha=source_dissolve*Sa*(-canvas_dissolve*Da)+source_dissolve*Sa+
1442            canvas_dissolve*Da;
1443          break;
1444        }
1445        case DstOverCompositeOp:
1446        case OverCompositeOp:
1447        case SrcOverCompositeOp:
1448        {
1449          alpha=Sa+Da-Sa*Da;
1450          break;
1451        }
1452        case DstOutCompositeOp:
1453        {
1454          alpha=Da*(1.0-Sa);
1455          break;
1456        }
1457        case OutCompositeOp:
1458        case SrcOutCompositeOp:
1459        {
1460          alpha=Sa*(1.0-Da);
1461          break;
1462        }
1463        case BlendCompositeOp:
1464        case PlusCompositeOp:
1465        {
1466          alpha=RoundToUnity(source_dissolve*Sa+canvas_dissolve*Da);
1467          break;
1468        }
1469        case XorCompositeOp:
1470        {
1471          alpha=Sa+Da-2.0*Sa*Da;
1472          break;
1473        }
1474        default:
1475        {
1476          alpha=1.0;
1477          break;
1478        }
1479      }
1480      if (GetPixelReadMask(image,q) == 0)
1481        {
1482          p+=GetPixelChannels(source_image);
1483          q+=GetPixelChannels(image);
1484          continue;
1485        }
1486      switch (compose)
1487      {
1488        case ColorizeCompositeOp:
1489        case HueCompositeOp:
1490        case LuminizeCompositeOp:
1491        case ModulateCompositeOp:
1492        case SaturateCompositeOp:
1493        {
1494          GetPixelInfoPixel(source_image,p,&source_pixel);
1495          GetPixelInfoPixel(image,q,&canvas_pixel);
1496          break;
1497        }
1498        default:
1499          break;
1500      }
1501      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1502      {
1503        MagickRealType
1504          pixel,
1505          sans;
1506
1507        PixelChannel channel=GetPixelChannelChannel(image,i);
1508        PixelTrait traits=GetPixelChannelTraits(image,channel);
1509        PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1510        if (traits == UndefinedPixelTrait)
1511          continue;
1512        if ((source_traits == UndefinedPixelTrait) &&
1513             (((compose != CopyAlphaCompositeOp) &&
1514               (compose != ChangeMaskCompositeOp)) ||
1515               (channel != AlphaPixelChannel)))
1516            continue;
1517        /*
1518          Sc: source color.
1519          Dc: canvas color.
1520        */
1521        Sc=(MagickRealType) GetPixelChannel(source_image,channel,p);
1522        Dc=(MagickRealType) q[i];
1523        if ((traits & CopyPixelTrait) != 0)
1524          {
1525            /*
1526              Copy channel.
1527            */
1528            q[i]=Sc;
1529            continue;
1530          }
1531        if (channel == AlphaPixelChannel)
1532          {
1533            /*
1534              Set alpha channel.
1535            */
1536            switch (compose)
1537            {
1538              case AlphaCompositeOp:
1539              {
1540                pixel=QuantumRange*Sa;
1541                break;
1542              }
1543              case AtopCompositeOp:
1544              case CopyBlackCompositeOp:
1545              case CopyBlueCompositeOp:
1546              case CopyCyanCompositeOp:
1547              case CopyGreenCompositeOp:
1548              case CopyMagentaCompositeOp:
1549              case CopyRedCompositeOp:
1550              case CopyYellowCompositeOp:
1551              case SrcAtopCompositeOp:
1552              case DstCompositeOp:
1553              case NoCompositeOp:
1554              {
1555                pixel=QuantumRange*Da;
1556                break;
1557              }
1558              case ChangeMaskCompositeOp:
1559              {
1560                MagickBooleanType
1561                  equivalent;
1562
1563                if (Da < 0.5)
1564                  {
1565                    pixel=(MagickRealType) TransparentAlpha;
1566                    break;
1567                  }
1568                equivalent=IsFuzzyEquivalencePixel(source_image,p,image,q);
1569                if (equivalent != MagickFalse)
1570                  pixel=(MagickRealType) TransparentAlpha;
1571                else
1572                  pixel=(MagickRealType) OpaqueAlpha;
1573                break;
1574              }
1575              case ClearCompositeOp:
1576              {
1577                pixel=(MagickRealType) TransparentAlpha;
1578                break;
1579              }
1580              case ColorizeCompositeOp:
1581              case HueCompositeOp:
1582              case LuminizeCompositeOp:
1583              case SaturateCompositeOp:
1584              {
1585                if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1586                  {
1587                    pixel=QuantumRange*Da;
1588                    break;
1589                  }
1590                if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1591                  {
1592                    pixel=QuantumRange*Sa;
1593                    break;
1594                  }
1595                if (Sa < Da)
1596                  {
1597                    pixel=QuantumRange*Da;
1598                    break;
1599                  }
1600                pixel=QuantumRange*Sa;
1601                break;
1602              }
1603              case CopyAlphaCompositeOp:
1604              {
1605                if ((source_traits & BlendPixelTrait) == 0)
1606                  pixel=GetPixelIntensity(source_image,p);
1607                else
1608                  pixel=QuantumRange*Sa;
1609                break;
1610              }
1611              case CopyCompositeOp:
1612              case DisplaceCompositeOp:
1613              case DistortCompositeOp:
1614              case DstAtopCompositeOp:
1615              case ReplaceCompositeOp:
1616              case SrcCompositeOp:
1617              {
1618                pixel=QuantumRange*Sa;
1619                break;
1620              }
1621              case DarkenIntensityCompositeOp:
1622              {
1623                pixel=Sa*GetPixelIntensity(source_image,p) <
1624                  Da*GetPixelIntensity(image,q) ? Sa : Da;
1625                break;
1626              }
1627              case LightenIntensityCompositeOp:
1628              {
1629                pixel=Sa*GetPixelIntensity(source_image,p) >
1630                  Da*GetPixelIntensity(image,q) ? Sa : Da;
1631                break;
1632              }
1633              case ModulateCompositeOp:
1634              {
1635                pixel=QuantumRange*Da;
1636                break;
1637              }
1638              default:
1639              {
1640                pixel=QuantumRange*alpha;
1641                break;
1642              }
1643            }
1644            q[i]=clamp != MagickFalse ? ClampPixel(pixel) :
1645              ClampToQuantum(pixel);
1646            continue;
1647          }
1648        /*
1649          Porter-Duff compositions:
1650            Sca: source normalized color multiplied by alpha.
1651            Dca: normalized canvas color multiplied by alpha.
1652        */
1653        Sca=QuantumScale*Sa*Sc;
1654        Dca=QuantumScale*Da*Dc;
1655        switch (compose)
1656        {
1657          case DarkenCompositeOp:
1658          case LightenCompositeOp:
1659          case ModulusSubtractCompositeOp:
1660          {
1661            gamma=PerceptibleReciprocal(1.0-alpha);
1662            break;
1663          }
1664          default:
1665          {
1666            gamma=PerceptibleReciprocal(alpha);
1667            break;
1668          }
1669        }
1670        pixel=Dc;
1671        switch (compose)
1672        {
1673          case AlphaCompositeOp:
1674          {
1675            pixel=QuantumRange*Sa;
1676            break;
1677          }
1678          case AtopCompositeOp:
1679          case SrcAtopCompositeOp:
1680          {
1681            pixel=QuantumRange*(Sca*Da+Dca*(1.0-Sa));
1682            break;
1683          }
1684          case BlendCompositeOp:
1685          {
1686            pixel=gamma*(source_dissolve*Sa*Sc+canvas_dissolve*Da*Dc);
1687            break;
1688          }
1689          case BlurCompositeOp:
1690          case CopyCompositeOp:
1691          case ReplaceCompositeOp:
1692          case SrcCompositeOp:
1693          {
1694            pixel=QuantumRange*Sca;
1695            break;
1696          }
1697          case DisplaceCompositeOp:
1698          case DistortCompositeOp:
1699          {
1700            pixel=Sc;
1701            break;
1702          }
1703          case BumpmapCompositeOp:
1704          {
1705            if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1706              {
1707                pixel=Dc;
1708                break;
1709              }
1710            pixel=QuantumScale*GetPixelIntensity(source_image,p)*Dc;
1711            break;
1712          }
1713          case ChangeMaskCompositeOp:
1714          {
1715            pixel=Dc;
1716            break;
1717          }
1718          case ClearCompositeOp:
1719          {
1720            pixel=0.0;
1721            break;
1722          }
1723          case ColorBurnCompositeOp:
1724          {
1725            if ((Sca == 0.0) && (Dca == Da))
1726              {
1727                pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1728                break;
1729              }
1730            if (Sca == 0.0)
1731              {
1732                pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1733                break;
1734              }
1735            pixel=QuantumRange*gamma*(Sa*Da-Sa*Da*MagickMin(1.0,(1.0-Dca/Da)*Sa/
1736              Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
1737            break;
1738          }
1739          case ColorDodgeCompositeOp:
1740          {
1741            if ((Sca*Da+Dca*Sa) >= Sa*Da)
1742              pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1743            else
1744              pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1745                (1.0-Sa));
1746            break;
1747          }
1748          case ColorizeCompositeOp:
1749          {
1750            if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1751              {
1752                pixel=Dc;
1753                break;
1754              }
1755            if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1756              {
1757                pixel=Sc;
1758                break;
1759              }
1760            CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1761              &sans,&sans,&luma);
1762            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1763              &hue,&chroma,&sans);
1764            HCLComposite(hue,chroma,luma,&red,&green,&blue);
1765            switch (channel)
1766            {
1767              case RedPixelChannel: pixel=red; break;
1768              case GreenPixelChannel: pixel=green; break;
1769              case BluePixelChannel: pixel=blue; break;
1770              default: pixel=Dc; break;
1771            }
1772            break;
1773          }
1774          case CopyAlphaCompositeOp:
1775          {
1776            pixel=Dc;
1777            break;
1778          }
1779          case CopyBlackCompositeOp:
1780          {
1781            if (channel == BlackPixelChannel)
1782              pixel=(MagickRealType) (QuantumRange-
1783                GetPixelBlack(source_image,p));
1784            break;
1785          }
1786          case CopyBlueCompositeOp:
1787          case CopyYellowCompositeOp:
1788          {
1789            if (channel == BluePixelChannel)
1790              pixel=(MagickRealType) GetPixelBlue(source_image,p);
1791            break;
1792          }
1793          case CopyGreenCompositeOp:
1794          case CopyMagentaCompositeOp:
1795          {
1796            if (channel == GreenPixelChannel)
1797              pixel=(MagickRealType) GetPixelGreen(source_image,p);
1798            break;
1799          }
1800          case CopyRedCompositeOp:
1801          case CopyCyanCompositeOp:
1802          {
1803            if (channel == RedPixelChannel)
1804              pixel=(MagickRealType) GetPixelRed(source_image,p);
1805            break;
1806          }
1807          case DarkenCompositeOp:
1808          {
1809            /*
1810              Darken is equivalent to a 'Minimum' method
1811                OR a greyscale version of a binary 'Or'
1812                OR the 'Intersection' of pixel sets.
1813            */
1814            if ((Sca*Da) < (Dca*Sa))
1815              {
1816                pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1817                break;
1818              }
1819            pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1820            break;
1821          }
1822          case DarkenIntensityCompositeOp:
1823          {
1824            pixel=Sa*GetPixelIntensity(source_image,p) <
1825              Da*GetPixelIntensity(image,q) ? Sc : Dc;
1826            break;
1827          }
1828          case DifferenceCompositeOp:
1829          {
1830            pixel=QuantumRange*gamma*(Sca+Dca-2.0*MagickMin(Sca*Da,Dca*Sa));
1831            break;
1832          }
1833          case DissolveCompositeOp:
1834          {
1835            pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1836              canvas_dissolve*Da*Dc+canvas_dissolve*Da*Dc);
1837            break;
1838          }
1839          case DivideDstCompositeOp:
1840          {
1841            if ((fabs((double) Sca) < MagickEpsilon) &&
1842                (fabs((double) Dca) < MagickEpsilon))
1843              {
1844                pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1845                break;
1846              }
1847            if (fabs((double) Dca) < MagickEpsilon)
1848              {
1849                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1850                break;
1851              }
1852            pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1853            break;
1854          }
1855          case DivideSrcCompositeOp:
1856          {
1857            if ((fabs((double) Dca) < MagickEpsilon) &&
1858                (fabs((double) Sca) < MagickEpsilon))
1859              {
1860                pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1861                break;
1862              }
1863            if (fabs((double) Sca) < MagickEpsilon)
1864              {
1865                pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1866                break;
1867              }
1868            pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1869            break;
1870          }
1871          case DstAtopCompositeOp:
1872          {
1873            pixel=QuantumRange*(Dca*Sa+Sca*(1.0-Da));
1874            break;
1875          }
1876          case DstCompositeOp:
1877          case NoCompositeOp:
1878          {
1879            pixel=QuantumRange*Dca;
1880            break;
1881          }
1882          case DstInCompositeOp:
1883          {
1884            pixel=QuantumRange*(Dca*Sa);
1885            break;
1886          }
1887          case DstOutCompositeOp:
1888          {
1889            pixel=QuantumRange*(Dca*(1.0-Sa));
1890            break;
1891          }
1892          case DstOverCompositeOp:
1893          {
1894            pixel=QuantumRange*gamma*(Dca+Sca*(1.0-Da));
1895            break;
1896          }
1897          case ExclusionCompositeOp:
1898          {
1899            pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1900              Dca*(1.0-Sa));
1901            break;
1902          }
1903          case HardLightCompositeOp:
1904          {
1905            if ((2.0*Sca) < Sa)
1906              {
1907                pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-
1908                  Sa));
1909                break;
1910              }
1911            pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1912              Dca*(1.0-Sa));
1913            break;
1914          }
1915          case HardMixCompositeOp:
1916          {
1917            pixel=gamma*(((Sca+Dca) < 1.0) ? 0.0 : QuantumRange);
1918            break;
1919          }
1920          case HueCompositeOp:
1921          {
1922            if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
1923              {
1924                pixel=Dc;
1925                break;
1926              }
1927            if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
1928              {
1929                pixel=Sc;
1930                break;
1931              }
1932            CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
1933              &hue,&chroma,&luma);
1934            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1935              &hue,&sans,&sans);
1936            HCLComposite(hue,chroma,luma,&red,&green,&blue);
1937            switch (channel)
1938            {
1939              case RedPixelChannel: pixel=red; break;
1940              case GreenPixelChannel: pixel=green; break;
1941              case BluePixelChannel: pixel=blue; break;
1942              default: pixel=Dc; break;
1943            }
1944            break;
1945          }
1946          case InCompositeOp:
1947          case SrcInCompositeOp:
1948          {
1949            pixel=QuantumRange*(Sca*Da);
1950            break;
1951          }
1952          case LinearBurnCompositeOp:
1953          {
1954            /*
1955              LinearBurn: as defined by Abode Photoshop, according to
1956              http://www.simplefilter.de/en/basics/mixmods.html is:
1957
1958                f(Sc,Dc) = Sc + Dc - 1
1959            */
1960            pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1961            break;
1962          }
1963          case LinearDodgeCompositeOp:
1964          {
1965            pixel=gamma*(Sa*Sc+Da*Dc);
1966            break;
1967          }
1968          case LinearLightCompositeOp:
1969          {
1970            /*
1971              LinearLight: as defined by Abode Photoshop, according to
1972              http://www.simplefilter.de/en/basics/mixmods.html is:
1973
1974                f(Sc,Dc) = Dc + 2*Sc - 1
1975            */
1976            pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1977            break;
1978          }
1979          case LightenCompositeOp:
1980          {
1981            if ((Sca*Da) > (Dca*Sa))
1982              {
1983                pixel=QuantumRange*(Sca+Dca*(1.0-Sa));
1984                break;
1985              }
1986            pixel=QuantumRange*(Dca+Sca*(1.0-Da));
1987            break;
1988          }
1989          case LightenIntensityCompositeOp:
1990          {
1991            /*
1992              Lighten is equivalent to a 'Maximum' method
1993                OR a greyscale version of a binary 'And'
1994                OR the 'Union' of pixel sets.
1995            */
1996            pixel=Sa*GetPixelIntensity(source_image,p) >
1997              Da*GetPixelIntensity(image,q) ? Sc : Dc;
1998            break;
1999          }
2000          case LuminizeCompositeOp:
2001          {
2002            if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2003              {
2004                pixel=Dc;
2005                break;
2006              }
2007            if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2008              {
2009                pixel=Sc;
2010                break;
2011              }
2012            CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2013              &hue,&chroma,&luma);
2014            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2015              &sans,&sans,&luma);
2016            HCLComposite(hue,chroma,luma,&red,&green,&blue);
2017            switch (channel)
2018            {
2019              case RedPixelChannel: pixel=red; break;
2020              case GreenPixelChannel: pixel=green; break;
2021              case BluePixelChannel: pixel=blue; break;
2022              default: pixel=Dc; break;
2023            }
2024            break;
2025          }
2026          case MathematicsCompositeOp:
2027          {
2028            /*
2029              'Mathematics' a free form user control mathematical composition
2030              is defined as...
2031
2032                f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2033
2034              Where the arguments A,B,C,D are (currently) passed to composite
2035              as a command separated 'geometry' string in "compose:args" image
2036              artifact.
2037
2038                 A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
2039
2040              Applying the SVG transparency formula (see above), we get...
2041
2042               Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2043
2044               Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2045                 Dca*(1.0-Sa)
2046            */
2047            pixel=QuantumRange*gamma*(geometry_info.rho*Sca*Dca+
2048              geometry_info.sigma*Sca*Da+geometry_info.xi*Dca*Sa+
2049              geometry_info.psi*Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2050            break;
2051          }
2052          case MinusDstCompositeOp:
2053          {
2054            pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2055            break;
2056          }
2057          case MinusSrcCompositeOp:
2058          {
2059            /*
2060              Minus source from canvas.
2061
2062                f(Sc,Dc) = Sc - Dc
2063            */
2064            pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2065            break;
2066          }
2067          case ModulateCompositeOp:
2068          {
2069            ssize_t
2070              offset;
2071
2072            if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2073              {
2074                pixel=Dc;
2075                break;
2076              }
2077            offset=(ssize_t) (GetPixelIntensity(source_image,p)-midpoint);
2078            if (offset == 0)
2079              {
2080                pixel=Dc;
2081                break;
2082              }
2083            CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2084              &hue,&chroma,&luma);
2085            luma+=(0.01*percent_luma*offset)/midpoint;
2086            chroma*=0.01*percent_chroma;
2087            HCLComposite(hue,chroma,luma,&red,&green,&blue);
2088            switch (channel)
2089            {
2090              case RedPixelChannel: pixel=red; break;
2091              case GreenPixelChannel: pixel=green; break;
2092              case BluePixelChannel: pixel=blue; break;
2093              default: pixel=Dc; break;
2094            }
2095            break;
2096          }
2097          case ModulusAddCompositeOp:
2098          {
2099            pixel=Sc+Dc;
2100            while (pixel > QuantumRange)
2101              pixel-=QuantumRange;
2102            while (pixel < 0.0)
2103              pixel+=QuantumRange;
2104            pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2105            break;
2106          }
2107          case ModulusSubtractCompositeOp:
2108          {
2109            pixel=Sc-Dc;
2110            while (pixel > QuantumRange)
2111              pixel-=QuantumRange;
2112            while (pixel < 0.0)
2113              pixel+=QuantumRange;
2114            pixel=(Sa*Da*pixel+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2115            break;
2116          }
2117          case MultiplyCompositeOp:
2118          {
2119            pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2120            break;
2121          }
2122          case OutCompositeOp:
2123          case SrcOutCompositeOp:
2124          {
2125            pixel=QuantumRange*(Sca*(1.0-Da));
2126            break;
2127          }
2128          case OverCompositeOp:
2129          case SrcOverCompositeOp:
2130          {
2131            pixel=QuantumRange*gamma*(Sca+Dca*(1.0-Sa));
2132            break;
2133          }
2134          case OverlayCompositeOp:
2135          {
2136            if ((2.0*Dca) < Da)
2137              {
2138                pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*(1.0-
2139                  Da));
2140                break;
2141              }
2142            pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2143              Sca*(1.0-Da));
2144            break;
2145          }
2146          case PegtopLightCompositeOp:
2147          {
2148            /*
2149              PegTop: A Soft-Light alternative: A continuous version of the
2150              Softlight function, producing very similar results.
2151
2152                f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2153
2154              http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2155            */
2156            if (fabs((double) Da) < MagickEpsilon)
2157              {
2158                pixel=QuantumRange*gamma*(Sca);
2159                break;
2160              }
2161            pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2162              Da)+Dca*(1.0-Sa));
2163            break;
2164          }
2165          case PinLightCompositeOp:
2166          {
2167            /*
2168              PinLight: A Photoshop 7 composition method
2169              http://www.simplefilter.de/en/basics/mixmods.html
2170
2171                f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
2172            */
2173            if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2174              {
2175                pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2176                break;
2177              }
2178            if ((Dca*Sa) > (2.0*Sca*Da))
2179              {
2180                pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2181                break;
2182              }
2183            pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2184            break;
2185          }
2186          case PlusCompositeOp:
2187          {
2188            pixel=QuantumRange*(Sca+Dca);
2189            break;
2190          }
2191          case SaturateCompositeOp:
2192          {
2193            if (fabs((double) (QuantumRange*Sa-TransparentAlpha)) < MagickEpsilon)
2194              {
2195                pixel=Dc;
2196                break;
2197              }
2198            if (fabs((double) (QuantumRange*Da-TransparentAlpha)) < MagickEpsilon)
2199              {
2200                pixel=Sc;
2201                break;
2202              }
2203            CompositeHCL(canvas_pixel.red,canvas_pixel.green,canvas_pixel.blue,
2204              &hue,&chroma,&luma);
2205            CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2206              &sans,&chroma,&sans);
2207            HCLComposite(hue,chroma,luma,&red,&green,&blue);
2208            switch (channel)
2209            {
2210              case RedPixelChannel: pixel=red; break;
2211              case GreenPixelChannel: pixel=green; break;
2212              case BluePixelChannel: pixel=blue; break;
2213              default: pixel=Dc; break;
2214            }
2215            break;
2216          }
2217          case ScreenCompositeOp:
2218          {
2219            /*
2220              Screen:  a negated multiply:
2221
2222                f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2223            */
2224            pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2225            break;
2226          }
2227          case SoftLightCompositeOp:
2228          {
2229            if ((2.0*Sca) < Sa)
2230              {
2231                pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2232                  Sca*(1.0-Da)+Dca*(1.0-Sa));
2233                break;
2234              }
2235            if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2236              {
2237                pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2238                  (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2239                  Dca*(1.0-Sa));
2240                break;
2241              }
2242            pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2243              (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2244            break;
2245          }
2246          case ThresholdCompositeOp:
2247          {
2248            MagickRealType
2249              delta;
2250
2251            delta=Sc-Dc;
2252            if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2253              {
2254                pixel=gamma*Dc;
2255                break;
2256              }
2257            pixel=gamma*(Dc+delta*amount);
2258            break;
2259          }
2260          case VividLightCompositeOp:
2261          {
2262            /*
2263              VividLight: A Photoshop 7 composition method.  See
2264              http://www.simplefilter.de/en/basics/mixmods.html.
2265
2266                f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2267            */
2268            if ((fabs((double) Sa) < MagickEpsilon) ||
2269                (fabs((double) (Sca-Sa)) < MagickEpsilon))
2270              {
2271                pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2272                break;
2273              }
2274            if ((2.0*Sca) <= Sa)
2275              {
2276                pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2277                  (1.0-Da)+Dca*(1.0-Sa));
2278                break;
2279              }
2280            pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*
2281              (1.0-Sa));
2282            break;
2283          }
2284          case XorCompositeOp:
2285          {
2286            pixel=QuantumRange*(Sca*(1.0-Da)+Dca*(1.0-Sa));
2287            break;
2288          }
2289          default:
2290          {
2291            pixel=Sc;
2292            break;
2293          }
2294        }
2295        q[i]=clamp != MagickFalse ? ClampPixel(pixel) : ClampToQuantum(pixel);
2296      }
2297      p+=GetPixelChannels(source_image);
2298      channels=GetPixelChannels(source_image);
2299      if (p >= (pixels+channels*source_image->columns))
2300        p=pixels;
2301      q+=GetPixelChannels(image);
2302    }
2303    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2304      status=MagickFalse;
2305    if (image->progress_monitor != (MagickProgressMonitor) NULL)
2306      {
2307        MagickBooleanType
2308          proceed;
2309
2310#if defined(MAGICKCORE_OPENMP_SUPPORT)
2311        #pragma omp critical (MagickCore_CompositeImage)
2312#endif
2313        proceed=SetImageProgress(image,CompositeImageTag,progress++,
2314          image->rows);
2315        if (proceed == MagickFalse)
2316          status=MagickFalse;
2317      }
2318  }
2319  source_view=DestroyCacheView(source_view);
2320  image_view=DestroyCacheView(image_view);
2321  if (canvas_image != (Image * ) NULL)
2322    canvas_image=DestroyImage(canvas_image);
2323  else
2324    source_image=DestroyImage(source_image);
2325  return(status);
2326}
2327
2328/*
2329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330%                                                                             %
2331%                                                                             %
2332%                                                                             %
2333%     T e x t u r e I m a g e                                                 %
2334%                                                                             %
2335%                                                                             %
2336%                                                                             %
2337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2338%
2339%  TextureImage() repeatedly tiles the texture image across and down the image
2340%  canvas.
2341%
2342%  The format of the TextureImage method is:
2343%
2344%      MagickBooleanType TextureImage(Image *image,const Image *texture,
2345%        ExceptionInfo *exception)
2346%
2347%  A description of each parameter follows:
2348%
2349%    o image: the image.
2350%
2351%    o texture_image: This image is the texture to layer on the background.
2352%
2353*/
2354MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2355  ExceptionInfo *exception)
2356{
2357#define TextureImageTag  "Texture/Image"
2358
2359  CacheView
2360    *image_view,
2361    *texture_view;
2362
2363  Image
2364    *texture_image;
2365
2366  MagickBooleanType
2367    status;
2368
2369  ssize_t
2370    y;
2371
2372  assert(image != (Image *) NULL);
2373  if (image->debug != MagickFalse)
2374    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2375  assert(image->signature == MagickCoreSignature);
2376  if (texture == (const Image *) NULL)
2377    return(MagickFalse);
2378  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2379    return(MagickFalse);
2380  texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2381  if (texture_image == (const Image *) NULL)
2382    return(MagickFalse);
2383  (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2384  (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2385    exception);
2386  status=MagickTrue;
2387  if ((image->compose != CopyCompositeOp) &&
2388      ((image->compose != OverCompositeOp) ||
2389       (image->alpha_trait != UndefinedPixelTrait) ||
2390       (texture_image->alpha_trait != UndefinedPixelTrait)))
2391    {
2392      /*
2393        Tile texture onto the image background.
2394      */
2395      for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2396      {
2397        register ssize_t
2398          x;
2399
2400        if (status == MagickFalse)
2401          continue;
2402        for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2403        {
2404          MagickBooleanType
2405            thread_status;
2406
2407          thread_status=CompositeImage(image,texture_image,image->compose,
2408            MagickTrue,x+texture_image->tile_offset.x,y+
2409            texture_image->tile_offset.y,exception);
2410          if (thread_status == MagickFalse)
2411            {
2412              status=thread_status;
2413              break;
2414            }
2415        }
2416        if (image->progress_monitor != (MagickProgressMonitor) NULL)
2417          {
2418            MagickBooleanType
2419              proceed;
2420
2421            proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2422              image->rows);
2423            if (proceed == MagickFalse)
2424              status=MagickFalse;
2425          }
2426      }
2427      (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2428        image->rows,image->rows);
2429      texture_image=DestroyImage(texture_image);
2430      return(status);
2431    }
2432  /*
2433    Tile texture onto the image background (optimized).
2434  */
2435  status=MagickTrue;
2436  texture_view=AcquireVirtualCacheView(texture_image,exception);
2437  image_view=AcquireAuthenticCacheView(image,exception);
2438#if defined(MAGICKCORE_OPENMP_SUPPORT)
2439  #pragma omp parallel for schedule(static,4) shared(status) \
2440    magick_threads(texture_image,image,1,1)
2441#endif
2442  for (y=0; y < (ssize_t) image->rows; y++)
2443  {
2444    MagickBooleanType
2445      sync;
2446
2447    register const Quantum
2448      *p,
2449      *pixels;
2450
2451    register ssize_t
2452      x;
2453
2454    register Quantum
2455      *q;
2456
2457    size_t
2458      width;
2459
2460    if (status == MagickFalse)
2461      continue;
2462    pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2463      (y+texture_image->tile_offset.y) % texture_image->rows,
2464      texture_image->columns,1,exception);
2465    q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2466    if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2467      {
2468        status=MagickFalse;
2469        continue;
2470      }
2471    for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2472    {
2473      register ssize_t
2474        j;
2475
2476      p=pixels;
2477      width=texture_image->columns;
2478      if ((x+(ssize_t) width) > (ssize_t) image->columns)
2479        width=image->columns-x;
2480      for (j=0; j < (ssize_t) width; j++)
2481      {
2482        register ssize_t
2483          i;
2484
2485        if (GetPixelReadMask(image,q) == 0)
2486          {
2487            p+=GetPixelChannels(texture_image);
2488            q+=GetPixelChannels(image);
2489            continue;
2490          }
2491        for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2492        {
2493          PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2494          PixelTrait traits=GetPixelChannelTraits(image,channel);
2495          PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2496            channel);
2497          if ((traits == UndefinedPixelTrait) ||
2498              (texture_traits == UndefinedPixelTrait))
2499            continue;
2500          SetPixelChannel(image,channel,p[i],q);
2501        }
2502        p+=GetPixelChannels(texture_image);
2503        q+=GetPixelChannels(image);
2504      }
2505    }
2506    sync=SyncCacheViewAuthenticPixels(image_view,exception);
2507    if (sync == MagickFalse)
2508      status=MagickFalse;
2509    if (image->progress_monitor != (MagickProgressMonitor) NULL)
2510      {
2511        MagickBooleanType
2512          proceed;
2513
2514        proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2515          image->rows);
2516        if (proceed == MagickFalse)
2517          status=MagickFalse;
2518      }
2519  }
2520  texture_view=DestroyCacheView(texture_view);
2521  image_view=DestroyCacheView(image_view);
2522  texture_image=DestroyImage(texture_image);
2523  return(status);
2524}
2525