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