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