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