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