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