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