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