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