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