]> granicus.if.org Git - imagemagick/blob - MagickCore/composite.c
(no commit message)
[imagemagick] / MagickCore / composite.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %        CCCC   OOO   M   M  PPPP    OOO   SSSSS  IIIII  TTTTT  EEEEE         %
7 %       C      O   O  MM MM  P   P  O   O  SS       I      T    E             %
8 %       C      O   O  M M M  PPPP   O   O   SSS     I      T    EEE           %
9 %       C      O   O  M   M  P      O   O     SS    I      T    E             %
10 %        CCCC   OOO   M   M  P       OOO   SSSSS  IIIII    T    EEEEE         %
11 %                                                                             %
12 %                                                                             %
13 %                     MagickCore Image Composite Methods                      %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/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 ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1725               {
1726                 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1727                 break;
1728               }
1729             if (fabs(Sca-Sa) < MagickEpsilon)
1730               {
1731                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1732                 break;
1733               }
1734             pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1735               (1.0-Sa));
1736             break;
1737           }
1738           case ColorizeCompositeOp:
1739           {
1740             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1741               {
1742                 pixel=Dc;
1743                 break;
1744               }
1745             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1746               {
1747                 pixel=Sc;
1748                 break;
1749               }
1750             CompositeHCL(destination_pixel.red,destination_pixel.green,
1751               destination_pixel.blue,&sans,&sans,&luma);
1752             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1753               &hue,&chroma,&sans);
1754             HCLComposite(hue,chroma,luma,&red,&green,&blue);
1755             switch (channel)
1756             {
1757               case RedPixelChannel: pixel=red; break;
1758               case GreenPixelChannel: pixel=green; break;
1759               case BluePixelChannel: pixel=blue; break;
1760               default: pixel=Dc; break;
1761             }
1762             break;
1763           }
1764           case CopyAlphaCompositeOp:
1765           case IntensityCompositeOp:
1766           {
1767             pixel=Dc;
1768             break;
1769           }
1770           case CopyBlackCompositeOp:
1771           {
1772             if (channel == BlackPixelChannel)
1773               pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1774             break;
1775           }
1776           case CopyBlueCompositeOp:
1777           case CopyYellowCompositeOp:
1778           {
1779             if (channel == BluePixelChannel)
1780               pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1781             break;
1782           }
1783           case CopyGreenCompositeOp:
1784           case CopyMagentaCompositeOp:
1785           {
1786             if (channel == GreenPixelChannel)
1787               pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1788             break;
1789           }
1790           case CopyRedCompositeOp:
1791           case CopyCyanCompositeOp:
1792           {
1793             if (channel == RedPixelChannel)
1794               pixel=(MagickRealType) GetPixelRed(composite_image,p);
1795             break;
1796           }
1797           case DarkenCompositeOp:
1798           {
1799             /*
1800               Darken is equivalent to a 'Minimum' method
1801                 OR a greyscale version of a binary 'Or'
1802                 OR the 'Intersection' of pixel sets.
1803             */
1804             if (Sc < Dc)
1805               {
1806                 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1807                 break;
1808               }
1809             pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1810             break;
1811           }
1812           case DarkenIntensityCompositeOp:
1813           {
1814             pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1815               (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1816             break;
1817           }
1818           case DifferenceCompositeOp:
1819           {
1820             pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1821             break;
1822           }
1823           case DissolveCompositeOp:
1824           {
1825             pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1826               destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1827             break;
1828           }
1829           case DivideDstCompositeOp:
1830           {
1831             if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1832               {
1833                 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1834                 break;
1835               }
1836             if (fabs(Dca) < MagickEpsilon)
1837               {
1838                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1839                 break;
1840               }
1841             pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1842             break;
1843           }
1844           case DivideSrcCompositeOp:
1845           {
1846             if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1847               {
1848                 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1849                 break;
1850               }
1851             if (fabs(Sca) < MagickEpsilon)
1852               {
1853                 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1854                 break;
1855               }
1856             pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1857             break;
1858           }
1859           case DstAtopCompositeOp:
1860           {
1861             pixel=Dc*Da+Sc*(1.0-Da);
1862             break;
1863           }
1864           case DstCompositeOp:
1865           case NoCompositeOp:
1866           {
1867             pixel=Dc;
1868             break;
1869           }
1870           case DstInCompositeOp:
1871           {
1872             pixel=gamma*(Sa*Dc*Sa);
1873             break;
1874           }
1875           case DstOutCompositeOp:
1876           {
1877             pixel=gamma*(Da*Dc*(1.0-Sa));
1878             break;
1879           }
1880           case DstOverCompositeOp:
1881           {
1882             pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1883             break;
1884           }
1885           case ExclusionCompositeOp:
1886           {
1887             pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1888               Dca*(1.0-Sa));
1889             break;
1890           }
1891           case HardLightCompositeOp:
1892           {
1893             if ((2.0*Sca) < Sa)
1894               {
1895                 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1896                   (1.0-Sa));
1897                 break;
1898               }
1899             pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1900               Dca*(1.0-Sa));
1901             break;
1902           }
1903           case HueCompositeOp:
1904           {
1905             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1906               {
1907                 pixel=Dc;
1908                 break;
1909               }
1910             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1911               {
1912                 pixel=Sc;
1913                 break;
1914               }
1915             CompositeHCL(destination_pixel.red,destination_pixel.green,
1916               destination_pixel.blue,&hue,&chroma,&luma);
1917             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1918               &hue,&sans,&sans);
1919             HCLComposite(hue,chroma,luma,&red,&green,&blue);
1920             switch (channel)
1921             {
1922               case RedPixelChannel: pixel=red; break;
1923               case GreenPixelChannel: pixel=green; break;
1924               case BluePixelChannel: pixel=blue; break;
1925               default: pixel=Dc; break;
1926             }
1927             break;
1928           }
1929           case InCompositeOp:
1930           case SrcInCompositeOp:
1931           {
1932             pixel=gamma*(Da*Sc*Da);
1933             break;
1934           }
1935           case LinearBurnCompositeOp:
1936           {
1937             /*
1938               LinearBurn: as defined by Abode Photoshop, according to
1939               http://www.simplefilter.de/en/basics/mixmods.html is:
1940
1941                 f(Sc,Dc) = Sc + Dc - 1
1942             */
1943             pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1944             break;
1945           }
1946           case LinearDodgeCompositeOp:
1947           {
1948             pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1949             break;
1950           }
1951           case LinearLightCompositeOp:
1952           {
1953             /*
1954               LinearLight: as defined by Abode Photoshop, according to
1955               http://www.simplefilter.de/en/basics/mixmods.html is:
1956
1957                 f(Sc,Dc) = Dc + 2*Sc - 1
1958             */
1959             pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1960             break;
1961           }
1962           case LightenCompositeOp:
1963           {
1964             if (Sc > Dc)
1965               {
1966                 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1967                 break;
1968               }
1969             pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1970             break;
1971           }
1972           case LightenIntensityCompositeOp:
1973           {
1974             /*
1975               Lighten is equivalent to a 'Maximum' method
1976                 OR a greyscale version of a binary 'And'
1977                 OR the 'Union' of pixel sets.
1978             */
1979             pixel=Sa*GetPixelIntensity(composite_image,p) >
1980               Da*GetPixelIntensity(image,q) ? Sc : Dc;
1981             break;
1982           }
1983           case LuminizeCompositeOp:
1984           {
1985             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1986               {
1987                 pixel=Dc;
1988                 break;
1989               }
1990             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1991               {
1992                 pixel=Sc;
1993                 break;
1994               }
1995             CompositeHCL(destination_pixel.red,destination_pixel.green,
1996               destination_pixel.blue,&hue,&chroma,&luma);
1997             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
1998               &sans,&sans,&luma);
1999             HCLComposite(hue,chroma,luma,&red,&green,&blue);
2000             switch (channel)
2001             {
2002               case RedPixelChannel: pixel=red; break;
2003               case GreenPixelChannel: pixel=green; break;
2004               case BluePixelChannel: pixel=blue; break;
2005               default: pixel=Dc; break;
2006             }
2007             break;
2008           }
2009           case MathematicsCompositeOp:
2010           {
2011             /*
2012               'Mathematics' a free form user control mathematical composition
2013               is defined as...
2014
2015                 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
2016
2017               Where the arguments A,B,C,D are (currently) passed to composite
2018               as a command separated 'geometry' string in "compose:args" image
2019               artifact.
2020
2021                  A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
2022
2023               Applying the SVG transparency formula (see above), we get...
2024
2025                Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
2026
2027                Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
2028                  Dca*(1.0-Sa)
2029             */
2030             pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
2031               Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
2032               Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
2033             break;
2034           }
2035           case MinusDstCompositeOp:
2036           {
2037             pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2038             break;
2039           }
2040           case MinusSrcCompositeOp:
2041           {
2042             /*
2043               Minus source from destination.
2044
2045                 f(Sc,Dc) = Sc - Dc
2046             */
2047             pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2048             break;
2049           }
2050           case ModulateCompositeOp:
2051           {
2052             ssize_t
2053               offset;
2054
2055             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2056               {
2057                 pixel=Dc;
2058                 break;
2059               }
2060             offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
2061             if (offset == 0)
2062               {
2063                 pixel=Dc;
2064                 break;
2065               }
2066             CompositeHCL(destination_pixel.red,destination_pixel.green,
2067               destination_pixel.blue,&hue,&chroma,&luma);
2068             luma+=(0.01*percent_luma*offset)/midpoint;
2069             chroma*=0.01*percent_chroma;
2070             HCLComposite(hue,chroma,luma,&red,&green,&blue);
2071             switch (channel)
2072             {
2073               case RedPixelChannel: pixel=red; break;
2074               case GreenPixelChannel: pixel=green; break;
2075               case BluePixelChannel: pixel=blue; break;
2076               default: pixel=Dc; break;
2077             }
2078             break;
2079           }
2080           case ModulusAddCompositeOp:
2081           {
2082             pixel=Sc+Dc;
2083             if (pixel > QuantumRange)
2084               pixel-=(QuantumRange+1.0);
2085             pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2086             break;
2087           }
2088           case ModulusSubtractCompositeOp:
2089           {
2090             pixel=Sc-Dc;
2091             if (pixel < 0.0)
2092               pixel+=(QuantumRange+1.0);
2093             pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2094             break;
2095           }
2096           case MultiplyCompositeOp:
2097           {
2098             pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2099             break;
2100           }
2101           case OutCompositeOp:
2102           case SrcOutCompositeOp:
2103           {
2104             pixel=gamma*(Sa*Sc*(1.0-Da));
2105             break;
2106           }
2107           case OverCompositeOp:
2108           case SrcOverCompositeOp:
2109           {
2110             pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2111             break;
2112           }
2113           case OverlayCompositeOp:
2114           {
2115             if ((2.0*Dca) < Da)
2116               {
2117                 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2118                   (1.0-Da));
2119                 break;
2120               }
2121             pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2122               Sca*(1.0-Da));
2123             break;
2124           }
2125           case PegtopLightCompositeOp:
2126           {
2127             /*
2128               PegTop: A Soft-Light alternative: A continuous version of the
2129               Softlight function, producing very similar results.
2130
2131                 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2132
2133               http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2134             */
2135             if (fabs(Da) < MagickEpsilon)
2136               {
2137                 pixel=QuantumRange*gamma*(Sca);
2138                 break;
2139               }
2140             pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2141               Da)+Dca*(1.0-Sa));
2142             break;
2143           }
2144           case PinLightCompositeOp:
2145           {
2146             /*
2147               PinLight: A Photoshop 7 composition method
2148               http://www.simplefilter.de/en/basics/mixmods.html
2149
2150                 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
2151             */
2152             if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2153               {
2154                 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2155                 break;
2156               }
2157             if ((Dca*Sa) > (2.0*Sca*Da))
2158               {
2159                 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2160                 break;
2161               }
2162             pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2163             break;
2164           }
2165           case PlusCompositeOp:
2166           {
2167             pixel=gamma*(Sa*Sc+Da*Dc);
2168             break;
2169           }
2170           case SaturateCompositeOp:
2171           {
2172             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2173               {
2174                 pixel=Dc;
2175                 break;
2176               }
2177             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2178               {
2179                 pixel=Sc;
2180                 break;
2181               }
2182             CompositeHCL(destination_pixel.red,destination_pixel.green,
2183               destination_pixel.blue,&hue,&chroma,&luma);
2184             CompositeHCL(source_pixel.red,source_pixel.green,source_pixel.blue,
2185               &sans,&chroma,&sans);
2186             HCLComposite(hue,chroma,luma,&red,&green,&blue);
2187             switch (channel)
2188             {
2189               case RedPixelChannel: pixel=red; break;
2190               case GreenPixelChannel: pixel=green; break;
2191               case BluePixelChannel: pixel=blue; break;
2192               default: pixel=Dc; break;
2193             }
2194             break;
2195           }
2196           case ScreenCompositeOp:
2197           {
2198             /*
2199               Screen:  a negated multiply:
2200
2201                 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2202             */
2203             pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2204             break;
2205           }
2206           case SoftLightCompositeOp:
2207           {
2208             /*
2209               Refer to the March 2009 SVG specification.
2210             */
2211             if ((2.0*Sca) < Sa)
2212               {
2213                 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2214                   Sca*(1.0-Da)+Dca*(1.0-Sa));
2215                 break;
2216               }
2217             if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2218               {
2219                 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2220                   (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2221                   Dca*(1.0-Sa));
2222                 break;
2223               }
2224             pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2225               (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2226             break;
2227           }
2228           case ThresholdCompositeOp:
2229           {
2230             MagickRealType
2231               delta;
2232
2233             delta=Sc-Dc;
2234             if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2235               {
2236                 pixel=gamma*Dc;
2237                 break;
2238               }
2239             pixel=gamma*(Dc+delta*amount);
2240             break;
2241           }
2242           case VividLightCompositeOp:
2243           {
2244             /*
2245               VividLight: A Photoshop 7 composition method.  See
2246               http://www.simplefilter.de/en/basics/mixmods.html.
2247
2248                 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2249             */
2250             if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2251               {
2252                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2253                 break;
2254               }
2255             if ((2.0*Sca) <= Sa)
2256               {
2257                 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2258                   (1.0-Da)+Dca*(1.0-Sa));
2259                 break;
2260               }
2261             pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2262               Dca*(1.0-Sa));
2263             break;
2264           }
2265           case XorCompositeOp:
2266           {
2267             pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2268             break;
2269           }
2270           default:
2271           {
2272             pixel=Sc;
2273             break;
2274           }
2275         }
2276         q[i]=ClampToQuantum(pixel);
2277       }
2278       p+=GetPixelChannels(composite_image);
2279       channels=GetPixelChannels(composite_image);
2280       if (p >= (pixels+channels*composite_image->columns))
2281         p=pixels;
2282       q+=GetPixelChannels(image);
2283     }
2284     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2285       status=MagickFalse;
2286     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2287       {
2288         MagickBooleanType
2289           proceed;
2290
2291 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2292         #pragma omp critical (MagickCore_CompositeImage)
2293 #endif
2294         proceed=SetImageProgress(image,CompositeImageTag,progress++,
2295           image->rows);
2296         if (proceed == MagickFalse)
2297           status=MagickFalse;
2298       }
2299   }
2300   composite_view=DestroyCacheView(composite_view);
2301   image_view=DestroyCacheView(image_view);
2302   if (destination_image != (Image * ) NULL)
2303     destination_image=DestroyImage(destination_image);
2304   else
2305     composite_image=DestroyImage(composite_image);
2306   return(status);
2307 }
2308 \f
2309 /*
2310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2311 %                                                                             %
2312 %                                                                             %
2313 %                                                                             %
2314 %     T e x t u r e I m a g e                                                 %
2315 %                                                                             %
2316 %                                                                             %
2317 %                                                                             %
2318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319 %
2320 %  TextureImage() repeatedly tiles the texture image across and down the image
2321 %  canvas.
2322 %
2323 %  The format of the TextureImage method is:
2324 %
2325 %      MagickBooleanType TextureImage(Image *image,const Image *texture,
2326 %        ExceptionInfo *exception)
2327 %
2328 %  A description of each parameter follows:
2329 %
2330 %    o image: the image.
2331 %
2332 %    o texture_image: This image is the texture to layer on the background.
2333 %
2334 */
2335 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
2336   ExceptionInfo *exception)
2337 {
2338 #define TextureImageTag  "Texture/Image"
2339
2340   CacheView
2341     *image_view,
2342     *texture_view;
2343
2344   Image
2345     *texture_image;
2346
2347   MagickBooleanType
2348     status;
2349
2350   ssize_t
2351     y;
2352
2353   assert(image != (Image *) NULL);
2354   if (image->debug != MagickFalse)
2355     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2356   assert(image->signature == MagickSignature);
2357   if (texture == (const Image *) NULL)
2358     return(MagickFalse);
2359   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2360     return(MagickFalse);
2361   texture_image=CloneImage(texture,0,0,MagickTrue,exception);
2362   if (texture_image == (const Image *) NULL)
2363     return(MagickFalse);
2364   (void) TransformImageColorspace(texture_image,image->colorspace,exception);
2365   (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod,
2366     exception);
2367   status=MagickTrue;
2368   if ((image->compose != CopyCompositeOp) &&
2369       ((image->compose != OverCompositeOp) ||
2370        (image->alpha_trait == BlendPixelTrait) ||
2371        (texture_image->alpha_trait == BlendPixelTrait)))
2372     {
2373       /*
2374         Tile texture onto the image background.
2375       */
2376       for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2377       {
2378         register ssize_t
2379           x;
2380
2381         if (status == MagickFalse)
2382           continue;
2383         for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2384         {
2385           MagickBooleanType
2386             thread_status;
2387
2388           thread_status=CompositeImage(image,texture_image,image->compose,
2389             MagickFalse,x+texture_image->tile_offset.x,y+
2390             texture_image->tile_offset.y,exception);
2391           if (thread_status == MagickFalse)
2392             {
2393               status=thread_status;
2394               break;
2395             }
2396         }
2397         if (image->progress_monitor != (MagickProgressMonitor) NULL)
2398           {
2399             MagickBooleanType
2400               proceed;
2401
2402             proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2403               y,image->rows);
2404             if (proceed == MagickFalse)
2405               status=MagickFalse;
2406           }
2407       }
2408       (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2409         image->rows,image->rows);
2410       texture_image=DestroyImage(texture_image);
2411       return(status);
2412     }
2413   /*
2414     Tile texture onto the image background (optimized).
2415   */
2416   status=MagickTrue;
2417   texture_view=AcquireVirtualCacheView(texture_image,exception);
2418   image_view=AcquireAuthenticCacheView(image,exception);
2419 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2420   #pragma omp parallel for schedule(static,4) shared(status) \
2421     magick_threads(texture_image,image,1,1)
2422 #endif
2423   for (y=0; y < (ssize_t) image->rows; y++)
2424   {
2425     MagickBooleanType
2426       sync;
2427
2428     register const Quantum
2429       *p,
2430       *pixels;
2431
2432     register ssize_t
2433       x;
2434
2435     register Quantum
2436       *q;
2437
2438     size_t
2439       width;
2440
2441     if (status == MagickFalse)
2442       continue;
2443     pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2444       (y+texture_image->tile_offset.y) % texture_image->rows,
2445       texture_image->columns,1,exception);
2446     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2447     if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2448       {
2449         status=MagickFalse;
2450         continue;
2451       }
2452     for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2453     {
2454       register ssize_t
2455         j;
2456
2457       p=pixels;
2458       width=texture_image->columns;
2459       if ((x+(ssize_t) width) > (ssize_t) image->columns)
2460         width=image->columns-x;
2461       for (j=0; j < (ssize_t) width; j++)
2462       {
2463         register ssize_t
2464           i;
2465
2466         if (GetPixelReadMask(image,q) == 0)
2467           {
2468             p+=GetPixelChannels(texture_image);
2469             q+=GetPixelChannels(image);
2470             continue;
2471           }
2472         for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2473         {
2474           PixelChannel channel=GetPixelChannelChannel(texture_image,i);
2475           PixelTrait traits=GetPixelChannelTraits(image,channel);
2476           PixelTrait texture_traits=GetPixelChannelTraits(texture_image,
2477             channel);
2478           if ((traits == UndefinedPixelTrait) ||
2479               (texture_traits == UndefinedPixelTrait))
2480             continue;
2481           SetPixelChannel(image,channel,p[i],q);
2482         }
2483         p+=GetPixelChannels(texture_image);
2484         q+=GetPixelChannels(image);
2485       }
2486     }
2487     sync=SyncCacheViewAuthenticPixels(image_view,exception);
2488     if (sync == MagickFalse)
2489       status=MagickFalse;
2490     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2491       {
2492         MagickBooleanType
2493           proceed;
2494
2495         proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2496           image->rows);
2497         if (proceed == MagickFalse)
2498           status=MagickFalse;
2499       }
2500   }
2501   texture_view=DestroyCacheView(texture_view);
2502   image_view=DestroyCacheView(image_view);
2503   texture_image=DestroyImage(texture_image);
2504   return(status);
2505 }