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