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