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