]> granicus.if.org Git - imagemagick/blob - MagickCore/composite.c
(no commit message)
[imagemagick] / MagickCore / composite.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %        CCCC   OOO   M   M  PPPP    OOO   SSSSS  IIIII  TTTTT  EEEEE         %
7 %       C      O   O  MM MM  P   P  O   O  SS       I      T    E             %
8 %       C      O   O  M M M  PPPP   O   O   SSS     I      T    EEE           %
9 %       C      O   O  M   M  P      O   O     SS    I      T    E             %
10 %        CCCC   OOO   M   M  P       OOO   SSSSS  IIIII    T    EEEEE         %
11 %                                                                             %
12 %                                                                             %
13 %                     MagickCore Image Composite Methods                      %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/cache-view.h"
48 #include "MagickCore/client.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/composite.h"
54 #include "MagickCore/composite-private.h"
55 #include "MagickCore/constitute.h"
56 #include "MagickCore/draw.h"
57 #include "MagickCore/fx.h"
58 #include "MagickCore/gem.h"
59 #include "MagickCore/geometry.h"
60 #include "MagickCore/image.h"
61 #include "MagickCore/image-private.h"
62 #include "MagickCore/list.h"
63 #include "MagickCore/log.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/monitor-private.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/option.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum.h"
71 #include "MagickCore/resample.h"
72 #include "MagickCore/resource_.h"
73 #include "MagickCore/string_.h"
74 #include "MagickCore/thread-private.h"
75 #include "MagickCore/utility.h"
76 #include "MagickCore/utility-private.h"
77 #include "MagickCore/version.h"
78 \f
79 /*
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %                                                                             %
82 %                                                                             %
83 %                                                                             %
84 %   C o m p o s i t e I m a g e                                               %
85 %                                                                             %
86 %                                                                             %
87 %                                                                             %
88 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89 %
90 %  CompositeImage() returns the second image composited onto the first
91 %  at the specified offset, using the specified composite method.
92 %
93 %  The format of the CompositeImage method is:
94 %
95 %      MagickBooleanType CompositeImage(Image *image,
96 %        const CompositeOperator compose,Image *composite_image,
97 %        const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
98 %
99 %  A description of each parameter follows:
100 %
101 %    o image: the destination image, modified by he composition
102 %
103 %    o compose: This operator affects how the composite is applied to
104 %      the image.  The operators and how they are utilized are listed here
105 %      http://www.w3.org/TR/SVG12/#compositing.
106 %
107 %    o composite_image: the composite (source) image.
108 %
109 %    o x_offset: the column offset of the composited image.
110 %
111 %    o y_offset: the row offset of the composited image.
112 %
113 %  Extra Controls from Image meta-data in 'composite_image' (artifacts)
114 %
115 %    o "compose:args"
116 %        A string containing extra numerical arguments for specific compose
117 %        methods, generally expressed as a 'geometry' or a comma separated list
118 %        of numbers.
119 %
120 %        Compose methods needing such arguments include "BlendCompositeOp" and
121 %        "DisplaceCompositeOp".
122 %
123 %    o "compose:outside-overlay"
124 %        Modify how the composition is to effect areas not directly covered
125 %        by the 'composite_image' at the offset given.  Normally this is
126 %        dependant on the 'compose' method, especially Duff-Porter methods.
127 %
128 %        If set to "false" then disable all normal handling of pixels not
129 %        covered by the composite_image.  Typically used for repeated tiling
130 %        of the composite_image by the calling API.
131 %
132 %        Previous to IM v6.5.3-3  this was called "modify-outside-overlay"
133 %
134 %    o exception: return any errors or warnings in this structure.
135 %
136 */
137
138 static inline double MagickMin(const double x,const double y)
139 {
140   if (x < y)
141     return(x);
142   return(y);
143 }
144 static inline double MagickMax(const double x,const double y)
145 {
146   if (x > y)
147     return(x);
148   return(y);
149 }
150
151 /*
152    Programmers notes on SVG specification.
153
154    A Composition is defined by...
155      Color Function :  f(Sc,Dc)  where Sc and Dc are the normizalized colors
156       Blending areas :  X = 1    for area of overlap   ie: f(Sc,Dc)
157                         Y = 1    for source preserved
158                         Z = 1    for destination preserved
159
160    Conversion to transparency (then optimized)
161       Dca' = f(Sc, Dc)*Sa*Da + Y*Sca*(1-Da) + Z*Dca*(1-Sa)
162       Da'  = X*Sa*Da + Y*Sa*(1-Da) + Z*Da*(1-Sa)
163
164    Where...
165      Sca = Sc*Sa     normalized Source color divided by Source alpha
166      Dca = Dc*Da     normalized Dest color divided by Dest alpha
167      Dc' = Dca'/Da'  the desired color value for this channel.
168
169    Da' (alpha result) is stored as 'gamma' in the functions.
170
171    The compose functions defined is just simplifications of the above
172    formula on a case by case bases.
173
174
175
176    The above SVG definitions also defines that Mathematical Composition
177    methods should use a 'Over' blending mode for Alpha Channel.
178    It however was not applied for composition modes of 'Plus', 'Minus',
179    the modulus versions of 'Add' and 'Subtract'.
180
181    Mathematical operator changes to be applied from IM v6.7...
182
183     1/ Modulus modes 'Add' and 'Subtract' are obsoleted and renamed
184        'ModulusAdd' and 'ModulusSubtract' for clarity.
185
186     2/ All mathematical compositions work as per the SVG specification
187        with regard to blending.  This now includes 'ModulusAdd' and
188        'ModulusSubtract'.
189
190     3/ When the special channel flag 'sync' (syncronize channel updates)
191        is turned off (enabled by default) then mathematical compositions are
192        only performed on the channels specified, and are applied
193        independantally of each other.  In other words the mathematics is
194        performed as 'pure' mathematical operations, rather than as image
195        operations.
196 */
197
198 static inline MagickRealType Atop(const MagickRealType p,
199   const MagickRealType Sa,const MagickRealType q,
200   const MagickRealType magick_unused(Da))
201 {
202   return(p*Sa+q*(1.0-Sa));  /* Da optimized out,  Da/gamma => 1.0 */
203 }
204
205 static inline void CompositeAtop(const PixelInfo *p,const PixelInfo *q,
206   PixelInfo *composite)
207 {
208   MagickRealType
209     Sa;
210
211   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
212   composite->alpha=q->alpha;   /* optimized  Da = 1.0-Gamma */
213   composite->red=Atop(p->red,Sa,q->red,1.0);
214   composite->green=Atop(p->green,Sa,q->green,1.0);
215   composite->blue=Atop(p->blue,Sa,q->blue,1.0);
216   if (q->colorspace == CMYKColorspace)
217     composite->black=Atop(p->black,Sa,q->black,1.0);
218 }
219
220 /*
221   Bumpmap: Multiply by overlay intensity
222   What is this Composition actually method for? Can't find any specification!
223
224   I think this was meant to be a 'HardLight effect' using a Shaded Image!
225   That is a Embossing, using a height map!  Better to do it piecemeal.
226 */
227 static inline void CompositeBumpmap(const PixelInfo *p,const PixelInfo *q,
228   PixelInfo *composite)
229 {
230   MagickRealType
231     intensity;
232
233   intensity=(MagickRealType) GetPixelInfoIntensity(p);
234   composite->red=QuantumScale*intensity*q->red;
235   composite->green=QuantumScale*intensity*q->green;
236   composite->blue=QuantumScale*intensity*q->blue;
237   composite->alpha=(MagickRealType) QuantumScale*intensity*p->alpha;
238   if (q->colorspace == CMYKColorspace)
239     composite->black=QuantumScale*intensity*q->black;
240 }
241
242 static inline void CompositeClear(const PixelInfo *q,PixelInfo *composite)
243 {
244   composite->alpha=(MagickRealType) TransparentAlpha;
245   composite->red=0.0;
246   composite->green=0.0;
247   composite->blue=0.0;
248   composite->black=1.0;
249 }
250
251 static MagickRealType ColorBurn(const MagickRealType Sca,
252   const MagickRealType Sa, const MagickRealType Dca,const MagickRealType Da)
253 {
254   if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca-Da) < MagickEpsilon))
255     return(Sa*Da+Dca*(1.0-Sa));
256   if (Sca < MagickEpsilon)
257     return(Dca*(1.0-Sa));
258   return(Sa*Da-Sa*MagickMin(Da,(Da-Dca)*Sa/Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
259 }
260
261 static inline void CompositeColorBurn(const PixelInfo *p,const PixelInfo *q,
262   PixelInfo *composite)
263 {
264   MagickRealType
265     Da,
266     gamma,
267     Sa;
268
269   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
270   Da=QuantumScale*q->alpha;
271   gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
272   composite->alpha=(MagickRealType) QuantumRange*gamma;
273   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
274   composite->red=gamma*ColorBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
275     q->red*Da,Da);
276   composite->green=gamma*ColorBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
277     q->green*Da,Da);
278   composite->blue=gamma*ColorBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
279     q->blue*Da,Da);
280   if (q->colorspace == CMYKColorspace)
281     composite->black=gamma*ColorBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
282       q->black*Da,Da);
283 }
284
285
286 static MagickRealType ColorDodge(const MagickRealType Sca,
287   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
288 {
289   /*
290     Working from first principles using the original formula:
291
292        f(Sc,Dc) = Dc/(1-Sc)
293
294     This works correctly!  Looks like the 2004 SVG model was right but just
295     required a extra condition for correct handling.
296   */
297   if ((fabs(Sca-Sa) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
298     return(Sca*(1.0-Da)+Dca*(1.0-Sa));
299   if (fabs(Sca-Sa) < MagickEpsilon)
300     return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
301   return(Dca*Sa*Sa/(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
302 }
303
304 static inline void CompositeColorDodge(const PixelInfo *p,const PixelInfo *q,
305   PixelInfo *composite)
306 {
307   MagickRealType
308     Da,
309     gamma,
310     Sa;
311
312   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
313   Da=QuantumScale*q->alpha;
314   gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
315   composite->alpha=(MagickRealType) QuantumRange*gamma;
316   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
317   composite->red=gamma*ColorDodge(QuantumScale*p->red*Sa,Sa,QuantumScale*
318     q->red*Da,Da);
319   composite->green=gamma*ColorDodge(QuantumScale*p->green*Sa,Sa,QuantumScale*
320     q->green*Da,Da);
321   composite->blue=gamma*ColorDodge(QuantumScale*p->blue*Sa,Sa,QuantumScale*
322     q->blue*Da,Da);
323   if (q->colorspace == CMYKColorspace)
324     composite->black=gamma*ColorDodge(QuantumScale*p->black*Sa,Sa,QuantumScale*
325       q->black*Da,Da);
326 }
327
328 static inline MagickRealType Darken(const MagickRealType p,
329   const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
330 {
331   if (p < q)
332     return(MagickOver_(p,alpha,q,beta));  /* src-over */
333   return(MagickOver_(q,beta,p,alpha));    /* dst-over */
334 }
335
336 static inline void CompositeDarken(const Image *image,const PixelInfo *p,
337   const PixelInfo *q,PixelInfo *composite)
338 {
339   MagickRealType
340     gamma;
341
342   /*
343     Darken is equivalent to a 'Minimum' method OR a greyscale version of a
344     binary 'Or' OR the 'Intersection' of pixel sets.
345   */
346   if (image->channel_mask != DefaultChannels)
347     {
348       /*
349         Handle channels as separate grayscale channels.
350       */
351       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
352         composite->red=MagickMin(p->red,q->red);
353       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
354         composite->green=MagickMin(p->green,q->green);
355       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
356         composite->blue=MagickMin(p->blue,q->blue);
357       if ((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0 &&
358           (q->colorspace == CMYKColorspace))
359         composite->black=MagickMin(p->black,q->black);
360       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
361         composite->alpha=MagickMax(p->alpha,q->alpha);
362       return;
363     }
364   composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
365   gamma=1.0-QuantumScale*composite->alpha;
366   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
367   composite->red=gamma*Darken(p->red,p->alpha,q->red,q->alpha);
368   composite->green=gamma*Darken(p->green,p->alpha,q->green,q->alpha);
369   composite->blue=gamma*Darken(p->blue,p->alpha,q->blue,q->alpha);
370   if (q->colorspace == CMYKColorspace)
371     composite->black=gamma*Darken(p->black,p->alpha,q->black,q->alpha);
372 }
373
374 static inline void CompositeDarkenIntensity(const Image *image,
375   const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
376 {
377   MagickRealType
378     Da,
379     Sa;
380
381   /*
382     Select the pixel based on the intensity level.
383     If 'Sync' flag select whole pixel based on alpha weighted intensity.
384     Otherwise use intensity only, but restrict copy according to channel.
385   */
386   if (image->channel_mask != DefaultChannels)
387     {
388       MagickBooleanType
389         from_p;
390
391       from_p=GetPixelInfoIntensity(p) < GetPixelInfoIntensity(q) ? MagickTrue :
392         MagickFalse;
393       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
394         composite->red=from_p != MagickFalse ? p->red : q->red;
395       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
396         composite->green=from_p != MagickFalse ? p->green : q->green;
397       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
398         composite->blue=from_p != MagickFalse ? p->blue : q->blue;
399       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
400           (q->colorspace == CMYKColorspace))
401         composite->black=from_p != MagickFalse ? p->black : q->black;
402       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
403         composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
404       return;
405     }
406   Sa=QuantumScale*p->alpha;
407   Da=QuantumScale*q->alpha;
408   *composite=(Sa*GetPixelInfoIntensity(p) < Da*GetPixelInfoIntensity(q)) ?
409     *p : *q;
410 }
411
412 static inline MagickRealType Difference(const MagickRealType p,
413   const MagickRealType Sa,const MagickRealType q,const MagickRealType Da)
414 {
415   /*
416     Optimized by Multipling by QuantumRange (taken from gamma).
417   */
418   return(Sa*p+Da*q-Sa*Da*2.0*MagickMin(p,q));
419 }
420
421 static inline void CompositeDifference(const Image *image,const PixelInfo *p,
422   const PixelInfo *q,PixelInfo *composite)
423 {
424   MagickRealType
425     Da,
426     gamma,
427     Sa;
428
429   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
430   Da=QuantumScale*q->alpha;
431   if (image->channel_mask != DefaultChannels)
432     {
433       /*
434         Handle channels as separate grayscale channels.
435       */
436       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
437         composite->red=fabs((double) (p->red-q->red));
438       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
439         composite->green=fabs((double) (p->green-q->green));
440       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
441         composite->blue=fabs((double) (p->blue-q->blue));
442       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
443           (q->colorspace == CMYKColorspace))
444         composite->black=fabs((double) (p->black-q->black));
445       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
446         composite->alpha=fabs((double) (p->alpha-q->alpha));
447      return;
448    }
449   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
450   composite->alpha=(MagickRealType) QuantumRange*gamma;
451   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
452   composite->red=gamma*Difference(p->red,Sa,q->red,Da);
453   composite->green=gamma*Difference(p->green,Sa,q->green,Da);
454   composite->blue=gamma*Difference(p->blue,Sa,q->blue,Da);
455   if (q->colorspace == CMYKColorspace)
456     composite->black=gamma*Difference(p->black,Sa,q->black,Da);
457 }
458
459 static MagickRealType Divide(const MagickRealType Sca,const MagickRealType Sa,
460   const MagickRealType Dca,const MagickRealType Da)
461 {
462   /*
463     Divide Source by Destination
464
465       f(Sc,Dc) = Sc / Dc
466
467     But with appropriate handling for special case of Dc == 0 specifically
468     so that   f(Black,Black)=Black  and  f(non-Black,Black)=White.
469     It is however also important to correctly do 'over' alpha blending which
470     is why the formula becomes so complex.
471   */
472   if ((fabs(Sca) < MagickEpsilon) && (fabs(Dca) < MagickEpsilon))
473     return(Sca*(1.0-Da)+Dca*(1.0-Sa));
474   if (fabs(Dca) < MagickEpsilon)
475     return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
476   return(Sca*Da*Da/Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
477 }
478
479 static inline void CompositeDivide(const Image *image,const PixelInfo *p,
480   const PixelInfo *q,PixelInfo *composite)
481 {
482   MagickRealType
483     Da,
484     gamma,
485     Sa;
486
487   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
488   Da=QuantumScale*q->alpha;
489   if (image->channel_mask != DefaultChannels)
490     {
491       /*
492         Handle channels as separate grayscale channels.
493       */
494       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
495         composite->red=QuantumRange*Divide(QuantumScale*p->red,1.0,
496           QuantumScale*q->red,1.0);
497       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
498         composite->green=QuantumRange*Divide(QuantumScale*p->green,1.0,
499           QuantumScale*q->green,1.0);
500       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
501         composite->blue=QuantumRange*Divide(QuantumScale*p->blue,1.0,
502           QuantumScale*q->blue,1.0);
503       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
504           (q->colorspace == CMYKColorspace))
505         composite->black=QuantumRange*Divide(QuantumScale*p->black,1.0,
506           QuantumScale*q->black,1.0);
507       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
508         composite->alpha=QuantumRange*(1.0-Divide(Sa,1.0,Da,1.0));
509       return;
510     }
511   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
512   composite->alpha=(MagickRealType) QuantumRange*gamma;
513   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
514   composite->red=gamma*Divide(QuantumScale*p->red*Sa,Sa,QuantumScale*
515     q->red*Da,Da);
516   composite->green=gamma*Divide(QuantumScale*p->green*Sa,Sa,QuantumScale*
517     q->green*Da,Da);
518   composite->blue=gamma*Divide(QuantumScale*p->blue*Sa,Sa,QuantumScale*
519     q->blue*Da,Da);
520   if (q->colorspace == CMYKColorspace)
521     composite->black=gamma*Divide(QuantumScale*p->black*Sa,Sa,QuantumScale*
522       q->black*Da,Da);
523 }
524
525 static MagickRealType Exclusion(const MagickRealType Sca,
526   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
527 {
528   return(Sca*Da+Dca*Sa-2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
529 }
530
531 static inline void CompositeExclusion(const Image *image,const PixelInfo *p,
532   const PixelInfo *q,PixelInfo *composite)
533 {
534   MagickRealType
535     gamma,
536     Sa,
537     Da;
538
539   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
540   Da=QuantumScale*q->alpha;
541   if (image->channel_mask != DefaultChannels)
542     {
543       /*
544         Handle channels as separate grayscale channels.
545       */
546       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
547         composite->red=QuantumRange*Exclusion(QuantumScale*p->red,1.0,
548           QuantumScale*q->red,1.0);
549       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
550         composite->green=QuantumRange*Exclusion(QuantumScale*p->green,1.0,
551           QuantumScale*q->green,1.0);
552       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
553         composite->blue=QuantumRange*Exclusion(QuantumScale*p->blue,1.0,
554           QuantumScale*q->blue,1.0);
555       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
556           (q->colorspace == CMYKColorspace))
557         composite->black=QuantumRange*Exclusion(QuantumScale*p->black,1.0,
558           QuantumScale*q->black,1.0);
559       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
560         composite->alpha=QuantumRange*(1.0-Exclusion(Sa,1.0,Da,1.0));
561       return;
562     }
563   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
564   composite->alpha=(MagickRealType) QuantumRange*gamma;
565   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
566   composite->red=gamma*Exclusion(QuantumScale*p->red*Sa,Sa,QuantumScale*
567     q->red*Da,Da);
568   composite->green=gamma*Exclusion(QuantumScale*p->green*Sa,Sa,QuantumScale*
569     q->green*Da,Da);
570   composite->blue=gamma*Exclusion(QuantumScale*p->blue*Sa,Sa,QuantumScale*
571     q->blue*Da,Da);
572   if (q->colorspace == CMYKColorspace)
573     composite->black=gamma*Exclusion(QuantumScale*p->black*Sa,Sa,
574       QuantumScale*q->black*Da,Da);
575 }
576
577 static MagickRealType HardLight(const MagickRealType Sca,
578   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
579 {
580   if ((2.0*Sca) < Sa)
581     return(2.0*Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
582   return(Sa*Da-2.0*(Da-Dca)*(Sa-Sca)+Sca*(1.0-Da)+Dca*(1.0-Sa));
583 }
584
585 static inline void CompositeHardLight(const PixelInfo *p,const PixelInfo *q,
586   PixelInfo *composite)
587 {
588   MagickRealType
589     Da,
590     gamma,
591     Sa;
592
593   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
594   Da=QuantumScale*q->alpha;
595   gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
596   composite->alpha=(MagickRealType) QuantumRange*gamma;
597   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
598   composite->red=gamma*HardLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
599     q->red*Da,Da);
600   composite->green=gamma*HardLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
601     q->green*Da,Da);
602   composite->blue=gamma*HardLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
603     q->blue*Da,Da);
604   if (q->colorspace == CMYKColorspace)
605     composite->black=gamma*HardLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
606       q->black*Da,Da);
607 }
608
609 static void CompositeHSB(const MagickRealType red,const MagickRealType green,
610   const MagickRealType blue,double *hue,double *saturation,double *brightness)
611 {
612   MagickRealType
613     delta,
614     max,
615     min;
616
617   /*
618     Convert RGB to HSB colorspace.
619   */
620   assert(hue != (double *) NULL);
621   assert(saturation != (double *) NULL);
622   assert(brightness != (double *) NULL);
623   max=(red > green ? red : green);
624   if (blue > max)
625     max=blue;
626   min=(red < green ? red : green);
627   if (blue < min)
628     min=blue;
629   *hue=0.0;
630   *saturation=0.0;
631   *brightness=(double) (QuantumScale*max);
632   if (fabs(max) < MagickEpsilon)
633     return;
634   *saturation=(double) (1.0-min/max);
635   delta=max-min;
636   if (fabs(delta) < MagickEpsilon)
637     return;
638   if (fabs(red-max) < MagickEpsilon)
639     *hue=(double) ((green-blue)/delta);
640   else
641     if (fabs(green-max) < MagickEpsilon)
642       *hue=(double) (2.0+(blue-red)/delta);
643     else
644       if (fabs(blue-max) < MagickEpsilon)
645         *hue=(double) (4.0+(red-green)/delta);
646   *hue/=6.0;
647   if (*hue < 0.0)
648     *hue+=1.0;
649 }
650
651 #if 0
652 static inline MagickRealType In(const MagickRealType p,const MagickRealType Sa,
653   const MagickRealType magick_unused(q),const MagickRealType Da)
654 {
655   return(Sa*p*Da);
656 }
657 #endif
658
659 static inline void CompositeIn(const PixelInfo *p,const PixelInfo *q,
660   PixelInfo *composite)
661 {
662 #if 0
663   MagickRealType
664     gamma,
665     Sa,
666     Da;
667
668   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
669   Da=QuantumScale*q->alpha;
670   gamma=Sa*Da;
671   composite->alpha=(MagickRealType) QuantumRange*gamma;
672   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
673   /* really this just preserves the src or p color as is! */
674   composite->red=gamma*In(p->red,Sa,q->red,Da);
675   composite->green=gamma*In(p->green,Sa,q->green,Da);
676   composite->blue=gamma*In(p->blue,Sa,q->blue,Da);
677   if (q->colorspace == CMYKColorspace)
678     composite->black=gamma*In(p->black,Sa,q->black,Da);
679 #else
680   /* Simplified to a multiply of the Alpha Channel */
681   *composite=*p; /* structure copy */
682   composite->alpha=QuantumScale*p->alpha*q->alpha;
683 #endif
684 }
685
686 static inline MagickRealType Lighten(const MagickRealType p,
687   const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
688 {
689    if (p > q)
690      return(MagickOver_(p,alpha,q,beta));  /* src-over */
691    return(MagickOver_(q,beta,p,alpha));    /* dst-over */
692 }
693
694 static inline void CompositeLighten(const Image *image,const PixelInfo *p,
695   const PixelInfo *q,PixelInfo *composite)
696 {
697   MagickRealType
698     gamma;
699
700   /*
701     Lighten is also equvalent to a 'Maximum' method OR a greyscale version of a
702     binary 'And' OR the 'Union' of pixel sets.
703   */
704   if (image->channel_mask != DefaultChannels)
705     {
706       /*
707         Handle channels as separate grayscale channels
708       */
709       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
710         composite->red=MagickMax(p->red,q->red);
711       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
712         composite->green=MagickMax(p->green,q->green);
713       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
714         composite->blue=MagickMax(p->blue,q->blue);
715       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
716           (q->colorspace == CMYKColorspace))
717         composite->black=MagickMax(p->black,q->black);
718       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
719         composite->alpha=MagickMin(p->alpha,q->alpha);
720       return;
721     }
722   composite->alpha=QuantumScale*p->alpha*q->alpha; /* Over Blend */
723   gamma=1.0-QuantumScale*composite->alpha;
724   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
725   composite->red=gamma*Lighten(p->red,p->alpha,q->red,q->alpha);
726   composite->green=gamma*Lighten(p->green,p->alpha,q->green,q->alpha);
727   composite->blue=gamma*Lighten(p->blue,p->alpha,q->blue,q->alpha);
728   if (q->colorspace == CMYKColorspace)
729     composite->black=gamma*Lighten(p->black,p->alpha,q->black,q->alpha);
730 }
731
732 static inline void CompositeLightenIntensity(const Image *image,
733   const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
734 {
735   MagickRealType
736     Da,
737     Sa;
738
739   /*
740     Select the pixel based on the intensity level.
741     If 'Sync' flag select whole pixel based on alpha weighted intensity.
742     Otherwise use Intenisty only, but restrict copy according to channel.
743   */
744   if (image->channel_mask != DefaultChannels)
745     {
746       MagickBooleanType
747         from_p;
748
749       from_p=GetPixelInfoIntensity(p) > GetPixelInfoIntensity(q) ? MagickTrue :
750         MagickFalse;
751       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
752         composite->red=from_p != MagickFalse ? p->red : q->red;
753       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
754         composite->green=from_p != MagickFalse ? p->green : q->green;
755       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
756         composite->blue=from_p != MagickFalse ? p->blue : q->blue;
757       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
758           (q->colorspace == CMYKColorspace))
759         composite->black=from_p != MagickFalse ? p->black : q->black;
760       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
761         composite->alpha=from_p != MagickFalse ? p->alpha : q->alpha;
762       return;
763     }
764   Sa=QuantumScale*p->alpha;
765   Da=QuantumScale*q->alpha;
766   *composite=(Sa*GetPixelInfoIntensity(p) > Da*GetPixelInfoIntensity(q)) ?
767     *p : *q;
768 }
769
770 static inline void CompositeLinearDodge(const PixelInfo *p,const PixelInfo *q,
771   PixelInfo *composite)
772 {
773   MagickRealType
774     Da,
775     gamma,
776     Sa;
777
778   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
779   Da=QuantumScale*q->alpha;
780   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
781   composite->alpha=(MagickRealType) QuantumRange*gamma;
782   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
783   composite->red=gamma*(p->red*Sa+q->red*Da);
784   composite->green=gamma*(p->green*Sa+q->green*Da);
785   composite->blue=gamma*(p->blue*Sa+q->blue*Da);
786   if (q->colorspace == CMYKColorspace)
787     composite->black=gamma*(p->black*Sa+q->black*Da);
788 }
789
790
791 static inline MagickRealType LinearBurn(const MagickRealType Sca,
792   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
793 {
794   /*
795     LinearBurn: as defined by Abode Photoshop, according to
796     http://www.simplefilter.de/en/basics/mixmods.html is:
797
798       f(Sc,Dc) = Sc + Dc - 1
799   */
800   return(Sca+Dca-Sa*Da);
801 }
802
803 static inline void CompositeLinearBurn(const PixelInfo *p,const PixelInfo *q,
804   PixelInfo *composite)
805 {
806   MagickRealType
807     Da,
808     gamma,
809     Sa;
810
811   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
812   Da=QuantumScale*q->alpha;
813   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
814   composite->alpha=(MagickRealType) QuantumRange*gamma;
815   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
816   composite->red=gamma*LinearBurn(QuantumScale*p->red*Sa,Sa,QuantumScale*
817     q->red*Da,Da);
818   composite->green=gamma*LinearBurn(QuantumScale*p->green*Sa,Sa,QuantumScale*
819     q->green*Da,Da);
820   composite->blue=gamma*LinearBurn(QuantumScale*p->blue*Sa,Sa,QuantumScale*
821     q->blue*Da,Da);
822   if (q->colorspace == CMYKColorspace)
823     composite->black=gamma*LinearBurn(QuantumScale*p->black*Sa,Sa,QuantumScale*
824       q->black*Da,Da);
825 }
826
827 static inline MagickRealType LinearLight(const MagickRealType Sca,
828   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
829 {
830   /*
831     LinearLight: as defined by Abode Photoshop, according to
832     http://www.simplefilter.de/en/basics/mixmods.html is:
833
834       f(Sc,Dc) = Dc + 2*Sc - 1
835   */
836   return((Sca-Sa)*Da+Sca+Dca);
837 }
838
839 static inline void CompositeLinearLight(const PixelInfo *p,const PixelInfo *q,
840   PixelInfo *composite)
841 {
842   MagickRealType
843     Da,
844     gamma,
845     Sa;
846
847   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
848   Da=QuantumScale*q->alpha;
849   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
850   composite->alpha=(MagickRealType) QuantumRange*gamma;
851   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
852   composite->red=gamma*LinearLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
853     q->red*Da,Da);
854   composite->green=gamma*LinearLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
855     q->green*Da,Da);
856   composite->blue=gamma*LinearLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
857     q->blue*Da,Da);
858   if (q->colorspace == CMYKColorspace)
859     composite->black=gamma*LinearLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
860       q->black*Da,Da);
861 }
862
863 static inline MagickRealType Mathematics(const MagickRealType Sca,
864   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da,
865   const GeometryInfo *geometry_info)
866 {
867   MagickRealType
868     gamma;
869
870   /*
871     'Mathematics' a free form user control mathematical composition is defined
872     as...
873
874        f(Sc,Dc) = A*Sc*Dc + B*Sc + C*Dc + D
875
876     Where the arguments A,B,C,D are (currently) passed to composite as
877     a command separated 'geometry' string in "compose:args" image artifact.
878
879        A = a->rho,   B = a->sigma,  C = a->xi,  D = a->psi
880
881     Applying the SVG transparency formula (see above), we get...
882
883      Dca' = Sa*Da*f(Sc,Dc) + Sca*(1.0-Da) + Dca*(1.0-Sa)
884
885      Dca' = A*Sca*Dca + B*Sca*Da + C*Dca*Sa + D*Sa*Da + Sca*(1.0-Da) +
886        Dca*(1.0-Sa)
887   */
888   gamma=geometry_info->rho*Sca*Dca+geometry_info->sigma*Sca*Da+
889     geometry_info->xi*Dca*Sa+geometry_info->psi*Sa*Da+Sca*(1.0-Da)+
890     Dca*(1.0-Sa);
891   return(gamma);
892 }
893
894 static inline void CompositeMathematics(const Image *image,const PixelInfo *p,
895   const PixelInfo *q,const GeometryInfo *args,PixelInfo *composite)
896 {
897   MagickRealType
898     Da,
899     gamma,
900     Sa;
901
902   Sa=QuantumScale*p->alpha; /* ??? - AT */
903   Da=QuantumScale*q->alpha;
904   if (image->channel_mask != DefaultChannels)
905     {
906       /*
907         Handle channels as separate grayscale channels.
908       */
909       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
910         composite->red=QuantumRange*Mathematics(QuantumScale*p->red,1.0,
911           QuantumScale*q->red,1.0,args);
912       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
913         composite->green=QuantumRange*Mathematics(QuantumScale*p->green,1.0,
914           QuantumScale*q->green,1.0,args);
915       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
916         composite->blue=QuantumRange*Mathematics(QuantumScale*p->blue,1.0,
917           QuantumScale*q->blue,1.0,args);
918       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
919           (q->colorspace == CMYKColorspace))
920         composite->black=QuantumRange*Mathematics(QuantumScale*p->black,1.0,
921           QuantumScale*q->black,1.0,args);
922       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
923         composite->alpha=QuantumRange*(1.0-Mathematics(Sa,1.0,Da,1.0,args));
924       return;
925     }
926   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
927   composite->alpha=(MagickRealType) QuantumRange*gamma;
928   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
929   composite->red=gamma*Mathematics(QuantumScale*p->red*Sa,Sa,QuantumScale*
930     q->red*Da,Da,args);
931   composite->green=gamma*Mathematics(QuantumScale*p->green*Sa,Sa,
932     QuantumScale*q->green*Da,Da,args);
933   composite->blue=gamma*Mathematics(QuantumScale*p->blue*Sa,Sa,QuantumScale*
934     q->blue*Da,Da,args);
935   if (q->colorspace == CMYKColorspace)
936     composite->black=gamma*Mathematics(QuantumScale*p->black*Sa,Sa,
937       QuantumScale*q->black*Da,Da,args);
938 }
939
940 static inline void CompositePlus(const Image *image,const PixelInfo *p,
941   const PixelInfo *q,PixelInfo *composite)
942 {
943   /*
944     NOTE: "Plus" does not use 'over' alpha-blending but uses a special
945     'plus' form of alph-blending. It is the ONLY mathematical operator to
946     do this. this is what makes it different to the otherwise equivalent
947     "LinearDodge" composition method.
948
949     Note however that color channels are still effected by the alpha channel
950     as a result of the blending, making it just as useless for independant
951     channel maths, just like all other mathematical composition methods.
952
953     As such the removal of the 'sync' flag, is still a usful convention.
954
955     The CompositePixelInfoPlus() function is defined in
956     "composite-private.h" so it can also be used for Image Blending.
957   */
958   if (image->channel_mask != DefaultChannels)
959     {
960       /*
961         Handle channels as separate grayscale channels.
962       */
963       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
964         composite->red=p->red+q->red;
965       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
966         composite->green=p->green+q->green;
967       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
968         composite->blue=p->blue+q->blue;
969       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
970           (q->colorspace == CMYKColorspace))
971         composite->black=p->black+q->black;
972       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
973         composite->alpha=p->alpha+q->alpha-QuantumRange;
974       return;
975     }
976   CompositePixelInfoPlus(p,p->alpha,q,q->alpha,composite);
977 }
978
979 static inline MagickRealType Minus(const MagickRealType Sca,
980   const MagickRealType Sa,const MagickRealType Dca,
981   const MagickRealType magick_unused(Da))
982 {
983   /*
984     Minus Source from Destination
985
986       f(Sc,Dc) = Sc - Dc
987   */
988   return(Sca+Dca-2.0*Dca*Sa);
989 }
990
991 static inline void CompositeMinus(const Image *image,const PixelInfo *p,
992   const PixelInfo *q,PixelInfo *composite)
993 {
994   MagickRealType
995     Da,
996     gamma,
997     Sa;
998
999   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1000   Da=QuantumScale*q->alpha;
1001   if (image->channel_mask != DefaultChannels)
1002     {
1003       /*
1004         Handle channels as separate grayscale channels.
1005       */
1006       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1007         composite->red=p->red-q->red;
1008       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1009         composite->green=p->green-q->green;
1010       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1011         composite->blue=p->blue-q->blue;
1012       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1013           (q->colorspace == CMYKColorspace))
1014         composite->black=p->black-q->black;
1015       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1016         composite->alpha=QuantumRange*(1.0-(Sa-Da));
1017       return;
1018     }
1019   gamma=RoundToUnity(Sa+Da-Sa*Da);  /* over blend, as per SVG doc */
1020   composite->alpha=(MagickRealType) QuantumRange*gamma;
1021   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1022   composite->red=gamma*Minus(p->red*Sa,Sa,q->red*Da,Da);
1023   composite->green=gamma*Minus(p->green*Sa,Sa,q->green*Da,Da);
1024   composite->blue=gamma*Minus(p->blue*Sa,Sa,q->blue*Da,Da);
1025   if (q->colorspace == CMYKColorspace)
1026     composite->black=gamma*Minus(p->black*Sa,Sa,q->black*Da,Da);
1027 }
1028
1029 static inline MagickRealType ModulusAdd(const MagickRealType p,
1030   const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
1031 {
1032   MagickRealType
1033     pixel;
1034
1035   pixel=p+q;
1036   if (pixel > QuantumRange)
1037     pixel-=(QuantumRange+1.0);
1038   return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
1039 }
1040
1041 static inline void CompositeModulusAdd(const Image *image,const PixelInfo *p,
1042   const PixelInfo *q,PixelInfo *composite)
1043 {
1044   MagickRealType
1045     Da,
1046     gamma,
1047     Sa;
1048
1049   if (image->channel_mask != DefaultChannels)
1050     {
1051       /*
1052         Handle channels as separate grayscale channels.
1053       */
1054       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1055         composite->red=ModulusAdd(p->red,1.0,q->red,1.0);
1056       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1057         composite->green=ModulusAdd(p->green,1.0,q->green,1.0);
1058       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1059         composite->blue=ModulusAdd(p->blue,1.0,q->blue,1.0);
1060       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1061           (q->colorspace == CMYKColorspace))
1062         composite->black=ModulusAdd(p->black,1.0,q->black,1.0);
1063       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1064         composite->alpha=ModulusAdd(p->alpha,1.0,q->alpha,1.0);
1065       return;
1066     }
1067   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1068   Da=QuantumScale*q->alpha;
1069   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1070   composite->alpha=(MagickRealType) QuantumRange*gamma;
1071   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1072   composite->red=ModulusAdd(p->red,Sa,q->red,Da);
1073   composite->green=ModulusAdd(p->green,Sa,q->green,Da);
1074   composite->blue=ModulusAdd(p->blue,Sa,q->blue,Da);
1075   if (q->colorspace == CMYKColorspace)
1076     composite->black=ModulusAdd(p->black,Sa,q->black,Da);
1077 }
1078
1079 static inline MagickRealType ModulusSubtract(const MagickRealType p,
1080   const MagickRealType Sa,const MagickRealType q, const MagickRealType Da)
1081 {
1082   MagickRealType
1083     pixel;
1084
1085   pixel=p-q;
1086   if (pixel < 0.0)
1087     pixel+=(QuantumRange+1.0);
1088   return(pixel*Sa*Da+p*Sa*(1.0-Da)+q*Da*(1.0-Sa));
1089 }
1090
1091 static inline void CompositeModulusSubtract(const Image *image,
1092   const PixelInfo *p,const PixelInfo *q,PixelInfo *composite)
1093 {
1094   MagickRealType
1095     Da,
1096     gamma,
1097     Sa;
1098
1099   if (image->channel_mask != DefaultChannels)
1100     {
1101       /*
1102         Handle channels as separate grayscale channels,
1103       */
1104       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1105         composite->red=ModulusSubtract(p->red,1.0,q->red,1.0);
1106       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1107         composite->green=ModulusSubtract(p->green,1.0,q->green,1.0);
1108       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1109         composite->blue=ModulusSubtract(p->blue,1.0,q->blue,1.0);
1110       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1111           (q->colorspace == CMYKColorspace))
1112         composite->black=ModulusSubtract(p->black,1.0,q->black,1.0);
1113       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1114         composite->alpha=ModulusSubtract(p->alpha,1.0,q->alpha,1.0);
1115       return;
1116     }
1117   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1118   Da=QuantumScale*q->alpha;
1119   gamma = RoundToUnity(Sa+Da-Sa*Da);
1120   composite->alpha=(MagickRealType) QuantumRange*gamma;
1121   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1122   composite->red=ModulusSubtract(p->red,Sa,q->red,Da);
1123   composite->green=ModulusSubtract(p->green,Sa,q->green,Da);
1124   composite->blue=ModulusSubtract(p->blue,Sa,q->blue,Da);
1125   if (q->colorspace == CMYKColorspace)
1126     composite->black=ModulusSubtract(p->black,Sa,q->black,Da);
1127 }
1128
1129 static  inline MagickRealType Multiply(const MagickRealType Sca,
1130   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
1131 {
1132   return(Sca*Dca+Sca*(1.0-Da)+Dca*(1.0-Sa));
1133 }
1134
1135 static inline void CompositeMultiply(const Image *image,const PixelInfo *p,
1136   const PixelInfo *q,PixelInfo *composite)
1137 {
1138   MagickRealType
1139     Da,
1140     gamma,
1141     Sa;
1142
1143   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1144   Da=QuantumScale*q->alpha;
1145   if (image->channel_mask != DefaultChannels)
1146     {
1147       /*
1148         Handle channels as separate grayscale channels.
1149       */
1150       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1151         composite->red=QuantumScale*p->red*q->red;
1152       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1153         composite->green=QuantumScale*p->green*q->green;
1154       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1155         composite->blue=QuantumScale*p->blue*q->blue;
1156       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1157           (q->colorspace == CMYKColorspace))
1158         composite->black=QuantumScale*p->black*q->black;
1159       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1160         composite->alpha=QuantumRange*(1.0-Sa*Da);
1161       return;
1162     }
1163   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1164   composite->alpha=(MagickRealType) QuantumRange*gamma;
1165   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1166   composite->red=gamma*Multiply(QuantumScale*p->red*Sa,Sa,QuantumScale*
1167     q->red*Da,Da);
1168   composite->green=gamma*Multiply(QuantumScale*p->green*Sa,Sa,QuantumScale*
1169     q->green*Da,Da);
1170   composite->blue=gamma*Multiply(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1171     q->blue*Da,Da);
1172   if (q->colorspace == CMYKColorspace)
1173     composite->black=gamma*Multiply(QuantumScale*p->black*Sa,Sa,
1174       QuantumScale*q->black*Da,Da);
1175 }
1176
1177 #if 0
1178 static inline MagickRealType Out(const MagickRealType p,const MagickRealType Sa,
1179   const MagickRealType magick_unused(q),const MagickRealType Da)
1180 {
1181   return(Sa*p*(1.0-Da));
1182 }
1183 #endif
1184
1185 static inline void CompositeOut(const PixelInfo *p,const PixelInfo *q,
1186   PixelInfo *composite)
1187 {
1188 #if 0
1189   MagickRealType
1190     Sa,
1191     Da,
1192     gamma;
1193
1194   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1195   Da=QuantumScale*q->alpha;
1196   gamma=Sa*(1.0-Da);
1197   composite->alpha=(MagickRealType) QuantumRange*gamma;
1198   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1199   composite->red=gamma*Out(p->red,Sa,q->red,Da);
1200   composite->green=gamma*Out(p->green,Sa,q->green,Da);
1201   composite->blue=gamma*Out(p->blue,Sa,q->blue,Da);
1202   if (q->colorspace == CMYKColorspace)
1203     composite->black=gamma*Out(p->black,Sa,q->black,Da);
1204 #else
1205   /* Simplified to a negated multiply of the Alpha Channel */
1206   *composite=*p; /* structure copy */
1207   composite->alpha=p->alpha*(1.0-QuantumScale*q->alpha);
1208 #endif
1209 }
1210
1211 static MagickRealType PegtopLight(const MagickRealType Sca,
1212   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
1213 {
1214   /*
1215     PegTop: A Soft-Light alternative: A continuous version of the Softlight
1216     function, producing very similar results.
1217
1218     f(Sc,Dc) = Dc^2*(1-2*Sc) + 2*Sc*Dc
1219
1220     See http://www.pegtop.net/delphi/articles/blendmodes/softlight.htm.
1221   */
1222   if (fabs(Da) < MagickEpsilon)
1223     return(Sca);
1224   return(Dca*Dca*(Sa-2.0*Sca)/Da+Sca*(2.0*Dca+1.0-Da)+Dca*(1.0-Sa));
1225 }
1226
1227 static inline void CompositePegtopLight(const PixelInfo *p,const PixelInfo *q,
1228   PixelInfo *composite)
1229 {
1230   MagickRealType
1231     Da,
1232     gamma,
1233     Sa;
1234
1235   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1236   Da=QuantumScale*q->alpha;
1237   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1238   composite->alpha=(MagickRealType) QuantumRange*gamma;
1239   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1240   composite->red=gamma*PegtopLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1241     q->red*Da,Da);
1242   composite->green=gamma*PegtopLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1243     q->green*Da,Da);
1244   composite->blue=gamma*PegtopLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1245     q->blue*Da,Da);
1246   if (q->colorspace == CMYKColorspace)
1247     composite->black=gamma*PegtopLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
1248       q->black*Da,Da);
1249 }
1250
1251 static MagickRealType PinLight(const MagickRealType Sca,const MagickRealType Sa,
1252   const MagickRealType Dca,const MagickRealType Da)
1253 {
1254   /*
1255     PinLight: A Photoshop 7 composition method
1256     http://www.simplefilter.de/en/basics/mixmods.html
1257
1258     f(Sc,Dc) = Dc<2*Sc-1 ? 2*Sc-1 : Dc>2*Sc   ? 2*Sc : Dc
1259   */
1260   if (Dca*Sa < Da*(2.0*Sca-Sa))
1261     return(Sca*(Da+1.0)-Sa*Da+Dca*(1.0-Sa));
1262   if ((Dca*Sa) > (2.0*Sca*Da))
1263     return(Sca*Da+Sca+Dca*(1.0-Sa));
1264   return(Sca*(1.0-Da)+Dca);
1265 }
1266
1267 static inline void CompositePinLight(const PixelInfo *p,const PixelInfo *q,
1268   PixelInfo *composite)
1269 {
1270   MagickRealType
1271     Da,
1272     gamma,
1273     Sa;
1274
1275   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1276   Da=QuantumScale*q->alpha;
1277   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1278   composite->alpha=(MagickRealType) QuantumRange*gamma;
1279   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1280   composite->red=gamma*PinLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1281     q->red*Da,Da);
1282   composite->green=gamma*PinLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1283     q->green*Da,Da);
1284   composite->blue=gamma*PinLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1285     q->blue*Da,Da);
1286   if (q->colorspace == CMYKColorspace)
1287     composite->black=gamma*PinLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
1288       q->black*Da,Da);
1289 }
1290
1291 static inline MagickRealType Screen(const MagickRealType Sca,
1292   const MagickRealType Dca)
1293 {
1294   /*
1295     Screen:  A negated multiply
1296       f(Sc,Dc) = 1.0-(1.0-Sc)*(1.0-Dc)
1297   */
1298   return(Sca+Dca-Sca*Dca);
1299 }
1300
1301 static inline void CompositeScreen(const Image *image,const PixelInfo *p,
1302   const PixelInfo *q,PixelInfo *composite)
1303 {
1304   MagickRealType
1305     Da,
1306     gamma,
1307     Sa;
1308
1309   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1310   Da=QuantumScale*q->alpha;
1311   if (image->channel_mask != DefaultChannels)
1312     {
1313       /*
1314         Handle channels as separate grayscale channels.
1315       */
1316       if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1317         composite->red=QuantumRange*Screen(QuantumScale*p->red,
1318           QuantumScale*q->red);
1319       if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1320         composite->green=QuantumRange*Screen(QuantumScale*p->green,
1321           QuantumScale*q->green);
1322       if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1323         composite->blue=QuantumRange*Screen(QuantumScale*p->blue,
1324           QuantumScale*q->blue);
1325       if (((GetPixelBlackTraits(image) & UpdatePixelTrait) != 0) &&
1326           (q->colorspace == CMYKColorspace))
1327         composite->black=QuantumRange*Screen(QuantumScale*p->black,
1328           QuantumScale*q->black);
1329       if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1330         composite->alpha=QuantumRange*(1.0-Screen(Sa,Da));
1331       return;
1332     }
1333   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1334   composite->alpha=(MagickRealType) QuantumRange*gamma;
1335   Sa*=QuantumScale; Da*=QuantumScale; /* optimization */
1336   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1337   composite->red=gamma*Screen(p->red*Sa,q->red*Da);
1338   composite->green=gamma*Screen(p->green*Sa,q->green*Da);
1339   composite->blue=gamma*Screen(p->blue*Sa,q->blue*Da);
1340   if (q->colorspace == CMYKColorspace)
1341     composite->black=gamma*Screen(p->black*Sa,q->black*Da);
1342 }
1343
1344 static MagickRealType SoftLight(const MagickRealType Sca,
1345   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
1346 {
1347   MagickRealType
1348     alpha,
1349     beta;
1350
1351   /*
1352     New specification:  March 2009 SVG specification.
1353   */
1354   alpha=Dca/Da;
1355   if ((2.0*Sca) < Sa)
1356     return(Dca*(Sa+(2.0*Sca-Sa)*(1.0-alpha))+Sca*(1.0-Da)+Dca*(1.0-Sa));
1357   if (((2.0*Sca) > Sa) && ((4.0*Dca) <= Da))
1358     {
1359       beta=Dca*Sa+Da*(2.0*Sca-Sa)*(4.0*alpha*(4.0*alpha+1.0)*(alpha-1.0)+7.0*
1360         alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
1361       return(beta);
1362     }
1363   beta=Dca*Sa+Da*(2.0*Sca-Sa)*(pow(alpha,0.5)-alpha)+Sca*(1.0-Da)+Dca*(1.0-Sa);
1364   return(beta);
1365 }
1366
1367 static inline void CompositeSoftLight(const PixelInfo *p,const PixelInfo *q,
1368   PixelInfo *composite)
1369 {
1370   MagickRealType
1371     Da,
1372     gamma,
1373     Sa;
1374
1375   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1376   Da=QuantumScale*q->alpha;
1377   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1378   composite->alpha=(MagickRealType) QuantumRange*gamma;
1379   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1380   composite->red=gamma*SoftLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1381     q->red*Da,Da);
1382   composite->green=gamma*SoftLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1383     q->green*Da,Da);
1384   composite->blue=gamma*SoftLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1385     q->blue*Da,Da);
1386   if (q->colorspace == CMYKColorspace)
1387     composite->black=gamma*SoftLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
1388       q->black*Da,Da);
1389 }
1390
1391 static inline MagickRealType Threshold(const MagickRealType p,
1392   const MagickRealType q,const MagickRealType threshold,
1393   const MagickRealType amount)
1394 {
1395   MagickRealType
1396     delta;
1397
1398   /*
1399     Multiply difference by amount, if differance larger than threshold???
1400     What use this is is completely unknown.  The Opacity calculation appears to
1401     be inverted  -- Anthony Thyssen
1402
1403     Deprecated.
1404   */
1405   delta=p-q;
1406   if ((MagickRealType) fabs((double) (2.0*delta)) < threshold)
1407     return(q);
1408   return(q+delta*amount);
1409 }
1410
1411 static inline void CompositeThreshold(const PixelInfo *p,const PixelInfo *q,
1412   const MagickRealType threshold,const MagickRealType amount,
1413   PixelInfo *composite)
1414 {
1415   composite->red=Threshold(p->red,q->red,threshold,amount);
1416   composite->green=Threshold(p->green,q->green,threshold,amount);
1417   composite->blue=Threshold(p->blue,q->blue,threshold,amount);
1418   composite->alpha=Threshold(p->alpha,q->alpha,threshold,amount);
1419   if (q->colorspace == CMYKColorspace)
1420     composite->black=Threshold(p->black,q->black,threshold,amount);
1421 }
1422
1423
1424 static MagickRealType VividLight(const MagickRealType Sca,
1425   const MagickRealType Sa,const MagickRealType Dca,const MagickRealType Da)
1426 {
1427   /*
1428     VividLight: A Photoshop 7 composition method.  See
1429     http://www.simplefilter.de/en/basics/mixmods.html.
1430
1431     f(Sc,Dc) = (2*Sc < 1) ? 1-(1-Dc)/(2*Sc) : Dc/(2*(1-Sc))
1432   */
1433   if ((fabs(Sa) < MagickEpsilon) || (fabs(Sca-Sa) < MagickEpsilon))
1434     return(Sa*Da+Sca*(1.0-Da)+Dca*(1.0-Sa));
1435   if ((2.0*Sca) <= Sa)
1436     return(Sa*(Da+Sa*(Dca-Da)/(2.0*Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
1437   return(Dca*Sa*Sa/(2.0*(Sa-Sca))+Sca*(1.0-Da)+Dca*(1.0-Sa));
1438 }
1439
1440 static inline void CompositeVividLight(const PixelInfo *p,const PixelInfo *q,
1441   PixelInfo *composite)
1442 {
1443   MagickRealType
1444     Da,
1445     gamma,
1446     Sa;
1447
1448   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1449   Da=QuantumScale*q->alpha;
1450   gamma=RoundToUnity(Sa+Da-Sa*Da); /* over blend, as per SVG doc */
1451   composite->alpha=(MagickRealType) QuantumRange*gamma;
1452   gamma=QuantumRange/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1453   composite->red=gamma*VividLight(QuantumScale*p->red*Sa,Sa,QuantumScale*
1454     q->red*Da,Da);
1455   composite->green=gamma*VividLight(QuantumScale*p->green*Sa,Sa,QuantumScale*
1456     q->green*Da,Da);
1457   composite->blue=gamma*VividLight(QuantumScale*p->blue*Sa,Sa,QuantumScale*
1458     q->blue*Da,Da);
1459   if (q->colorspace == CMYKColorspace)
1460     composite->black=gamma*VividLight(QuantumScale*p->black*Sa,Sa,QuantumScale*
1461       q->black*Da,Da);
1462 }
1463
1464 static MagickRealType Xor(const MagickRealType Sca,const MagickRealType Sa,
1465   const MagickRealType Dca,const MagickRealType Da)
1466 {
1467   return(Sca*(1.0-Da)+Dca*(1.0-Sa));
1468 }
1469
1470 static inline void CompositeXor(const PixelInfo *p,const PixelInfo *q,
1471   PixelInfo *composite)
1472 {
1473   MagickRealType
1474     Da,
1475     gamma,
1476     Sa;
1477
1478   Sa=QuantumScale*p->alpha;  /* simplify and speed up equations */
1479   Da=QuantumScale*q->alpha;
1480   gamma=Sa+Da-2.0*Sa*Da;        /* Xor blend mode X=0,Y=1,Z=1 */
1481   composite->alpha=(MagickRealType) QuantumRange*gamma;
1482   gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
1483   composite->red=gamma*Xor(p->red*Sa,Sa,q->red*Da,Da);
1484   composite->green=gamma*Xor(p->green*Sa,Sa,q->green*Da,Da);
1485   composite->blue=gamma*Xor(p->blue*Sa,Sa,q->blue*Da,Da);
1486   if (q->colorspace == CMYKColorspace)
1487     composite->black=gamma*Xor(p->black*Sa,Sa,q->black*Da,Da);
1488 }
1489
1490 static void HSBComposite(const double hue,const double saturation,
1491   const double brightness,double *red,double *green,
1492   double *blue)
1493 {
1494   double
1495     f,
1496     h,
1497     p,
1498     q,
1499     t;
1500
1501   /*
1502     Convert HSB to RGB colorspace.
1503   */
1504   assert(red != (double *) NULL);
1505   assert(green != (double *) NULL);
1506   assert(blue != (double *) NULL);
1507   if (saturation == 0.0)
1508     {
1509       *red=(double) QuantumRange*brightness;
1510       *green=(*red);
1511       *blue=(*red);
1512       return;
1513     }
1514   h=6.0*(hue-floor(hue));
1515   f=h-floor((double) h);
1516   p=brightness*(1.0-saturation);
1517   q=brightness*(1.0-saturation*f);
1518   t=brightness*(1.0-saturation*(1.0-f));
1519   switch ((int) h)
1520   {
1521     case 0:
1522     default:
1523     {
1524       *red=(double) QuantumRange*brightness;
1525       *green=(double) QuantumRange*t;
1526       *blue=(double) QuantumRange*p;
1527       break;
1528     }
1529     case 1:
1530     {
1531       *red=(double) QuantumRange*q;
1532       *green=(double) QuantumRange*brightness;
1533       *blue=(double) QuantumRange*p;
1534       break;
1535     }
1536     case 2:
1537     {
1538       *red=(double) QuantumRange*p;
1539       *green=(double) QuantumRange*brightness;
1540       *blue=(double) QuantumRange*t;
1541       break;
1542     }
1543     case 3:
1544     {
1545       *red=(double) QuantumRange*p;
1546       *green=(double) QuantumRange*q;
1547       *blue=(double) QuantumRange*brightness;
1548       break;
1549     }
1550     case 4:
1551     {
1552       *red=(double) QuantumRange*t;
1553       *green=(double) QuantumRange*p;
1554       *blue=(double) QuantumRange*brightness;
1555       break;
1556     }
1557     case 5:
1558     {
1559       *red=(double) QuantumRange*brightness;
1560       *green=(double) QuantumRange*p;
1561       *blue=(double) QuantumRange*q;
1562       break;
1563     }
1564   }
1565 }
1566
1567 MagickExport MagickBooleanType CompositeImage(Image *image,
1568   const CompositeOperator compose,const Image *composite_image,
1569   const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo *exception)
1570 {
1571 #define CompositeImageTag  "Composite/Image"
1572
1573   CacheView
1574     *composite_view,
1575     *image_view;
1576
1577   const char
1578     *value;
1579
1580   double
1581     sans;
1582
1583   GeometryInfo
1584     geometry_info;
1585
1586   Image
1587     *destination_image;
1588
1589   MagickBooleanType
1590     modify_outside_overlay,
1591     status;
1592
1593   MagickOffsetType
1594     progress;
1595
1596   MagickRealType
1597     amount,
1598     destination_dissolve,
1599     midpoint,
1600     percent_brightness,
1601     percent_saturation,
1602     source_dissolve,
1603     threshold;
1604
1605   MagickStatusType
1606     flags;
1607
1608   ssize_t
1609     y;
1610
1611   /*
1612     Prepare composite image.
1613   */
1614   assert(image != (Image *) NULL);
1615   assert(image->signature == MagickSignature);
1616   if (image->debug != MagickFalse)
1617     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1618   assert(composite_image != (Image *) NULL);
1619   assert(composite_image->signature == MagickSignature);
1620   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1621     return(MagickFalse);
1622   destination_image=(Image *) NULL;
1623   amount=0.5;
1624   destination_dissolve=1.0;
1625   modify_outside_overlay=MagickFalse;
1626   percent_brightness=100.0;
1627   percent_saturation=100.0;
1628   source_dissolve=1.0;
1629   threshold=0.05f;
1630   switch (compose)
1631   {
1632     case ClearCompositeOp:
1633     case DstAtopCompositeOp:
1634     case DstInCompositeOp:
1635     case InCompositeOp:
1636     case OutCompositeOp:
1637     case SrcCompositeOp:
1638     case SrcInCompositeOp:
1639     case SrcOutCompositeOp:
1640     {
1641       /*
1642         Modify destination outside the overlaid region.
1643       */
1644       modify_outside_overlay=MagickTrue;
1645       break;
1646     }
1647     case CopyCompositeOp:
1648     {
1649       if ((x_offset < 0) || (y_offset < 0))
1650         break;
1651       if ((x_offset+(ssize_t) composite_image->columns) >= (ssize_t) image->columns)
1652         break;
1653       if ((y_offset+(ssize_t) composite_image->rows) >= (ssize_t) image->rows)
1654         break;
1655       status=MagickTrue;
1656       image_view=AcquireCacheView(image);
1657       composite_view=AcquireCacheView(composite_image);
1658 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1659 #pragma omp parallel for schedule(dynamic,4) shared(status)
1660 #endif
1661       for (y=0; y < (ssize_t) composite_image->rows; y++)
1662       {
1663         MagickBooleanType
1664           sync;
1665
1666         register const Quantum
1667           *p;
1668
1669         register Quantum
1670           *q;
1671
1672         register ssize_t
1673           x;
1674
1675         if (status == MagickFalse)
1676           continue;
1677         p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1678           1,exception);
1679         q=GetCacheViewAuthenticPixels(image_view,x_offset,y+y_offset,
1680           composite_image->columns,1,exception);
1681         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1682           {
1683             status=MagickFalse;
1684             continue;
1685           }
1686         for (x=0; x < (ssize_t) composite_image->columns; x++)
1687         {
1688           SetPixelRed(image,GetPixelRed(composite_image,p),q);
1689           SetPixelGreen(image,GetPixelGreen(composite_image,p),q);
1690           SetPixelBlue(image,GetPixelBlue(composite_image,p),q);
1691           SetPixelAlpha(image,GetPixelAlpha(composite_image,p),q);
1692           if (image->colorspace == CMYKColorspace)
1693             SetPixelBlack(image,GetPixelBlack(composite_image,p),q);
1694           p+=GetPixelChannels(composite_image);
1695           q+=GetPixelChannels(image);
1696         }
1697         sync=SyncCacheViewAuthenticPixels(image_view,exception);
1698         if (sync == MagickFalse)
1699           status=MagickFalse;
1700         if (image->progress_monitor != (MagickProgressMonitor) NULL)
1701           {
1702             MagickBooleanType
1703               proceed;
1704
1705 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1706 #pragma omp critical (MagickCore_CompositeImage)
1707 #endif
1708             proceed=SetImageProgress(image,CompositeImageTag,
1709               (MagickOffsetType) y,image->rows);
1710             if (proceed == MagickFalse)
1711               status=MagickFalse;
1712           }
1713       }
1714       composite_view=DestroyCacheView(composite_view);
1715       image_view=DestroyCacheView(image_view);
1716       return(status);
1717     }
1718     case CopyOpacityCompositeOp:
1719     case ChangeMaskCompositeOp:
1720     {
1721       /*
1722         Modify destination outside the overlaid region and require an alpha
1723         channel to exist, to add transparency.
1724       */
1725       if (image->matte == MagickFalse)
1726         (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1727       modify_outside_overlay=MagickTrue;
1728       break;
1729     }
1730     case BlurCompositeOp:
1731     {
1732       CacheView
1733         *composite_view,
1734         *destination_view;
1735
1736       PixelInfo
1737         pixel;
1738
1739       MagickRealType
1740         angle_range,
1741         angle_start,
1742         height,
1743         width;
1744
1745       ResampleFilter
1746         *resample_filter;
1747
1748       SegmentInfo
1749         blur;
1750
1751       /*
1752         Blur Image dictated by an overlay gradient map: X = red_channel;
1753           Y = green_channel; compose:args =  x_scale[,y_scale[,angle]].
1754       */
1755       destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
1756         exception);
1757       if (destination_image == (Image *) NULL)
1758         return(MagickFalse);
1759       /*
1760         Determine the horizontal and vertical maximim blur.
1761       */
1762       SetGeometryInfo(&geometry_info);
1763       flags=NoValue;
1764       value=GetImageArtifact(composite_image,"compose:args");
1765       if (value != (char *) NULL)
1766         flags=ParseGeometry(value,&geometry_info);
1767       if ((flags & WidthValue) == 0 )
1768         {
1769           destination_image=DestroyImage(destination_image);
1770           return(MagickFalse);
1771         }
1772       width=geometry_info.rho;
1773       height=geometry_info.sigma;
1774       blur.x1=geometry_info.rho;
1775       blur.x2=0.0;
1776       blur.y1=0.0;
1777       blur.y2=geometry_info.sigma;
1778       angle_start=0.0;
1779       angle_range=0.0;
1780       if ((flags & HeightValue) == 0)
1781         blur.y2=blur.x1;
1782       if ((flags & XValue) != 0 )
1783         {
1784           MagickRealType
1785             angle;
1786
1787           angle=DegreesToRadians(geometry_info.xi);
1788           blur.x1=width*cos(angle);
1789           blur.x2=width*sin(angle);
1790           blur.y1=(-height*sin(angle));
1791           blur.y2=height*cos(angle);
1792         }
1793       if ((flags & YValue) != 0 )
1794         {
1795           angle_start=DegreesToRadians(geometry_info.xi);
1796           angle_range=DegreesToRadians(geometry_info.psi)-angle_start;
1797         }
1798       /*
1799         Blur Image by resampling.
1800       */
1801       resample_filter=AcquireResampleFilter(image,exception);
1802       SetResampleFilter(resample_filter,CubicFilter,2.0);
1803       destination_view=AcquireCacheView(destination_image);
1804       composite_view=AcquireCacheView(composite_image);
1805       for (y=0; y < (ssize_t) composite_image->rows; y++)
1806       {
1807         MagickBooleanType
1808           sync;
1809
1810         register const Quantum
1811           *restrict p;
1812
1813         register Quantum
1814           *restrict q;
1815
1816         register ssize_t
1817           x;
1818
1819         if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1820           continue;
1821         p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1822           1,exception);
1823         q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1824           destination_image->columns,1,exception);
1825         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1826           break;
1827         for (x=0; x < (ssize_t) composite_image->columns; x++)
1828         {
1829           if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
1830             {
1831               p+=GetPixelChannels(composite_image);
1832               continue;
1833             }
1834           if (fabs(angle_range) > MagickEpsilon)
1835             {
1836               MagickRealType
1837                 angle;
1838
1839               angle=angle_start+angle_range*QuantumScale*
1840                 GetPixelBlue(composite_image,p);
1841               blur.x1=width*cos(angle);
1842               blur.x2=width*sin(angle);
1843               blur.y1=(-height*sin(angle));
1844               blur.y2=height*cos(angle);
1845             }
1846           ScaleResampleFilter(resample_filter,blur.x1*QuantumScale*
1847             GetPixelRed(composite_image,p),blur.y1*QuantumScale*
1848             GetPixelGreen(composite_image,p),blur.x2*QuantumScale*
1849             GetPixelRed(composite_image,p),blur.y2*QuantumScale*
1850             GetPixelGreen(composite_image,p));
1851           (void) ResamplePixelColor(resample_filter,(double) x_offset+x,
1852             (double) y_offset+y,&pixel);
1853           SetPixelInfoPixel(destination_image,&pixel,q);
1854           p+=GetPixelChannels(composite_image);
1855           q+=GetPixelChannels(destination_image);
1856         }
1857         sync=SyncCacheViewAuthenticPixels(destination_view,exception);
1858         if (sync == MagickFalse)
1859           break;
1860       }
1861       resample_filter=DestroyResampleFilter(resample_filter);
1862       composite_view=DestroyCacheView(composite_view);
1863       destination_view=DestroyCacheView(destination_view);
1864       composite_image=destination_image;
1865       break;
1866     }
1867     case DisplaceCompositeOp:
1868     case DistortCompositeOp:
1869     {
1870       CacheView
1871         *composite_view,
1872         *destination_view,
1873         *image_view;
1874
1875       PixelInfo
1876         pixel;
1877
1878       MagickRealType
1879         horizontal_scale,
1880         vertical_scale;
1881
1882       PointInfo
1883         center,
1884         offset;
1885
1886       /*
1887         Displace/Distort based on overlay gradient map:
1888           X = red_channel;  Y = green_channel;
1889           compose:args = x_scale[,y_scale[,center.x,center.y]]
1890       */
1891       destination_image=CloneImage(image,image->columns,image->rows,MagickTrue,
1892         exception);
1893       if (destination_image == (Image *) NULL)
1894         return(MagickFalse);
1895       SetGeometryInfo(&geometry_info);
1896       flags=NoValue;
1897       value=GetImageArtifact(composite_image,"compose:args");
1898       if (value != (char *) NULL)
1899         flags=ParseGeometry(value,&geometry_info);
1900       if ((flags & (WidthValue|HeightValue)) == 0 )
1901         {
1902           if ((flags & AspectValue) == 0)
1903             {
1904               horizontal_scale=(MagickRealType) (composite_image->columns-1.0)/
1905                 2.0;
1906               vertical_scale=(MagickRealType) (composite_image->rows-1.0)/2.0;
1907             }
1908           else
1909             {
1910               horizontal_scale=(MagickRealType) (image->columns-1.0)/2.0;
1911               vertical_scale=(MagickRealType) (image->rows-1.0)/2.0;
1912             }
1913         }
1914       else
1915         {
1916           horizontal_scale=geometry_info.rho;
1917           vertical_scale=geometry_info.sigma;
1918           if ((flags & PercentValue) != 0)
1919             {
1920               if ((flags & AspectValue) == 0)
1921                 {
1922                   horizontal_scale*=(composite_image->columns-1.0)/200.0;
1923                   vertical_scale*=(composite_image->rows-1.0)/200.0;
1924                 }
1925               else
1926                 {
1927                   horizontal_scale*=(image->columns-1.0)/200.0;
1928                   vertical_scale*=(image->rows-1.0)/200.0;
1929                 }
1930             }
1931           if ((flags & HeightValue) == 0)
1932             vertical_scale=horizontal_scale;
1933         }
1934       /*
1935         Determine fixed center point for absolute distortion map
1936          Absolute distort ==
1937            Displace offset relative to a fixed absolute point
1938            Select that point according to +X+Y user inputs.
1939            default = center of overlay image
1940            arg flag '!' = locations/percentage relative to background image
1941       */
1942       center.x=(MagickRealType) x_offset;
1943       center.y=(MagickRealType) y_offset;
1944       if (compose == DistortCompositeOp)
1945         {
1946           if ((flags & XValue) == 0)
1947             if ((flags & AspectValue) == 0)
1948               center.x=(MagickRealType) x_offset+(composite_image->columns-1)/
1949                 2.0;
1950             else
1951               center.x=((MagickRealType) image->columns-1)/2.0;
1952           else
1953             if ((flags & AspectValue) == 0)
1954               center.x=(MagickRealType) x_offset+geometry_info.xi;
1955             else
1956               center.x=geometry_info.xi;
1957           if ((flags & YValue) == 0)
1958             if ((flags & AspectValue) == 0)
1959               center.y=(MagickRealType) y_offset+(composite_image->rows-1)/2.0;
1960             else
1961               center.y=((MagickRealType) image->rows-1)/2.0;
1962           else
1963             if ((flags & AspectValue) == 0)
1964               center.y=(MagickRealType) y_offset+geometry_info.psi;
1965             else
1966               center.y=geometry_info.psi;
1967         }
1968       /*
1969         Shift the pixel offset point as defined by the provided,
1970         displacement/distortion map.  -- Like a lens...
1971       */
1972       GetPixelInfo(image,&pixel);
1973       image_view=AcquireCacheView(image);
1974       destination_view=AcquireCacheView(destination_image);
1975       composite_view=AcquireCacheView(composite_image);
1976       for (y=0; y < (ssize_t) composite_image->rows; y++)
1977       {
1978         MagickBooleanType
1979           sync;
1980
1981         register const Quantum
1982           *restrict p;
1983
1984         register Quantum
1985           *restrict q;
1986
1987         register ssize_t
1988           x;
1989
1990         if (((y+y_offset) < 0) || ((y+y_offset) >= (ssize_t) image->rows))
1991           continue;
1992         p=GetCacheViewVirtualPixels(composite_view,0,y,composite_image->columns,
1993           1,exception);
1994         q=QueueCacheViewAuthenticPixels(destination_view,0,y,
1995           destination_image->columns,1,exception);
1996         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1997           break;
1998         for (x=0; x < (ssize_t) composite_image->columns; x++)
1999         {
2000           if (((x_offset+x) < 0) || ((x_offset+x) >= (ssize_t) image->columns))
2001             {
2002               p+=GetPixelChannels(composite_image);
2003               continue;
2004             }
2005           /*
2006             Displace the offset.
2007           */
2008           offset.x=(horizontal_scale*(GetPixelRed(composite_image,p)-
2009             (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2010             QuantumRange+1.0)/2.0)+center.x+((compose == DisplaceCompositeOp) ?
2011             x : 0);
2012           offset.y=(vertical_scale*(GetPixelGreen(composite_image,p)-
2013             (((MagickRealType) QuantumRange+1.0)/2.0)))/(((MagickRealType)
2014             QuantumRange+1.0)/2.0)+center.y+((compose == DisplaceCompositeOp) ?
2015             y : 0);
2016           (void) InterpolatePixelInfo(image,image_view,
2017             UndefinedInterpolatePixel,(double) offset.x,(double) offset.y,
2018             &pixel,exception);
2019           /*
2020             Mask with the 'invalid pixel mask' in alpha channel.
2021           */
2022           pixel.alpha=(MagickRealType) QuantumRange*(1.0-(1.0-QuantumScale*
2023             pixel.alpha)*(1.0-QuantumScale*
2024             GetPixelAlpha(composite_image,p)));
2025           SetPixelInfoPixel(destination_image,&pixel,q);
2026           p+=GetPixelChannels(composite_image);
2027           q+=GetPixelChannels(destination_image);
2028         }
2029         sync=SyncCacheViewAuthenticPixels(destination_view,exception);
2030         if (sync == MagickFalse)
2031           break;
2032       }
2033       destination_view=DestroyCacheView(destination_view);
2034       composite_view=DestroyCacheView(composite_view);
2035       image_view=DestroyCacheView(image_view);
2036       composite_image=destination_image;
2037       break;
2038     }
2039     case DissolveCompositeOp:
2040     {
2041       /*
2042         Geometry arguments to dissolve factors.
2043       */
2044       value=GetImageArtifact(composite_image,"compose:args");
2045       if (value != (char *) NULL)
2046         {
2047           flags=ParseGeometry(value,&geometry_info);
2048           source_dissolve=geometry_info.rho/100.0;
2049           destination_dissolve=1.0;
2050           if ((source_dissolve-MagickEpsilon) < 0.0)
2051             source_dissolve=0.0;
2052           if ((source_dissolve+MagickEpsilon) > 1.0)
2053             {
2054               destination_dissolve=2.0-source_dissolve;
2055               source_dissolve=1.0;
2056             }
2057           if ((flags & SigmaValue) != 0)
2058             destination_dissolve=geometry_info.sigma/100.0;
2059           if ((destination_dissolve-MagickEpsilon) < 0.0)
2060             destination_dissolve=0.0;
2061           modify_outside_overlay=MagickTrue;
2062           if ((destination_dissolve+MagickEpsilon) > 1.0 )
2063             {
2064               destination_dissolve=1.0;
2065               modify_outside_overlay=MagickFalse;
2066             }
2067         }
2068       break;
2069     }
2070     case BlendCompositeOp:
2071     {
2072       value=GetImageArtifact(composite_image,"compose:args");
2073       if (value != (char *) NULL)
2074         {
2075           flags=ParseGeometry(value,&geometry_info);
2076           source_dissolve=geometry_info.rho/100.0;
2077           destination_dissolve=1.0-source_dissolve;
2078           if ((flags & SigmaValue) != 0)
2079             destination_dissolve=geometry_info.sigma/100.0;
2080           modify_outside_overlay=MagickTrue;
2081           if ((destination_dissolve+MagickEpsilon) > 1.0)
2082             modify_outside_overlay=MagickFalse;
2083         }
2084       break;
2085     }
2086     case MathematicsCompositeOp:
2087     {
2088       /*
2089         Just collect the values from "compose:args", setting.
2090         Unused values are set to zero automagically.
2091
2092         Arguments are normally a comma separated list, so this probably should
2093         be changed to some 'general comma list' parser, (with a minimum
2094         number of values)
2095       */
2096       SetGeometryInfo(&geometry_info);
2097       value=GetImageArtifact(composite_image,"compose:args");
2098       if (value != (char *) NULL)
2099         (void) ParseGeometry(value,&geometry_info);
2100       break;
2101     }
2102     case ModulateCompositeOp:
2103     {
2104       /*
2105         Determine the brightness and saturation scale.
2106       */
2107       value=GetImageArtifact(composite_image,"compose:args");
2108       if (value != (char *) NULL)
2109         {
2110           flags=ParseGeometry(value,&geometry_info);
2111           percent_brightness=geometry_info.rho;
2112           if ((flags & SigmaValue) != 0)
2113             percent_saturation=geometry_info.sigma;
2114         }
2115       break;
2116     }
2117     case ThresholdCompositeOp:
2118     {
2119       /*
2120         Determine the amount and threshold.
2121       */
2122       value=GetImageArtifact(composite_image,"compose:args");
2123       if (value != (char *) NULL)
2124         {
2125           flags=ParseGeometry(value,&geometry_info);
2126           amount=geometry_info.rho;
2127           threshold=geometry_info.sigma;
2128           if ((flags & SigmaValue) == 0)
2129             threshold=0.05f;
2130         }
2131       threshold*=QuantumRange;
2132       break;
2133     }
2134     default:
2135       break;
2136   }
2137   value=GetImageArtifact(composite_image,"compose:outside-overlay");
2138   if (value != (const char *) NULL)
2139     modify_outside_overlay=IsMagickTrue(value);
2140   /*
2141     Composite image.
2142   */
2143   status=MagickTrue;
2144   progress=0;
2145   midpoint=((MagickRealType) QuantumRange+1.0)/2;
2146   image_view=AcquireCacheView(image);
2147   composite_view=AcquireCacheView(composite_image);
2148 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2149 //  #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
2150 #endif
2151   for (y=0; y < (ssize_t) image->rows; y++)
2152   {
2153     const Quantum
2154       *pixels;
2155
2156     double
2157       brightness,
2158       hue,
2159       saturation;
2160
2161     register const Quantum
2162       *restrict p;
2163
2164     register Quantum
2165       *restrict q;
2166
2167     register ssize_t
2168       x;
2169
2170 MagickBooleanType composite_channels;
2171
2172     if (status == MagickFalse)
2173       continue;
2174     if (modify_outside_overlay == MagickFalse)
2175       {
2176         if (y < y_offset)
2177           continue;
2178         if ((y-y_offset) >= (ssize_t) composite_image->rows)
2179           continue;
2180       }
2181     /*
2182       If pixels is NULL, y is outside overlay region.
2183     */
2184     pixels=(Quantum *) NULL;
2185     p=(Quantum *) NULL;
2186     if ((y >= y_offset) && ((y-y_offset) < (ssize_t) composite_image->rows))
2187       {
2188         p=GetCacheViewVirtualPixels(composite_view,0,y-y_offset,
2189           composite_image->columns,1,exception);
2190         if (p == (const Quantum *) NULL)
2191           {
2192             status=MagickFalse;
2193             continue;
2194           }
2195         pixels=p;
2196         if (x_offset < 0)
2197           p-=x_offset*GetPixelChannels(composite_image);
2198       }
2199     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2200     if (q == (Quantum *) NULL)
2201       {
2202         status=MagickFalse;
2203         continue;
2204       }
2205     hue=0.0;
2206     saturation=0.0;
2207     brightness=0.0;
2208     for (x=0; x < (ssize_t) image->columns; x++)
2209     {
2210       if (modify_outside_overlay == MagickFalse)
2211         {
2212           if (x < x_offset)
2213             {
2214               q+=GetPixelChannels(image);
2215               continue;
2216             }
2217           if ((x-x_offset) >= (ssize_t) composite_image->columns)
2218             break;
2219         }
2220       composite_channels=MagickFalse;
2221       switch (compose)
2222       {
2223         case AtopCompositeOp:
2224         case ClearCompositeOp:
2225         case CopyCompositeOp:
2226         case DarkenCompositeOp:
2227         case DarkenIntensityCompositeOp:
2228         case DifferenceCompositeOp:
2229         case DivideDstCompositeOp:
2230         case DivideSrcCompositeOp:
2231         case DstAtopCompositeOp:
2232         case DstCompositeOp:
2233         case DstInCompositeOp:
2234         case DstOverCompositeOp:
2235         case DstOutCompositeOp:
2236         case ExclusionCompositeOp:
2237         case InCompositeOp:
2238         case LightenCompositeOp:
2239         case LightenIntensityCompositeOp:
2240         case MinusDstCompositeOp:
2241         case MinusSrcCompositeOp:
2242         case ModulusAddCompositeOp:
2243         case ModulusSubtractCompositeOp:
2244         case MultiplyCompositeOp:
2245         case NoCompositeOp:
2246         case OutCompositeOp:
2247         case OverCompositeOp:
2248         case PlusCompositeOp:
2249         case ReplaceCompositeOp:
2250         case ScreenCompositeOp:
2251         case SrcAtopCompositeOp:
2252         case SrcCompositeOp:
2253         case SrcInCompositeOp:
2254         case SrcOutCompositeOp:
2255         case SrcOverCompositeOp:
2256         case XorCompositeOp:
2257         {
2258           composite_channels=MagickTrue;
2259           break;
2260         }
2261         default:
2262           break;
2263       }
2264       if (composite_channels != MagickFalse) {
2265         MagickRealType
2266           alpha,
2267           Da,
2268           Dc,
2269           gamma,
2270           Sa,
2271           Sc;
2272
2273         register ssize_t
2274           i;
2275
2276         if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
2277             ((x-x_offset) >= (ssize_t) composite_image->columns))
2278           {
2279             Quantum
2280               source[MaxPixelChannels];
2281
2282             /*
2283               Virtual composite:
2284                 Sc: source color.
2285                 Dc: destination color.
2286             */
2287             (void) GetOneVirtualPixel(composite_image,x-x_offset,y-y_offset,
2288               source,exception);
2289             for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2290             {
2291               MagickRealType
2292                 pixel;
2293
2294               PixelChannel
2295                 channel;
2296
2297               PixelTrait
2298                 traits;
2299
2300               channel=GetPixelChannelMapChannel(image,i);
2301               traits=GetPixelChannelMapTraits(image,channel);
2302               if (traits == UndefinedPixelTrait)
2303                 continue;
2304               switch (compose)
2305               {
2306                 case ClearCompositeOp:
2307                 case CopyCompositeOp:
2308                 case ReplaceCompositeOp:
2309                 case SrcCompositeOp:
2310                 {
2311                   pixel=0.0;
2312                   if (channel == AlphaPixelChannel)
2313                     pixel=(MagickRealType) TransparentAlpha;
2314                   break;
2315                 }
2316                 case DstAtopCompositeOp:
2317                 case InCompositeOp:
2318                 case OutCompositeOp:
2319                 case SrcInCompositeOp:
2320                 case SrcOutCompositeOp:
2321                 {
2322                   pixel=(MagickRealType) q[i];
2323                   if (channel == AlphaPixelChannel)
2324                     pixel=(MagickRealType) TransparentAlpha;
2325                   break;
2326                 }
2327                 default:
2328                 {
2329                   pixel=source[channel];
2330                   break;
2331                 }
2332               }
2333               q[i]=ClampToQuantum(pixel);
2334             }
2335             q+=GetPixelChannels(image);
2336             continue;
2337           }
2338         /*
2339           Authentic composite:
2340             Sa: source normalized alpha.
2341             Da: destination normalized alpha.
2342         */
2343         Sa=QuantumScale*GetPixelAlpha(composite_image,p);
2344         Da=QuantumScale*GetPixelAlpha(image,q);
2345         switch (compose)
2346         {
2347           case DarkenCompositeOp:
2348           case DstAtopCompositeOp:
2349           case DstInCompositeOp:
2350           case InCompositeOp:
2351           case LightenCompositeOp:
2352           case SrcInCompositeOp:
2353           {
2354             alpha=Sa*Da;
2355             break;
2356           }
2357           case DifferenceCompositeOp:
2358           case DivideDstCompositeOp:
2359           case DivideSrcCompositeOp:
2360           case ExclusionCompositeOp:
2361           case MinusDstCompositeOp:
2362           case MinusSrcCompositeOp:
2363           case ModulusAddCompositeOp:
2364           case ModulusSubtractCompositeOp:
2365           case MultiplyCompositeOp:
2366           case ScreenCompositeOp:
2367           {
2368             alpha=RoundToUnity(Sa+Da-Sa*Da);
2369             break;
2370           }
2371           case DstOverCompositeOp:
2372           {
2373             alpha=Da*(-Sa)+Da+Sa;
2374             break;
2375           }
2376           case DstOutCompositeOp:
2377           {
2378             alpha=Da*(1.0-Sa);
2379             break;
2380           }
2381           case OutCompositeOp:
2382           case SrcOutCompositeOp:
2383           {
2384             alpha=Sa*(1.0-Da);
2385             break;
2386           }
2387           case OverCompositeOp:
2388           case SrcOverCompositeOp:
2389           {
2390             alpha=Sa*(-Da)+Sa+Da;
2391             break;
2392           }
2393           case PlusCompositeOp:
2394           {
2395             alpha=RoundToUnity(Sa+Da);
2396             break;
2397           }
2398           case XorCompositeOp:
2399           {
2400             alpha=Sa+Da-2.0*Sa*Da;
2401             break;
2402           }
2403           default:
2404           {
2405             alpha=1.0;
2406             break;
2407           }
2408         }
2409         for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2410         {
2411           MagickRealType
2412             pixel;
2413
2414           PixelChannel
2415             channel;
2416
2417           PixelTrait
2418             composite_traits,
2419             traits;
2420
2421           channel=GetPixelChannelMapChannel(image,i);
2422           traits=GetPixelChannelMapTraits(image,channel);
2423           composite_traits=GetPixelChannelMapTraits(composite_image,channel);
2424           if ((traits == UndefinedPixelTrait) ||
2425               (composite_traits == UndefinedPixelTrait))
2426             continue;
2427           /*
2428             Sc: source color.
2429             Dc: destination color.
2430           */
2431           Sc=(MagickRealType) GetPixelChannel(composite_image,channel,p);
2432           Dc=(MagickRealType) q[i];
2433           if ((traits & CopyPixelTrait) != 0)
2434             {
2435               if (channel != AlphaPixelChannel)
2436                 {
2437                   /*
2438                     Copy channel.
2439                   */
2440                   q[i]=Sc;
2441                   continue;
2442                 }
2443               /*
2444                 Set alpha channel.
2445               */
2446               pixel=0.0;
2447               switch (compose)
2448               {
2449                 case AtopCompositeOp:
2450                 case SrcAtopCompositeOp:
2451                 case DstCompositeOp:
2452                 case NoCompositeOp:
2453                 {
2454                   pixel=QuantumRange*Da;
2455                   break;
2456                 }
2457                 case CopyCompositeOp:
2458                 case DstAtopCompositeOp:
2459                 case ReplaceCompositeOp:
2460                 case SrcCompositeOp:
2461                 {
2462                   pixel=QuantumRange*Sa;
2463                   break;
2464                 }
2465                 case DarkenIntensityCompositeOp:
2466                 {
2467                   pixel=Sa*GetPixelIntensity(composite_image,p) <
2468                     Da*GetPixelIntensity(image,q) ? Sa : Da;
2469                   break;
2470                 }
2471                 case LightenIntensityCompositeOp:
2472                 {
2473                   pixel=Sa*GetPixelIntensity(composite_image,p) >
2474                     Da*GetPixelIntensity(image,q) ? Sa : Da;
2475                   break;
2476                 }
2477                 default:
2478                 {
2479                   pixel=QuantumRange*alpha;
2480                   break;
2481                 }
2482               }
2483               q[i]=ClampToQuantum(pixel);
2484               continue;
2485             }
2486           /*
2487             Porter-Duff compositions.
2488           */
2489           switch (compose)
2490           {
2491             case DarkenCompositeOp:
2492             case LightenCompositeOp:
2493             {
2494               gamma=1.0-QuantumScale*Dc;
2495               break;
2496             }
2497             default:
2498               break;
2499           }
2500           gamma=QuantumRange/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
2501           pixel=0.0;
2502           switch (compose)
2503           {
2504             case AtopCompositeOp:
2505             case SrcAtopCompositeOp:
2506             {
2507               pixel=Sc*Sa+Dc*(1.0-Sa);
2508               break;
2509             }
2510             case CopyCompositeOp:
2511             case ReplaceCompositeOp:
2512             case SrcCompositeOp:
2513             {
2514               pixel=Sc;
2515               break;
2516             }
2517             case DarkenCompositeOp:
2518             {
2519               if (Sc < Dc)
2520                 {
2521                   pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2522                   break;
2523                 }
2524               pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
2525               break;
2526             }
2527             case DarkenIntensityCompositeOp:
2528             {
2529               pixel=Sa*GetPixelIntensity(composite_image,p) <
2530                 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2531               break;
2532             }
2533             case DifferenceCompositeOp:
2534             {
2535               pixel=gamma*(Sa*Sc+Da*Dc-Sa*Da*2.0*MagickMin(Sc,Dc));
2536               break;
2537             }
2538             case DivideDstCompositeOp:
2539             {
2540               if ((fabs((QuantumScale*Sa*Sc)) < MagickEpsilon) &&
2541                   (fabs((QuantumScale*Da*Dc)) < MagickEpsilon))
2542                 {
2543                   pixel=gamma*((QuantumScale*Sa*Sc)*(1.0-Da)+
2544                     (QuantumScale*Da*Dc)*(1.0-Sa));
2545                   break;
2546                 }
2547               if (fabs((QuantumScale*Da*Dc)) < MagickEpsilon)
2548                 {
2549                   pixel=gamma*(Sa*Da+(QuantumScale*Sa*Sc)*(1.0-Da)+
2550                     (QuantumScale*Da*Dc)*(1.0-Sa));
2551                   break;
2552                 }
2553               pixel=gamma*((QuantumScale*Sa*Sc)*Da*Da/(QuantumScale*Da*Dc)+
2554                 (QuantumScale*Sa*Sc)*(1.0-Da)+(QuantumScale*Da*Dc)*(1.0-Sa));
2555               break;
2556             }
2557             case DivideSrcCompositeOp:
2558             {
2559               if ((fabs((QuantumScale*Da*Dc)) < MagickEpsilon) &&
2560                   (fabs((QuantumScale*Sa*Sc)) < MagickEpsilon))
2561                 {
2562                   pixel=gamma*((QuantumScale*Da*Dc)*(1.0-Sa)+
2563                     (QuantumScale*Sa*Sc)*(1.0-Da));
2564                   break;
2565                 }
2566               if (fabs((QuantumScale*Sa*Sc)) < MagickEpsilon)
2567                 {
2568                   pixel=gamma*(Da*Sa+(QuantumScale*Da*Dc)*(1.0-Sa)+
2569                     (QuantumScale*Sa*Sc)*(1.0-Da));
2570                   break;
2571                 }
2572               pixel=gamma*((QuantumScale*Da*Dc)*Sa*Sa/(QuantumScale*Sa*Sc)+
2573                 (QuantumScale*Da*Dc)*(1.0-Sa)+(QuantumScale*Sa*Sc)*(1.0-Da));
2574               break;
2575             }
2576             case DstAtopCompositeOp:
2577             {
2578               pixel=Dc*Da+Sc*(1.0-Da);
2579               break;
2580             }
2581             case DstCompositeOp:
2582             case NoCompositeOp:
2583             {
2584               pixel=Dc;
2585               break;
2586             }
2587             case DstInCompositeOp:
2588             {
2589               pixel=gamma*(Sa*Dc*Sa);
2590               break;
2591             }
2592             case DstOutCompositeOp:
2593             {
2594               pixel=gamma*(Da*Dc*(1.0-Sa));
2595               break;
2596             }
2597             case DstOverCompositeOp:
2598             {
2599               pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
2600               break;
2601             }
2602             case ExclusionCompositeOp:
2603             {
2604               pixel=gamma*((QuantumScale*Sa*Sc)*Da+(QuantumScale*Da*Dc)*Sa-2.0*
2605                 (QuantumScale*Sa*Sc)*(QuantumScale*Da*Dc)+(QuantumScale*Sa*Sc)*
2606                 (1.0-Da)+(QuantumScale*Da*Dc)*(1.0-Sa));
2607               break;
2608             }
2609             case InCompositeOp:
2610             case SrcInCompositeOp:
2611             {
2612               pixel=gamma*(Da*Sc*Da);
2613               break;
2614             }
2615             case LightenIntensityCompositeOp:
2616             {
2617               pixel=Sa*GetPixelIntensity(composite_image,p) >
2618                 Da*GetPixelIntensity(image,q) ? Sc : Dc;
2619               break;
2620             }
2621             case MinusDstCompositeOp:
2622             {
2623               pixel=gamma*(Sa*Sc+Da*Dc-2.0*Da*Dc*Sa);
2624               break;
2625             }
2626             case MinusSrcCompositeOp:
2627             {
2628               pixel=gamma*(Da*Dc+Sa*Sc-2.0*Sa*Sc*Da);
2629               break;
2630             }
2631             case LightenCompositeOp:
2632             {
2633               if (Sc > Dc)
2634                 {
2635                   pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2636                   break;
2637                 }
2638               pixel=gamma*(Da*Dc-Da*Sa*Sc+Sa*Sc);
2639               break;
2640             }
2641             case ModulusAddCompositeOp:
2642             {
2643               pixel=Sc+Dc;
2644               if (pixel > QuantumRange)
2645                 pixel-=(QuantumRange+1.0);
2646               pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2647               break;
2648             }
2649             case ModulusSubtractCompositeOp:
2650             {
2651               pixel=Sc+Dc;
2652               if (pixel < 0.0)
2653                 pixel+=(QuantumRange+1.0);
2654               pixel=gamma*(pixel*Sa*Da+Sa*Sc*(1.0-Da)+Da*Dc*(1.0-Sa));
2655               break;
2656             }
2657             case MultiplyCompositeOp:
2658             {
2659               pixel=gamma*((QuantumScale*Sa*Sc)*(QuantumScale*Da*Dc)+
2660                 (QuantumScale*Sa*Sc)*(1.0-Da)+(QuantumScale*Da*Dc)*(1.0-Sa));
2661               break;
2662             }
2663             case OutCompositeOp:
2664             case SrcOutCompositeOp:
2665             {
2666               pixel=gamma*(Sa*Sc*(1.0-Da));
2667               break;
2668             }
2669             case OverCompositeOp:
2670             case SrcOverCompositeOp:
2671             {
2672               pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
2673               break;
2674             }
2675             case PlusCompositeOp:
2676             {
2677               pixel=gamma*(Sa*Sc+Da*Dc);
2678               break;
2679             }
2680             case ScreenCompositeOp:
2681             {
2682               pixel=gamma*((Sa*Sc)+(Da*Dc)-(Sa*Sc)*(Da*Dc));
2683               break;
2684             }
2685             case XorCompositeOp:
2686             {
2687               pixel=gamma*(Sc*Sa*(1.0-Da)+Dc*Da*(1.0-Sa));
2688               break;
2689             }
2690             default:
2691               break;
2692           }
2693           q[i]=ClampToQuantum(pixel);
2694         }
2695       } else {
2696         PixelInfo
2697           composite,
2698           destination,
2699           source,
2700           zero;
2701
2702         GetPixelInfo(image,&zero);
2703         source=zero;
2704         destination=zero;
2705         destination.red=(MagickRealType) GetPixelRed(image,q);
2706         destination.green=(MagickRealType) GetPixelGreen(image,q);
2707         destination.blue=(MagickRealType) GetPixelBlue(image,q);
2708         if (image->colorspace == CMYKColorspace)
2709           destination.black=(MagickRealType) GetPixelBlack(image,q);
2710         if (image->colorspace == CMYKColorspace)
2711           {
2712             destination.red=(MagickRealType) QuantumRange-destination.red;
2713             destination.green=(MagickRealType) QuantumRange-destination.green;
2714             destination.blue=(MagickRealType) QuantumRange-destination.blue;
2715             destination.black=(MagickRealType) QuantumRange-destination.black;
2716           }
2717         if (image->matte != MagickFalse)
2718           destination.alpha=(MagickRealType) GetPixelAlpha(image,q);
2719         /*
2720           Handle destination modifications outside overlaid region.
2721         */
2722         composite=destination;
2723         if ((pixels == (Quantum *) NULL) || (x < x_offset) ||
2724             ((x-x_offset) >= (ssize_t) composite_image->columns))
2725           {
2726             switch (compose)
2727             {
2728               case DissolveCompositeOp:
2729               case BlendCompositeOp:
2730               {
2731                 composite.alpha=destination_dissolve*(composite.alpha);
2732                 break;
2733               }
2734               case ClearCompositeOp:
2735               case SrcCompositeOp:
2736               {
2737                 CompositeClear(&destination,&composite);
2738                 break;
2739               }
2740               case InCompositeOp:
2741               case SrcInCompositeOp:
2742               case OutCompositeOp:
2743               case SrcOutCompositeOp:
2744               case DstInCompositeOp:
2745               case DstAtopCompositeOp:
2746               case CopyOpacityCompositeOp:
2747               case ChangeMaskCompositeOp:
2748               {
2749                 composite.alpha=(MagickRealType) TransparentAlpha;
2750                 break;
2751               }
2752               default:
2753               {
2754                 (void) GetOneVirtualPixelInfo(composite_image,
2755                   GetPixelCacheVirtualMethod(composite_image),x-x_offset,y-
2756                   y_offset,&composite,exception);
2757                 break;
2758               }
2759             }
2760             if (image->colorspace == CMYKColorspace)
2761               {
2762                 composite.red=(MagickRealType) QuantumRange-composite.red;
2763                 composite.green=(MagickRealType) QuantumRange-composite.green;
2764                 composite.blue=(MagickRealType) QuantumRange-composite.blue;
2765                 composite.black=(MagickRealType) QuantumRange-composite.black;
2766               }
2767             SetPixelRed(image,ClampToQuantum(composite.red),q);
2768             SetPixelGreen(image,ClampToQuantum(composite.green),q);
2769             SetPixelBlue(image,ClampToQuantum(composite.blue),q);
2770             if (image->matte != MagickFalse)
2771               SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
2772             if (image->colorspace == CMYKColorspace)
2773               SetPixelBlack(image,ClampToQuantum(composite.black),q);
2774             q+=GetPixelChannels(image);
2775             continue;
2776           }
2777         /*
2778           Handle normal overlay of source onto destination.
2779         */
2780         source.red=(MagickRealType) GetPixelRed(composite_image,p);
2781         source.green=(MagickRealType) GetPixelGreen(composite_image,p);
2782         source.blue=(MagickRealType) GetPixelBlue(composite_image,p);
2783         if (composite_image->colorspace == CMYKColorspace)
2784           source.black=(MagickRealType) GetPixelBlack(composite_image,p);
2785         if (composite_image->colorspace == CMYKColorspace)
2786           {
2787             source.red=(MagickRealType) QuantumRange-source.red;
2788             source.green=(MagickRealType) QuantumRange-source.green;
2789             source.blue=(MagickRealType) QuantumRange-source.blue;
2790             source.black=(MagickRealType) QuantumRange-source.black;
2791           }
2792         if (composite_image->matte != MagickFalse)
2793           source.alpha=(MagickRealType) GetPixelAlpha(composite_image,p);
2794         /*
2795           Porter-Duff compositions.
2796         */
2797         switch (compose)
2798         {
2799           case ClearCompositeOp:
2800           {
2801             CompositeClear(&destination,&composite);
2802             break;
2803           }
2804           case SrcCompositeOp:
2805           case CopyCompositeOp:
2806           case ReplaceCompositeOp:
2807           {
2808             composite=source;
2809             break;
2810           }
2811           case NoCompositeOp:
2812           case DstCompositeOp:
2813             break;
2814           case OverCompositeOp:
2815           case SrcOverCompositeOp:
2816           {
2817             CompositePixelInfoOver(&source,source.alpha,&destination,
2818               destination.alpha,&composite);
2819             break;
2820           }
2821           case DstOverCompositeOp:
2822           {
2823             CompositePixelInfoOver(&destination,destination.alpha,&source,
2824               source.alpha,&composite);
2825             break;
2826           }
2827           case SrcInCompositeOp:
2828           case InCompositeOp:
2829           {
2830             CompositeIn(&source,&destination,&composite);
2831             break;
2832           }
2833           case DstInCompositeOp:
2834           {
2835             CompositeIn(&destination,&source,&composite);
2836             break;
2837           }
2838           case OutCompositeOp:
2839           case SrcOutCompositeOp:
2840           {
2841             CompositeOut(&source,&destination,&composite);
2842             break;
2843           }
2844           case DstOutCompositeOp:
2845           {
2846             CompositeOut(&destination,&source,&composite);
2847             break;
2848           }
2849           case AtopCompositeOp:
2850           case SrcAtopCompositeOp:
2851           {
2852             CompositeAtop(&source,&destination,&composite);
2853             break;
2854           }
2855           case DstAtopCompositeOp:
2856           {
2857             CompositeAtop(&destination,&source,&composite);
2858             break;
2859           }
2860           case XorCompositeOp:
2861           {
2862             CompositeXor(&source,&destination,&composite);
2863             break;
2864           }
2865           case PlusCompositeOp:
2866           {
2867             CompositePlus(image,&source,&destination,&composite);
2868             break;
2869           }
2870           case MinusDstCompositeOp:
2871           {
2872             CompositeMinus(image,&source,&destination,&composite);
2873             break;
2874           }
2875           case MinusSrcCompositeOp:
2876           {
2877             CompositeMinus(image,&destination,&source,&composite);
2878             break;
2879           }
2880           case ModulusAddCompositeOp:
2881           {
2882             CompositeModulusAdd(image,&source,&destination,&composite);
2883             break;
2884           }
2885           case ModulusSubtractCompositeOp:
2886           {
2887             CompositeModulusSubtract(image,&source,&destination,&composite);
2888             break;
2889           }
2890           case DifferenceCompositeOp:
2891           {
2892             CompositeDifference(image,&source,&destination,&composite);
2893             break;
2894           }
2895           case ExclusionCompositeOp:
2896           {
2897             CompositeExclusion(image,&source,&destination,&composite);
2898             break;
2899           }
2900           case MultiplyCompositeOp:
2901           {
2902             CompositeMultiply(image,&source,&destination,&composite);
2903             break;
2904           }
2905           case ScreenCompositeOp:
2906           {
2907             CompositeScreen(image,&source,&destination,&composite);
2908             break;
2909           }
2910           case DivideDstCompositeOp:
2911           {
2912             CompositeDivide(image,&source,&destination,&composite);
2913             break;
2914           }
2915           case DivideSrcCompositeOp:
2916           {
2917             CompositeDivide(image,&destination,&source,&composite);
2918             break;
2919           }
2920           case DarkenCompositeOp:
2921           {
2922             CompositeDarken(image,&source,&destination,&composite);
2923             break;
2924           }
2925           case LightenCompositeOp:
2926           {
2927             CompositeLighten(image,&source,&destination,&composite);
2928             break;
2929           }
2930           case DarkenIntensityCompositeOp:
2931           {
2932             CompositeDarkenIntensity(image,&source,&destination,&composite);
2933             break;
2934           }
2935           case LightenIntensityCompositeOp:
2936           {
2937             CompositeLightenIntensity(image,&source,&destination,&composite);
2938             break;
2939           }
2940           case MathematicsCompositeOp:
2941           {
2942             CompositeMathematics(image,&source,&destination,&geometry_info,
2943               &composite);
2944             break;
2945           }
2946           case ColorDodgeCompositeOp:
2947           {
2948             CompositeColorDodge(&source,&destination,&composite);
2949             break;
2950           }
2951           case ColorBurnCompositeOp:
2952           {
2953             CompositeColorBurn(&source,&destination,&composite);
2954             break;
2955           }
2956           case LinearDodgeCompositeOp:
2957           {
2958             CompositeLinearDodge(&source,&destination,&composite);
2959             break;
2960           }
2961           case LinearBurnCompositeOp:
2962           {
2963             CompositeLinearBurn(&source,&destination,&composite);
2964             break;
2965           }
2966           case HardLightCompositeOp:
2967           {
2968             CompositeHardLight(&source,&destination,&composite);
2969             break;
2970           }
2971           case OverlayCompositeOp:
2972           {
2973             CompositeHardLight(&destination,&source,&composite);
2974             break;
2975           }
2976           case SoftLightCompositeOp:
2977           {
2978             CompositeSoftLight(&source,&destination,&composite);
2979             break;
2980           }
2981           case LinearLightCompositeOp:
2982           {
2983             CompositeLinearLight(&source,&destination,&composite);
2984             break;
2985           }
2986           case PegtopLightCompositeOp:
2987           {
2988             CompositePegtopLight(&source,&destination,&composite);
2989             break;
2990           }
2991           case VividLightCompositeOp:
2992           {
2993             CompositeVividLight(&source,&destination,&composite);
2994             break;
2995           }
2996           case PinLightCompositeOp:
2997           {
2998             CompositePinLight(&source,&destination,&composite);
2999             break;
3000           }
3001           case ChangeMaskCompositeOp:
3002           {
3003             if ((composite.alpha > ((MagickRealType) QuantumRange/2.0)) ||
3004                 (IsFuzzyEquivalencePixelInfo(&source,&destination) != MagickFalse))
3005               composite.alpha=(MagickRealType) TransparentAlpha;
3006             else
3007               composite.alpha=(MagickRealType) OpaqueAlpha;
3008             break;
3009           }
3010           case BumpmapCompositeOp:
3011           {
3012             if (source.alpha == TransparentAlpha)
3013               break;
3014             CompositeBumpmap(&source,&destination,&composite);
3015             break;
3016           }
3017           case DissolveCompositeOp:
3018           {
3019             CompositePixelInfoOver(&source,source_dissolve*source.alpha,
3020               &destination,(MagickRealType) (destination_dissolve*
3021               destination.alpha),&composite);
3022             break;
3023           }
3024           case BlendCompositeOp:
3025           {
3026             CompositePixelInfoBlend(&source,source_dissolve,&destination,
3027               destination_dissolve,&composite);
3028             break;
3029           }
3030           case ThresholdCompositeOp:
3031           {
3032             CompositeThreshold(&source,&destination,threshold,amount,&composite);
3033             break;
3034           }
3035           case ModulateCompositeOp:
3036           {
3037             double
3038               blue,
3039               green,
3040               red;
3041
3042             ssize_t
3043               offset;
3044
3045             if (source.alpha == TransparentAlpha)
3046               break;
3047             offset=(ssize_t) (GetPixelInfoIntensity(&source)-midpoint);
3048             if (offset == 0)
3049               break;
3050             CompositeHSB(destination.red,destination.green,destination.blue,&hue,
3051               &saturation,&brightness);
3052             brightness+=(0.01*percent_brightness*offset)/midpoint;
3053             saturation*=0.01*percent_saturation;
3054             HSBComposite(hue,saturation,brightness,&red,&green,&blue);
3055             composite.red=red;
3056             composite.green=green;
3057             composite.blue=blue;
3058             break;
3059           }
3060           case HueCompositeOp:
3061           {
3062             if (source.alpha == TransparentAlpha)
3063               break;
3064             if (destination.alpha == TransparentAlpha)
3065               {
3066                 composite=source;
3067                 break;
3068               }
3069             CompositeHSB(destination.red,destination.green,destination.blue,&hue,
3070               &saturation,&brightness);
3071             CompositeHSB(source.red,source.green,source.blue,&hue,&sans,&sans);
3072             HSBComposite(hue,saturation,brightness,&composite.red,
3073               &composite.green,&composite.blue);
3074             if (source.alpha < destination.alpha)
3075               composite.alpha=source.alpha;
3076             break;
3077           }
3078           case SaturateCompositeOp:
3079           {
3080             if (source.alpha == TransparentAlpha)
3081               break;
3082             if (destination.alpha == TransparentAlpha)
3083               {
3084                 composite=source;
3085                 break;
3086               }
3087             CompositeHSB(destination.red,destination.green,destination.blue,&hue,
3088               &saturation,&brightness);
3089             CompositeHSB(source.red,source.green,source.blue,&sans,&saturation,
3090               &sans);
3091             HSBComposite(hue,saturation,brightness,&composite.red,
3092               &composite.green,&composite.blue);
3093             if (source.alpha < destination.alpha)
3094               composite.alpha=source.alpha;
3095             break;
3096           }
3097           case LuminizeCompositeOp:
3098           {
3099             if (source.alpha == TransparentAlpha)
3100               break;
3101             if (destination.alpha == TransparentAlpha)
3102               {
3103                 composite=source;
3104                 break;
3105               }
3106             CompositeHSB(destination.red,destination.green,destination.blue,&hue,
3107               &saturation,&brightness);
3108             CompositeHSB(source.red,source.green,source.blue,&sans,&sans,
3109               &brightness);
3110             HSBComposite(hue,saturation,brightness,&composite.red,
3111               &composite.green,&composite.blue);
3112             if (source.alpha < destination.alpha)
3113               composite.alpha=source.alpha;
3114             break;
3115           }
3116           case ColorizeCompositeOp:
3117           {
3118             if (source.alpha == TransparentAlpha)
3119               break;
3120             if (destination.alpha == TransparentAlpha)
3121               {
3122                 composite=source;
3123                 break;
3124               }
3125             CompositeHSB(destination.red,destination.green,destination.blue,&sans,
3126               &sans,&brightness);
3127             CompositeHSB(source.red,source.green,source.blue,&hue,&saturation,
3128               &sans);
3129             HSBComposite(hue,saturation,brightness,&composite.red,
3130               &composite.green,&composite.blue);
3131             if (source.alpha < destination.alpha)
3132               composite.alpha=source.alpha;
3133             break;
3134           }
3135           case CopyRedCompositeOp:
3136           case CopyCyanCompositeOp:
3137           {
3138             composite.red=source.red;
3139             break;
3140           }
3141           case CopyGreenCompositeOp:
3142           case CopyMagentaCompositeOp:
3143           {
3144             composite.green=source.green;
3145             break;
3146           }
3147           case CopyBlueCompositeOp:
3148           case CopyYellowCompositeOp:
3149           {
3150             composite.blue=source.blue;
3151             break;
3152           }
3153           case CopyOpacityCompositeOp:
3154           {
3155             if (source.matte == MagickFalse)
3156               {
3157                 composite.alpha=(MagickRealType) GetPixelInfoIntensity(&source);
3158                 break;
3159               }
3160             composite.alpha=source.alpha;
3161             break;
3162           }
3163           case CopyBlackCompositeOp:
3164           {
3165             if (source.colorspace != CMYKColorspace)
3166               ConvertRGBToCMYK(&source);
3167             composite.black=source.black;
3168             break;
3169           }
3170           case BlurCompositeOp:
3171           case DisplaceCompositeOp:
3172           case DistortCompositeOp:
3173           {
3174             composite=source;
3175             break;
3176           }
3177           default:
3178             break;
3179         }
3180         if (image->colorspace == CMYKColorspace)
3181           {
3182             composite.red=(MagickRealType) QuantumRange-composite.red;
3183             composite.green=(MagickRealType) QuantumRange-composite.green;
3184             composite.blue=(MagickRealType) QuantumRange-composite.blue;
3185             composite.black=(MagickRealType) QuantumRange-composite.black;
3186           }
3187         SetPixelRed(image,ClampToQuantum(composite.red),q);
3188         SetPixelGreen(image,ClampToQuantum(composite.green),q);
3189         SetPixelBlue(image,ClampToQuantum(composite.blue),q);
3190         if (image->colorspace == CMYKColorspace)
3191           SetPixelBlack(image,ClampToQuantum(composite.black),q);
3192         SetPixelAlpha(image,ClampToQuantum(composite.alpha),q);
3193       }
3194       p+=GetPixelChannels(composite_image);
3195       if (p >= (pixels+composite_image->columns*GetPixelChannels(composite_image)))
3196         p=pixels;
3197       q+=GetPixelChannels(image);
3198     }
3199     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3200       status=MagickFalse;
3201     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3202       {
3203         MagickBooleanType
3204           proceed;
3205
3206 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3207   #pragma omp critical (MagickCore_CompositeImage)
3208 #endif
3209         proceed=SetImageProgress(image,CompositeImageTag,progress++,
3210           image->rows);
3211         if (proceed == MagickFalse)
3212           status=MagickFalse;
3213       }
3214   }
3215   composite_view=DestroyCacheView(composite_view);
3216   image_view=DestroyCacheView(image_view);
3217   if (destination_image != (Image * ) NULL)
3218     destination_image=DestroyImage(destination_image);
3219   return(status);
3220 }
3221 \f
3222 /*
3223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3224 %                                                                             %
3225 %                                                                             %
3226 %                                                                             %
3227 %     T e x t u r e I m a g e                                                 %
3228 %                                                                             %
3229 %                                                                             %
3230 %                                                                             %
3231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3232 %
3233 %  TextureImage() repeatedly tiles the texture image across and down the image
3234 %  canvas.
3235 %
3236 %  The format of the TextureImage method is:
3237 %
3238 %      MagickBooleanType TextureImage(Image *image,const Image *texture,
3239 %        ExceptionInfo *exception)
3240 %
3241 %  A description of each parameter follows:
3242 %
3243 %    o image: the image.
3244 %
3245 %    o texture: This image is the texture to layer on the background.
3246 %
3247 */
3248 MagickExport MagickBooleanType TextureImage(Image *image,const Image *texture,
3249   ExceptionInfo *exception)
3250 {
3251 #define TextureImageTag  "Texture/Image"
3252
3253   CacheView
3254     *image_view,
3255     *texture_view;
3256
3257   MagickBooleanType
3258     status;
3259
3260   ssize_t
3261     y;
3262
3263   assert(image != (Image *) NULL);
3264   if (image->debug != MagickFalse)
3265     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3266   assert(image->signature == MagickSignature);
3267   if (texture == (const Image *) NULL)
3268     return(MagickFalse);
3269   (void) SetImageVirtualPixelMethod(texture,TileVirtualPixelMethod);
3270   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3271     return(MagickFalse);
3272   status=MagickTrue;
3273   if ((image->compose != CopyCompositeOp) &&
3274       ((image->compose != OverCompositeOp) || (image->matte != MagickFalse) ||
3275        (texture->matte != MagickFalse)))
3276     {
3277       /*
3278         Tile texture onto the image background.
3279       */
3280 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3281       #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
3282 #endif
3283       for (y=0; y < (ssize_t) image->rows; y+=(ssize_t) texture->rows)
3284       {
3285         register ssize_t
3286           x;
3287
3288         if (status == MagickFalse)
3289           continue;
3290         for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
3291         {
3292           MagickBooleanType
3293             thread_status;
3294
3295           thread_status=CompositeImage(image,image->compose,texture,x+
3296             texture->tile_offset.x,y+texture->tile_offset.y,exception);
3297           if (thread_status == MagickFalse)
3298             {
3299               status=thread_status;
3300               break;
3301             }
3302         }
3303         if (image->progress_monitor != (MagickProgressMonitor) NULL)
3304           {
3305             MagickBooleanType
3306               proceed;
3307
3308 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3309   #pragma omp critical (MagickCore_TextureImage)
3310 #endif
3311             proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType)
3312               y,image->rows);
3313             if (proceed == MagickFalse)
3314               status=MagickFalse;
3315           }
3316       }
3317       (void) SetImageProgress(image,TextureImageTag,(MagickOffsetType)
3318         image->rows,image->rows);
3319       return(status);
3320     }
3321   /*
3322     Tile texture onto the image background (optimized).
3323   */
3324   status=MagickTrue;
3325   image_view=AcquireCacheView(image);
3326   texture_view=AcquireCacheView(texture);
3327 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3328   #pragma omp parallel for schedule(dynamic,4) shared(status) omp_throttle(1)
3329 #endif
3330   for (y=0; y < (ssize_t) image->rows; y++)
3331   {
3332     MagickBooleanType
3333       sync;
3334
3335     register const Quantum
3336       *p,
3337       *pixels;
3338
3339     register ssize_t
3340       x;
3341
3342     register Quantum
3343       *q;
3344
3345     size_t
3346       width;
3347
3348     if (status == MagickFalse)
3349       continue;
3350     pixels=GetCacheViewVirtualPixels(texture_view,texture->tile_offset.x,(y+
3351       texture->tile_offset.y) % texture->rows,texture->columns,1,exception);
3352     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
3353       exception);
3354     if ((pixels == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3355       {
3356         status=MagickFalse;
3357         continue;
3358       }
3359     for (x=0; x < (ssize_t) image->columns; x+=(ssize_t) texture->columns)
3360     {
3361       register ssize_t
3362         i;
3363
3364       p=pixels;
3365       width=texture->columns;
3366       if ((x+(ssize_t) width) > (ssize_t) image->columns)
3367         width=image->columns-x;
3368       for (i=0; i < (ssize_t) width; i++)
3369       {
3370         SetPixelRed(image,GetPixelRed(texture,p),q);
3371         SetPixelGreen(image,GetPixelGreen(texture,p),q);
3372         SetPixelBlue(image,GetPixelBlue(texture,p),q);
3373         SetPixelAlpha(image,GetPixelAlpha(texture,p),q);
3374         if ((image->colorspace == CMYKColorspace)  &&
3375             (texture->colorspace == CMYKColorspace))
3376           SetPixelBlack(image,GetPixelBlack(texture,p),q);
3377         p+=GetPixelChannels(texture);
3378         q+=GetPixelChannels(image);
3379       }
3380     }
3381     sync=SyncCacheViewAuthenticPixels(image_view,exception);
3382     if (sync == MagickFalse)
3383       status=MagickFalse;
3384     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3385       {
3386         MagickBooleanType
3387           proceed;
3388
3389 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3390         #pragma omp critical (MagickCore_TextureImage)
3391 #endif
3392         proceed=SetImageProgress(image,TextureImageTag,(MagickOffsetType) y,
3393           image->rows);
3394         if (proceed == MagickFalse)
3395           status=MagickFalse;
3396       }
3397   }
3398   texture_view=DestroyCacheView(texture_view);
3399   image_view=DestroyCacheView(image_view);
3400   return(status);
3401 }