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