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