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