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