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