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