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