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