]> granicus.if.org Git - imagemagick/blob - MagickCore/composite.c
561b7303b02b9bf1510505459b8ffe5623539e86
[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 LightenIntensityCompositeOp:
1525               {
1526                 pixel=Sa*GetPixelIntensity(composite_image,p) >
1527                   Da*GetPixelIntensity(image,q) ? Sa : Da;
1528                 break;
1529               }
1530               case ModulateCompositeOp:
1531               {
1532                 if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1533                   {
1534                     pixel=QuantumRange*Da;
1535                     break;
1536                   }
1537                 pixel=QuantumRange*Da;
1538                 break;
1539               }
1540               default:
1541               {
1542                 pixel=QuantumRange*alpha;
1543                 break;
1544               }
1545             }
1546             q[i]=ClampToQuantum(pixel);
1547             continue;
1548           }
1549         /*
1550           Porter-Duff compositions:
1551             Sca: source normalized color multiplied by alpha.
1552             Dca: normalized destination color multiplied by alpha.
1553         */
1554         Sca=QuantumScale*Sa*Sc;
1555         Dca=QuantumScale*Da*Dc;
1556         switch (compose)
1557         {
1558           case DarkenCompositeOp:
1559           case LightenCompositeOp:
1560           case ModulusSubtractCompositeOp:
1561           {
1562             gamma=1.0-alpha;
1563             break;
1564           }
1565           default:
1566             break;
1567         }
1568         gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
1569         switch (compose)
1570         {
1571           case AtopCompositeOp:
1572           case SrcAtopCompositeOp:
1573           {
1574             pixel=Sc*Sa+Dc*(1.0-Sa);
1575             break;
1576           }
1577           case BlendCompositeOp:
1578           {
1579             pixel=gamma*(source_dissolve*Sa*Sc+destination_dissolve*Da*Dc);
1580             break;
1581           }
1582           case BlurCompositeOp:
1583           case DisplaceCompositeOp:
1584           case DistortCompositeOp:
1585           case CopyCompositeOp:
1586           case ReplaceCompositeOp:
1587           case SrcCompositeOp:
1588           {
1589             pixel=Sc;
1590             break;
1591           }
1592           case BumpmapCompositeOp:
1593           {
1594             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1595               {
1596                 pixel=Dc;
1597                 break;
1598               }
1599             pixel=QuantumScale*GetPixelIntensity(composite_image,p)*Dc;
1600             break;
1601           }
1602           case ChangeMaskCompositeOp:
1603           {
1604             pixel=Dc;
1605             break;
1606           }
1607           case ClearCompositeOp:
1608           {
1609             pixel=0.0;
1610             break;
1611           }
1612           case ColorBurnCompositeOp:
1613           {
1614             /*
1615               Refer to the March 2009 SVG specification.
1616             */
1617             if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
1618               {
1619                 pixel=QuantumRange*gamma*(Sa*Da+Dca*(1.0-Sa));
1620                 break;
1621               }
1622             if (Sca < MagickEpsilon)
1623               {
1624                 pixel=QuantumRange*gamma*(Dca*(1.0-Sa));
1625                 break;
1626               }
1627             pixel=QuantumRange*gamma*(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+
1628               Sca*(1.0-Da)+Dca*(1.0-Sa));
1629             break;
1630           }
1631           case ColorDodgeCompositeOp:
1632           {
1633             if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1634               {
1635                 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1636                 break;
1637               }
1638             if (fabs(Sca-Sa) < MagickEpsilon)
1639               {
1640                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1641                 break;
1642               }
1643             pixel=QuantumRange*gamma*(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*
1644               (1.0-Sa));
1645             break;
1646           }
1647           case ColorizeCompositeOp:
1648           {
1649             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1650               {
1651                 pixel=Dc;
1652                 break;
1653               }
1654             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1655               {
1656                 pixel=Sc;
1657                 break;
1658               }
1659             CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1660               GetPixelBlue(image,q),&sans,&sans,&brightness);
1661             CompositeHSB(GetPixelRed(composite_image,p),
1662               GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1663               &hue,&saturation,&sans);
1664             HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1665             switch (channel)
1666             {
1667               case RedPixelChannel: pixel=red; break;
1668               case GreenPixelChannel: pixel=green; break;
1669               case BluePixelChannel: pixel=blue; break;
1670               default: pixel=Dc; break;
1671             }
1672             break;
1673           }
1674           case CopyAlphaCompositeOp:
1675           {
1676             if (channel == AlphaPixelChannel)
1677               {
1678                 if (composite_image->matte != MagickFalse)
1679                   pixel=(MagickRealType) GetPixelAlpha(composite_image,p);
1680                 else
1681                   pixel=(MagickRealType) GetPixelIntensity(composite_image,p);
1682                 break;
1683               }
1684             pixel=Dc;
1685             break;
1686           }
1687           case CopyBlackCompositeOp:
1688           {
1689             pixel=(MagickRealType) GetPixelBlack(composite_image,p);
1690             break;
1691           }
1692           case CopyBlueCompositeOp:
1693           case CopyYellowCompositeOp:
1694           {
1695             pixel=(MagickRealType) GetPixelBlue(composite_image,p);
1696             break;
1697           }
1698           case CopyGreenCompositeOp:
1699           case CopyMagentaCompositeOp:
1700           {
1701             pixel=(MagickRealType) GetPixelGreen(composite_image,p);
1702             break;
1703           }
1704           case CopyRedCompositeOp:
1705           case CopyCyanCompositeOp:
1706           {
1707             pixel=(MagickRealType) GetPixelRed(composite_image,p);
1708             break;
1709           }
1710           case DarkenCompositeOp:
1711           {
1712             /*
1713               Darken is equivalent to a 'Minimum' method
1714                 OR a greyscale version of a binary 'Or'
1715                 OR the 'Intersection' of pixel sets.
1716             */
1717             if (Sc < Dc)
1718               {
1719                 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1720                 break;
1721               }
1722             pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1723             break;
1724           }
1725           case DarkenIntensityCompositeOp:
1726           {
1727             pixel=(1.0-Sa)*GetPixelIntensity(composite_image,p) <
1728               (1.0-Da)*GetPixelIntensity(image,q) ? Sc : Dc;
1729             break;
1730           }
1731           case DifferenceCompositeOp:
1732           {
1733             pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
1734             break;
1735           }
1736           case DissolveCompositeOp:
1737           {
1738             pixel=gamma*(source_dissolve*Sa*Sc-source_dissolve*Sa*
1739               destination_dissolve*Da*Dc+destination_dissolve*Da*Dc);
1740             break;
1741           }
1742           case DivideDstCompositeOp:
1743           {
1744             if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
1745               {
1746                 pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca*(1.0-Sa));
1747                 break;
1748               }
1749             if (fabs(Dca) < MagickEpsilon)
1750               {
1751                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1752                 break;
1753               }
1754             pixel=QuantumRange*gamma*(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1755             break;
1756           }
1757           case DivideSrcCompositeOp:
1758           {
1759             if ((fabs(Dca) < MagickEpsilon) && (fabs(Sca) < MagickEpsilon))
1760               {
1761                 pixel=QuantumRange*gamma*(Dca*(1.0-Sa)+Sca*(1.0-Da));
1762                 break;
1763               }
1764             if (fabs(Sca) < MagickEpsilon)
1765               {
1766                 pixel=QuantumRange*gamma*(Da*Sa+Dca*(1.0-Sa)+Sca*(1.0-Da));
1767                 break;
1768               }
1769             pixel=QuantumRange*gamma*(Dca*Sa*Sa/Sca+Dca*(1.0-Sa)+Sca*(1.0-Da));
1770             break;
1771           }
1772           case DstAtopCompositeOp:
1773           {
1774             pixel=Dc*Da+Sc*(1.0-Da);
1775             break;
1776           }
1777           case DstCompositeOp:
1778           case NoCompositeOp:
1779           {
1780             pixel=Dc;
1781             break;
1782           }
1783           case DstInCompositeOp:
1784           {
1785             pixel=gamma*(Sa*Dc*Sa);
1786             break;
1787           }
1788           case DstOutCompositeOp:
1789           {
1790             pixel=gamma*(Da*Dc*(1.0-Sa));
1791             break;
1792           }
1793           case DstOverCompositeOp:
1794           {
1795             pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1796             break;
1797           }
1798           case ExclusionCompositeOp:
1799           {
1800             pixel=QuantumRange*gamma*(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+
1801               Dca*(1.0-Sa));
1802             break;
1803           }
1804           case HardLightCompositeOp:
1805           {
1806             if ((2.0*Sca) < Sa)
1807               {
1808                 pixel=QuantumRange*gamma*(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*
1809                   (1.0-Sa));
1810                 break;
1811               }
1812             pixel=QuantumRange*gamma*(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+
1813               Dca*(1.0-Sa));
1814             break;
1815           }
1816           case HueCompositeOp:
1817           {
1818             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1819               {
1820                 pixel=Dc;
1821                 break;
1822               }
1823             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1824               {
1825                 pixel=Sc;
1826                 break;
1827               }
1828             CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1829               GetPixelBlue(image,q),&hue,&saturation,&brightness);
1830             CompositeHSB(GetPixelRed(composite_image,p),
1831               GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1832               &hue,&sans,&sans);
1833             HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1834             switch (channel)
1835             {
1836               case RedPixelChannel: pixel=red; break;
1837               case GreenPixelChannel: pixel=green; break;
1838               case BluePixelChannel: pixel=blue; break;
1839               default: pixel=Dc; break;
1840             }
1841             break;
1842           }
1843           case InCompositeOp:
1844           case SrcInCompositeOp:
1845           {
1846             pixel=gamma*(Da*Sc*Da);
1847             break;
1848           }
1849           case LinearBurnCompositeOp:
1850           {
1851             /*
1852               LinearBurn: as defined by Abode Photoshop, according to
1853               http://www.simplefilter.de/en/basics/mixmods.html is:
1854
1855                 f(Sc,Dc) = Sc + Dc - 1
1856             */
1857             pixel=QuantumRange*gamma*(Sca+Dca-Sa*Da);
1858             break;
1859           }
1860           case LinearDodgeCompositeOp:
1861           {
1862             pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
1863             break;
1864           }
1865           case LinearLightCompositeOp:
1866           {
1867             /*
1868               LinearLight: as defined by Abode Photoshop, according to
1869               http://www.simplefilter.de/en/basics/mixmods.html is:
1870
1871                 f(Sc,Dc) = Dc + 2*Sc - 1
1872             */
1873             pixel=QuantumRange*gamma*((Sca-Sa)*Da+Sca+Dca);
1874             break;
1875           }
1876           case LightenCompositeOp:
1877           {
1878             if (Sc > Dc)
1879               {
1880                 pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
1881                 break;
1882               }
1883             pixel=QuantumRange*gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
1884             break;
1885           }
1886           case LightenIntensityCompositeOp:
1887           {
1888             /*
1889               Lighten is equivalent to a 'Maximum' method
1890                 OR a greyscale version of a binary 'And'
1891                 OR the 'Union' of pixel sets.
1892             */
1893             pixel=Sa*GetPixelIntensity(composite_image,p) >
1894               Da*GetPixelIntensity(image,q) ? Sc : Dc;
1895             break;
1896           }
1897           case LuminizeCompositeOp:
1898           {
1899             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1900               {
1901                 pixel=Dc;
1902                 break;
1903               }
1904             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
1905               {
1906                 pixel=Sc;
1907                 break;
1908               }
1909             CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1910               GetPixelBlue(image,q),&hue,&saturation,&brightness);
1911             CompositeHSB(GetPixelRed(composite_image,p),
1912               GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
1913               &sans,&sans,&brightness);
1914             HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1915             switch (channel)
1916             {
1917               case RedPixelChannel: pixel=red; break;
1918               case GreenPixelChannel: pixel=green; break;
1919               case BluePixelChannel: pixel=blue; break;
1920               default: pixel=Dc; break;
1921             }
1922             break;
1923           }
1924           case MathematicsCompositeOp:
1925           {
1926             /*
1927               'Mathematics' a free form user control mathematical composition
1928               is defined as...
1929
1930                 f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
1931
1932               Where the arguments A,B,C,D are (currently) passed to composite
1933               as a command separated 'geometry' string in "compose:args" image
1934               artifact.
1935
1936                  A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
1937
1938               Applying the SVG transparency formula (see above), we get...
1939
1940                Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
1941
1942                Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
1943                  Dca*(1.0-Sa)
1944             */
1945             pixel=gamma*geometry_info.rho*Sa*Sc*Da*Dc+geometry_info.sigma*
1946               Sa*Sc*Da+geometry_info.xi*Da*Dc*Sa+geometry_info.psi*Sa*Da+
1947               Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa);
1948             break;
1949           }
1950           case MinusDstCompositeOp:
1951           {
1952             pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
1953             break;
1954           }
1955           case MinusSrcCompositeOp:
1956           {
1957             /*
1958               Minus source from destination.
1959
1960                 f(Sc,Dc) = Sc - Dc
1961             */
1962             pixel=QuantumRange*gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
1963             break;
1964           }
1965           case ModulateCompositeOp:
1966           {
1967             ssize_t
1968               offset;
1969
1970             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
1971               {
1972                 pixel=Dc;
1973                 break;
1974               }
1975             offset=(ssize_t) (GetPixelIntensity(composite_image,p)-midpoint);
1976             if (offset == 0)
1977               {
1978                 pixel=Dc;
1979                 break;
1980               }
1981             CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
1982               GetPixelBlue(image,q),&hue,&saturation,&brightness);
1983             brightness+=(0.01*percent_brightness*offset)/midpoint;
1984             saturation*=0.01*percent_saturation;
1985             HSBComposite(hue,saturation,brightness,&red,&green,&blue);
1986             switch (channel)
1987             {
1988               case RedPixelChannel: pixel=red; break;
1989               case GreenPixelChannel: pixel=green; break;
1990               case BluePixelChannel: pixel=blue; break;
1991               default: pixel=Dc; break;
1992             }
1993             break;
1994           }
1995           case ModulusAddCompositeOp:
1996           {
1997             pixel=Sc+Dc;
1998             if (pixel > QuantumRange)
1999               pixel-=(QuantumRange+1.0);
2000             pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2001             break;
2002           }
2003           case ModulusSubtractCompositeOp:
2004           {
2005             pixel=Sc-Dc;
2006             if (pixel < 0.0)
2007               pixel+=(QuantumRange+1.0);
2008             pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2009             break;
2010           }
2011           case MultiplyCompositeOp:
2012           {
2013             pixel=QuantumRange*gamma*(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
2014             break;
2015           }
2016           case OutCompositeOp:
2017           case SrcOutCompositeOp:
2018           {
2019             pixel=gamma*(Sa*Sc*(1.0-Da));
2020             break;
2021           }
2022           case OverCompositeOp:
2023           case SrcOverCompositeOp:
2024           {
2025             pixel=QuantumRange*gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2026             break;
2027           }
2028           case OverlayCompositeOp:
2029           {
2030             if ((2.0*Dca) < Da)
2031               {
2032                 pixel=QuantumRange*gamma*(2.0*Dca*Sca+Dca*(1.0-Sa)+Sca*
2033                   (1.0-Da));
2034                 break;
2035               }
2036             pixel=QuantumRange*gamma*(Da*Sa-2.0*(Sa-Sca)*(Da-Dca)+Dca*(1.0-Sa)+
2037               Sca*(1.0-Da));
2038             break;
2039           }
2040           case PegtopLightCompositeOp:
2041           {
2042             /*
2043               PegTop: A Soft-Light alternative: A continuous version of the
2044               Softlight function, producing very similar results.
2045
2046                 f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
2047
2048               http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
2049             */
2050             if (fabs(Da) < MagickEpsilon)
2051               {
2052                 pixel=QuantumRange*gamma*(Sca);
2053                 break;
2054               }
2055             pixel=QuantumRange*gamma*(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-
2056               Da)+Dca*(1.0-Sa));
2057             break;
2058           }
2059           case PinLightCompositeOp:
2060           {
2061             /*
2062               PinLight: A Photoshop 7 composition method
2063               http://www.simplefilter.de/en/basics/mixmods.html
2064
2065                 f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
2066             */
2067             if ((Dca*Sa) < (Da*(2.0*Sca-Sa)))
2068               {
2069                 pixel=QuantumRange*gamma*(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
2070                 break;
2071               }
2072             if ((Dca*Sa) > (2.0*Sca*Da))
2073               {
2074                 pixel=QuantumRange*gamma*(Sca*Da+Sca+Dca*(1.0-Sa));
2075                 break;
2076               }
2077             pixel=QuantumRange*gamma*(Sca*(1.0-Da)+Dca);
2078             break;
2079           }
2080           case PlusCompositeOp:
2081           {
2082             pixel=QuantumRange*gamma*(Sa*Sc+Da*Dc);
2083             break;
2084           }
2085           case SaturateCompositeOp:
2086           {
2087             if (fabs(QuantumRange*Sa-TransparentAlpha) < MagickEpsilon)
2088               {
2089                 pixel=Dc;
2090                 break;
2091               }
2092             if (fabs(QuantumRange*Da-TransparentAlpha) < MagickEpsilon)
2093               {
2094                 pixel=Sc;
2095                 break;
2096               }
2097             CompositeHSB(GetPixelRed(image,q),GetPixelGreen(image,q),
2098               GetPixelBlue(image,q),&hue,&saturation,&brightness);
2099             CompositeHSB(GetPixelRed(composite_image,p),
2100               GetPixelGreen(composite_image,p),GetPixelBlue(composite_image,p),
2101               &sans,&saturation,&sans);
2102             HSBComposite(hue,saturation,brightness,&red,&green,&blue);
2103             switch (channel)
2104             {
2105               case RedPixelChannel: pixel=red; break;
2106               case GreenPixelChannel: pixel=green; break;
2107               case BluePixelChannel: pixel=blue; break;
2108               default: pixel=Dc; break;
2109             }
2110             break;
2111           }
2112           case ScreenCompositeOp:
2113           {
2114             /*
2115               Screen:  a negated multiply:
2116
2117                 f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
2118             */
2119             pixel=QuantumRange*gamma*(Sca+Dca-Sca*Dca);
2120             break;
2121           }
2122           case SoftLightCompositeOp:
2123           {
2124             /*
2125               Refer to the March 2009 SVG specification.
2126             */
2127             if ((2.0*Sca) < Sa)
2128               {
2129                 pixel=QuantumRange*gamma*(Dca*(Sa+(2.0*Sca-Sa)*(1.0-(Dca/Da)))+
2130                   Sca*(1.0-Da)+Dca*(1.0-Sa));
2131                 break;
2132               }
2133             if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
2134               {
2135                 pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*(Dca/Da)*
2136                   (4.0*(Dca/Da)+1.0)*((Dca/Da)-1.0)+7.0*(Dca/Da))+Sca*(1.0-Da)+
2137                   Dca*(1.0-Sa));
2138                 break;
2139               }
2140             pixel=QuantumRange*gamma*(Dca*Sa+Da*(2.0*Sca-Sa)*(pow((Dca/Da),0.5)-
2141               (Dca/Da))+Sca*(1.0-Da)+Dca*(1.0-Sa));
2142             break;
2143           }
2144           case ThresholdCompositeOp:
2145           {
2146             MagickRealType
2147               delta;
2148
2149             delta=Sc-Dc;
2150             if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
2151               {
2152                 pixel=gamma*Dc;
2153                 break;
2154               }
2155             pixel=gamma*(Dc+delta*amount);
2156             break;
2157           }
2158           case VividLightCompositeOp:
2159           {
2160             /*
2161               VividLight: A Photoshop 7 composition method.  See
2162               http://www.simplefilter.de/en/basics/mixmods.html.
2163
2164                 f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
2165             */
2166             if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
2167               {
2168                 pixel=QuantumRange*gamma*(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
2169                 break;
2170               }
2171             if ((2.0*Sca) <= Sa)
2172               {
2173                 pixel=QuantumRange*gamma*(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*
2174                   (1.0-Da)+Dca*(1.0-Sa));
2175                 break;
2176               }
2177             pixel=QuantumRange*gamma*(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+
2178               Dca*(1.0-Sa));
2179             break;
2180           }
2181           case XorCompositeOp:
2182           {
2183             pixel=QuantumRange*gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2184             break;
2185           }
2186           default:
2187           {
2188             pixel=Sc;
2189             break;
2190           }
2191         }
2192         q[i]=ClampToQuantum(pixel);
2193       }
2194       p+=GetPixelChannels(composite_image);
2195       channels=GetPixelChannels(composite_image);
2196       if (p >= (pixels+channels*composite_image->columns))
2197         p=pixels;
2198       q+=GetPixelChannels(image);
2199     }
2200     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2201       status=MagickFalse;
2202     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2203       {
2204         MagickBooleanType
2205           proceed;
2206
2207 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2208   #pragma omp critical (MagickCore_CompositeImage)
2209 #endif
2210         proceed=SetImageProgress(image,CompositeImageTag,progress++,
2211           image->rows);
2212         if (proceed == MagickFalse)
2213           status=MagickFalse;
2214       }
2215   }
2216   composite_view=DestroyCacheView(composite_view);
2217   image_view=DestroyCacheView(image_view);
2218   if (destination_image != (Image * ) NULL)
2219     destination_image=DestroyImage(destination_image);
2220   return(status);
2221 }
2222 \f
2223 /*
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225 %                                                                             %
2226 %                                                                             %
2227 %                                                                             %
2228 %     T e x t u r e I m a g e                                                 %
2229 %                                                                             %
2230 %                                                                             %
2231 %                                                                             %
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2233 %
2234 %  TextureImage() repeatedly tiles the texture image across and down the image
2235 %  canvas.
2236 %
2237 %  The format of the TextureImage method is:
2238 %
2239 %      MagickBooleanType TextureImage(Image *image,const Image *texture_image,
2240 %        ExceptionInfo *exception)
2241 %
2242 %  A description of each parameter follows:
2243 %
2244 %    o image: the image.
2245 %
2246 %    o texture_image: This image is the texture to layer on the background.
2247 %
2248 */
2249 MagickExport MagickBooleanType TextureImage(Image *image,
2250   const Image *texture_image,ExceptionInfo *exception)
2251 {
2252 #define TextureImageTag  "Texture/Image"
2253
2254   CacheView
2255     *image_view,
2256     *texture_view;
2257
2258   MagickBooleanType
2259     status;
2260
2261   ssize_t
2262     y;
2263
2264   assert(image != (Image *) NULL);
2265   if (image->debug != MagickFalse)
2266     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2267   assert(image->signature == MagickSignature);
2268   if (texture_image == (const Image *) NULL)
2269     return(MagickFalse);
2270   (void) SetImageVirtualPixelMethod(texture_image,TileVirtualPixelMethod);
2271   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2272     return(MagickFalse);
2273   status=MagickTrue;
2274   if ((image->compose != CopyCompositeOp) &&
2275       ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
2276        (texture_image->matte != MagickFalse)))
2277     {
2278       /*
2279         Tile texture onto the image background.
2280       */
2281 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2282       #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2283 #endif
2284       for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture_image->rows)
2285       {
2286         register ssize_t
2287           x;
2288
2289         if (status == MagickFalse)
2290           continue;
2291         for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2292         {
2293           MagickBooleanType
2294             thread_status;
2295
2296           thread_status=CompositeImage(image,image->compose,texture_image,x+
2297             texture_image->tile_offset.x,y+texture_image->tile_offset.y,
2298             exception);
2299           if (thread_status == MagickFalse)
2300             {
2301               status=thread_status;
2302               break;
2303             }
2304         }
2305         if (image->progress_monitor != (MagickProgressMonitor) NULL)
2306           {
2307             MagickBooleanType
2308               proceed;
2309
2310 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2311   #pragma omp critical (MagickCore_TextureImage)
2312 #endif
2313             proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2314               y,image->rows);
2315             if (proceed == MagickFalse)
2316               status=MagickFalse;
2317           }
2318       }
2319       (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
2320         image->rows,image->rows);
2321       return(status);
2322     }
2323   /*
2324     Tile texture onto the image background (optimized).
2325   */
2326   status=MagickTrue;
2327   image_view=AcquireCacheView(image);
2328   texture_view=AcquireCacheView(texture_image);
2329 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2330   #pragma omp parallel for schedule(static,4) shared(status) omp_throttle(1)
2331 #endif
2332   for (y=0; y < (ssize_t) image->rows; y++)
2333   {
2334     MagickBooleanType
2335       sync;
2336
2337     register const Quantum
2338       *p,
2339       *pixels;
2340
2341     register ssize_t
2342       x;
2343
2344     register Quantum
2345       *q;
2346
2347     size_t
2348       width;
2349
2350     if (status == MagickFalse)
2351       continue;
2352     pixels=GetCacheViewVirtualPixels(texture_view,texture_image->tile_offset.x,
2353       (y+texture_image->tile_offset.y) % texture_image->rows,
2354       texture_image->columns,1,exception);
2355     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2356     if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2357       {
2358         status=MagickFalse;
2359         continue;
2360       }
2361     for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture_image->columns)
2362     {
2363       register ssize_t
2364         j;
2365
2366       p=pixels;
2367       width=texture_image->columns;
2368       if ((x+(ssize_t) width) > (ssize_t) image->columns)
2369         width=image->columns-x;
2370       for (j=0; j < (ssize_t) width; j++)
2371       {
2372         register ssize_t
2373           i;
2374
2375         for (i=0; i < (ssize_t) GetPixelChannels(texture_image); i++)
2376         {
2377           PixelChannel
2378             channel;
2379
2380           PixelTrait
2381             texture_traits,
2382             traits;
2383
2384           channel=GetPixelChannelMapChannel(texture_image,i);
2385           texture_traits=GetPixelChannelMapTraits(texture_image,channel);
2386           traits=GetPixelChannelMapTraits(image,channel);
2387           if ((traits == UndefinedPixelTrait) ||
2388               (texture_traits == UndefinedPixelTrait))
2389             continue;
2390           SetPixelChannel(image,channel,p[i],q);
2391         }
2392         p+=GetPixelChannels(texture_image);
2393         q+=GetPixelChannels(image);
2394       }
2395     }
2396     sync=SyncCacheViewAuthenticPixels(image_view,exception);
2397     if (sync == MagickFalse)
2398       status=MagickFalse;
2399     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2400       {
2401         MagickBooleanType
2402           proceed;
2403
2404 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2405         #pragma omp critical (MagickCore_TextureImage)
2406 #endif
2407         proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
2408           image->rows);
2409         if (proceed == MagickFalse)
2410           status=MagickFalse;
2411       }
2412   }
2413   texture_view=DestroyCacheView(texture_view);
2414   image_view=DestroyCacheView(image_view);
2415   return(status);
2416 }