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