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