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