root / ImageMagick / branches / ImageMagick-6.3.5 / magick / composite.c

Revision 8071, 60.7 kB (checked in by cristy, 14 months ago)
Line 
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%                    ImageMagick Image Composite Methods                      %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2007 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
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/cache-view.h"
45#include "magick/client.h"
46#include "magick/color.h"
47#include "magick/color-private.h"
48#include "magick/colorspace.h"
49#include "magick/colorspace-private.h"
50#include "magick/composite.h"
51#include "magick/composite-private.h"
52#include "magick/constitute.h"
53#include "magick/draw.h"
54#include "magick/fx.h"
55#include "magick/gem.h"
56#include "magick/geometry.h"
57#include "magick/image.h"
58#include "magick/image-private.h"
59#include "magick/list.h"
60#include "magick/log.h"
61#include "magick/memory_.h"
62#include "magick/option.h"
63#include "magick/pixel-private.h"
64#include "magick/property.h"
65#include "magick/quantum.h"
66#include "magick/resample.h"
67#include "magick/resource_.h"
68#include "magick/string_.h"
69#include "magick/utility.h"
70#include "magick/version.h"
71
72/*
73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74%                                                                             %
75%                                                                             %
76%                                                                             %
77%   C o m p o s i t e I m a g e C h a n n e l                                 %
78%                                                                             %
79%                                                                             %
80%                                                                             %
81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82%
83%  CompositeImageChannel() returns the second image composited onto the first
84%  at the specified offsets.
85%
86%  The format of the CompositeImageChannel method is:
87%
88%      MagickBooleanType CompositeImage(Image *image,
89%        const CompositeOperator compose,Image *composite_image,
90%        const long x_offset,const long y_offset)
91%      MagickBooleanType CompositeImageChannel(Image *image,
92%        const ChannelType channel,const CompositeOperator compose,
93%        Image *composite_image,const long x_offset,const long y_offset)
94%
95%  A description of each parameter follows:
96%
97%    o image: The image.
98%
99%    o channel: The channel.
100%
101%    o compose: This operator affects how the composite is applied to
102%      the image.  The operators and how they are utilized are listed here
103%      http://www.w3.org/TR/SVG12/#compositing.
104%
105%    o composite_image: The composite image.
106%
107%    o x_offset: The column offset of the composited image.
108%
109%    o y_offset: The row offset of the composited image.
110%
111*/
112
113static inline double MagickMin(const double x,const double y)
114{
115  if (x < y)
116    return(x);
117  return(y);
118}
119
120static inline MagickRealType Add(const MagickRealType p,const MagickRealType q)
121{
122  MagickRealType
123    pixel;
124
125  pixel=p+q;
126  if (pixel > QuantumRange)
127    pixel-=(QuantumRange+1.0);
128  return(pixel);
129}
130
131static inline void CompositeAdd(const MagickPixelPacket *p,
132  const MagickRealType alpha,const MagickPixelPacket *q,
133  const MagickRealType beta,MagickPixelPacket *composite)
134{
135  composite->red=Add(p->red,q->red);
136  composite->green=Add(p->green,q->green);
137  composite->blue=Add(p->blue,q->blue);
138  composite->opacity=Add(alpha,beta);
139  if (q->colorspace == CMYKColorspace)
140    composite->index=Add(p->index,q->index);
141}
142
143static inline MagickRealType Atop(const MagickRealType p,
144  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
145{
146  MagickRealType
147    pixel;
148
149  pixel=((1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)+
150    (1.0-QuantumScale*beta)*q*QuantumScale*alpha);
151  return(pixel);
152}
153
154static inline void CompositeAtop(const MagickPixelPacket *p,
155  const MagickRealType alpha,const MagickPixelPacket *q,
156  const MagickRealType beta,MagickPixelPacket *composite)
157{
158  MagickRealType
159    gamma;
160
161  gamma=(1.0-QuantumScale*beta);
162  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
163  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
164  composite->red=gamma*Atop(p->red,alpha,q->red,beta);
165  composite->green=gamma*Atop(p->green,alpha,q->green,beta);
166  composite->blue=gamma*Atop(p->blue,alpha,q->blue,beta);
167  if (q->colorspace == CMYKColorspace)
168    composite->index=gamma*Atop(p->index,alpha,q->index,beta);
169}
170
171static inline void CompositeBumpmap(const MagickPixelPacket *p,
172  const MagickRealType magick_unused(alpha),const MagickPixelPacket *q,
173  const MagickRealType magick_unused(beta),MagickPixelPacket *composite)
174{
175  MagickRealType
176    intensity;
177
178  intensity=MagickPixelIntensity(p);
179  composite->red=QuantumScale*intensity*q->red;
180  composite->green=QuantumScale*intensity*q->green;
181  composite->blue=QuantumScale*intensity*q->blue;
182  composite->opacity=(MagickRealType) QuantumScale*intensity*p->opacity;
183  if (q->colorspace == CMYKColorspace)
184    composite->index=QuantumScale*intensity*q->index;
185}
186
187static inline void CompositeClear(const MagickPixelPacket *q,
188  MagickPixelPacket *composite)
189{
190  composite->red=0.0;
191  composite->green=0.0;
192  composite->blue=0.0;
193  composite->opacity=(MagickRealType) TransparentOpacity;
194  if (q->colorspace == CMYKColorspace)
195    composite->index=0.0;
196}
197
198static MagickRealType ColorBurn(const MagickRealType p,
199  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
200{
201  MagickRealType
202    delta,
203    pixel;
204
205  delta=QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)+
206    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha);
207  if (delta <= ((1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta)))
208    {
209      pixel=QuantumScale*(1.0-QuantumScale*alpha)*p*
210        (1.0-(1.0-QuantumScale*beta))+QuantumScale*(1.0-QuantumScale*beta)*q*
211        (1.0-(1.0-QuantumScale*alpha));
212      return(pixel);
213    }
214  pixel=QuantumScale*((1.0-QuantumScale*alpha)*(QuantumScale*(1.0-QuantumScale*
215    alpha)*p*(1.0-QuantumScale*beta)+QuantumScale*(1.0-QuantumScale*beta)*q*
216    (1.0-QuantumScale*alpha)-(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta))/
217    QuantumScale*(1.0-QuantumScale*alpha)*p+QuantumScale*(1.0-
218    QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+
219    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha)));
220  return(pixel);
221}
222
223static inline void CompositeColorBurn(const MagickPixelPacket *p,
224  const MagickRealType alpha,const MagickPixelPacket *q,
225  const MagickRealType beta,MagickPixelPacket *composite)
226{
227  MagickRealType
228    gamma;
229
230  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
231    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
232  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
233  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
234  composite->red=gamma*ColorBurn(p->red,alpha,q->red,beta);
235  composite->green=gamma*ColorBurn(p->green,alpha,q->green,beta);
236  composite->blue=gamma*ColorBurn(p->blue,alpha,q->blue,beta);
237  if (q->colorspace == CMYKColorspace)
238    composite->index=gamma*ColorBurn(p->index,alpha,q->index,beta);
239}
240
241static MagickRealType ColorDodge(const MagickRealType p,
242  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
243{
244  MagickRealType
245    delta,
246    pixel;
247
248  delta=QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)+
249    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha);
250  if (delta >= ((1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta)))
251    {
252      pixel=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta)+QuantumScale*
253        (1.0-QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+QuantumScale*
254        (1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha));
255      return((MagickRealType) QuantumRange*pixel);
256    }
257  pixel=QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha)/
258    (1.0-QuantumScale*(1.0-QuantumScale*alpha)*p/(1.0-QuantumScale*alpha))+
259    QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+
260    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha));
261  return((MagickRealType) QuantumRange*pixel);
262}
263
264static inline void CompositeColorDodge(const MagickPixelPacket *p,
265  const MagickRealType alpha,const MagickPixelPacket *q,
266  const MagickRealType beta,MagickPixelPacket *composite)
267{
268  MagickRealType
269    gamma;
270
271  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
272    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
273  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
274  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
275  composite->red=gamma*ColorDodge(p->red,alpha,q->red,beta);
276  composite->green=gamma*ColorDodge(p->green,alpha,q->green,beta);
277  composite->blue=gamma*ColorDodge(p->blue,alpha,q->blue,beta);
278  if (q->colorspace == CMYKColorspace)
279    composite->index=gamma*ColorDodge(p->index,alpha,q->index,beta);
280}
281
282static inline MagickRealType Darken(const MagickRealType p,
283  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
284{
285  MagickRealType
286    pixel;
287
288  if (((1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)) <
289      ((1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha)))
290    {
291      pixel=(1.0-QuantumScale*alpha)*p+(1.0-QuantumScale*beta)*q*QuantumScale*
292        alpha;
293      return(pixel);
294    }
295  pixel=(1.0-QuantumScale*beta)*q+(1.0-QuantumScale*alpha)*p*QuantumScale*beta;
296  return(pixel);
297}
298
299static inline void CompositeDarken(const MagickPixelPacket *p,
300  const MagickRealType alpha,const MagickPixelPacket *q,
301  const MagickRealType beta,MagickPixelPacket *composite)
302{
303  MagickRealType
304    gamma;
305
306  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
307    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
308  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
309  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
310  composite->red=gamma*Darken(p->red,alpha,q->red,beta);
311  composite->green=gamma*Darken(p->green,alpha,q->green,beta);
312  composite->blue=gamma*Darken(p->blue,alpha,q->blue,beta);
313  if (q->colorspace == CMYKColorspace)
314    composite->index=gamma*Darken(p->index,alpha,q->index,beta);
315}
316
317static inline MagickRealType Difference(const MagickRealType p,
318  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
319{
320  MagickRealType
321    pixel;
322
323  pixel=QuantumScale*(1.0-QuantumScale*alpha)*p+QuantumScale*
324    (1.0-QuantumScale*beta)*q-2.0*MagickMin(QuantumScale*(1.0-QuantumScale*
325    alpha)*p*(1.0-QuantumScale*beta),QuantumScale*(1.0-QuantumScale*beta)*q*
326    (1.0-QuantumScale*alpha));
327  return((MagickRealType) QuantumRange*pixel);
328}
329
330static inline void CompositeDifference(const MagickPixelPacket *p,
331  const MagickRealType alpha,const MagickPixelPacket *q,
332  const MagickRealType beta,MagickPixelPacket *composite)
333{
334  MagickRealType
335    gamma;
336
337  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
338    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
339  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
340  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
341  composite->red=gamma*Difference(p->red,alpha,q->red,beta);
342  composite->green=gamma*Difference(p->green,alpha,q->green,beta);
343  composite->blue=gamma*Difference(p->blue,alpha,q->blue,beta);
344  if (q->colorspace == CMYKColorspace)
345    composite->index=gamma*Difference(p->index,alpha,q->index,beta);
346}
347
348static inline MagickRealType Divide(const MagickRealType p,
349  const MagickRealType q)
350{
351  MagickRealType
352    pixel;
353
354  if (q == 0.0)
355    return(0.0);
356  pixel=p/q;
357  return((MagickRealType) QuantumRange*pixel);
358}
359
360static inline void CompositeDivide(const MagickPixelPacket *p,
361  const MagickRealType alpha,const MagickPixelPacket *q,
362  const MagickRealType beta,MagickPixelPacket *composite)
363{
364  composite->red=Divide(p->red,q->red);
365  composite->green=Divide(p->green,q->green);
366  composite->blue=Divide(p->blue,q->blue);
367  composite->opacity=Divide(alpha,beta);
368  if (q->colorspace == CMYKColorspace)
369    composite->index=Divide(p->index,q->index);
370}
371
372static inline MagickRealType Exclusion(const MagickRealType p,
373  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
374{
375  MagickRealType
376    pixel;
377
378  pixel=(QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)+
379    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha)-2.0*
380    QuantumScale*(1.0-QuantumScale*alpha)*p*QuantumScale*
381    (1.0-QuantumScale*beta)*q)+QuantumScale*(1.0-QuantumScale*alpha)*p*
382    (1.0-(1.0-QuantumScale*beta))+QuantumScale*(1.0-QuantumScale*beta)*q*
383    (1.0 -(1.0-QuantumScale*alpha));
384  return((MagickRealType) QuantumRange*pixel);
385}
386
387static inline void CompositeExclusion(const MagickPixelPacket *p,
388  const MagickRealType alpha,const MagickPixelPacket *q,
389  const MagickRealType beta,MagickPixelPacket *composite)
390{
391  MagickRealType
392    gamma;
393
394  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
395    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
396  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
397  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
398  composite->red=gamma*Exclusion(p->red,alpha,q->red,beta);
399  composite->green=gamma*Exclusion(p->green,alpha,q->green,beta);
400  composite->blue=gamma*Exclusion(p->blue,alpha,q->blue,beta);
401  if (q->colorspace == CMYKColorspace)
402    composite->index=gamma*Exclusion(p->index,alpha,q->index,beta);
403}
404
405static MagickRealType HardLight(const MagickRealType p,
406  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
407{
408  MagickRealType
409    pixel;
410
411  if ((2.0*QuantumScale*(1.0-QuantumScale*alpha)*p) < (1.0-QuantumScale*alpha))
412    {
413      pixel=2.0*QuantumScale*(1.0-QuantumScale*alpha)*p*QuantumScale*
414        (1.0-QuantumScale*beta)*q+QuantumScale*(1.0-QuantumScale*alpha)*p*
415        (1.0-(1.0-QuantumScale*beta))+QuantumScale*(1.0-QuantumScale*beta)*q*
416        (1.0-(1.0-QuantumScale*alpha));
417      return((MagickRealType) QuantumRange*pixel);
418    }
419  pixel=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta)-2.0*
420    ((1.0-QuantumScale*beta)-QuantumScale*(1.0-QuantumScale*beta)*q)*
421    ((1.0-QuantumScale*alpha)-QuantumScale*(1.0-QuantumScale*alpha)*p)+
422    QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+
423    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha));
424  return((MagickRealType) QuantumRange*pixel);
425}
426
427static inline void CompositeHardLight(const MagickPixelPacket *p,
428  const MagickRealType alpha,const MagickPixelPacket *q,
429  const MagickRealType beta,MagickPixelPacket *composite)
430{
431  MagickRealType
432    gamma;
433
434  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
435    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
436  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
437  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
438  composite->red=gamma*HardLight(p->red,alpha,q->red,beta);
439  composite->green=gamma*HardLight(p->green,alpha,q->green,beta);
440  composite->blue=gamma*HardLight(p->blue,alpha,q->blue,beta);
441  if (q->colorspace == CMYKColorspace)
442    composite->index=gamma*HardLight(p->index,alpha,q->index,beta);
443}
444
445static void CompositeHSB(const MagickRealType red,const MagickRealType green,
446  const MagickRealType blue,double *hue,double *saturation,double *brightness)
447{
448  MagickRealType
449    delta,
450    max,
451    min;
452
453  /*
454    Convert RGB to HSB colorspace.
455  */
456  assert(hue != (double *) NULL);
457  assert(saturation != (double *) NULL);
458  assert(brightness != (double *) NULL);
459  max=(red > green ? red : green);
460  if (blue > max)
461    max=blue;
462  min=(red < green ? red : green);
463  if (blue < min)
464    min=blue;
465  *hue=0.0;
466  *saturation=0.0;
467  *brightness=(double) (QuantumScale*max);
468  if (max == 0.0)
469    return;
470  *saturation=(double) (1.0-min/max);
471  delta=max-min;
472  if (delta == 0.0)
473    return;
474  if (red == max)
475    *hue=(double) ((green-blue)/delta);
476  else
477    if (green == max)
478      *hue=(double) (2.0+(blue-red)/delta);
479    else
480      if (blue == max)
481        *hue=(double) (4.0+(red-green)/delta);
482  *hue/=6.0;
483  if (*hue < 0.0)
484    *hue+=1.0;
485}
486
487static inline MagickRealType In(const MagickRealType p,
488  const MagickRealType alpha,const MagickRealType magick_unused(q),
489  const MagickRealType beta)
490{
491  MagickRealType
492    pixel;
493
494  pixel=(1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta);
495  return(pixel);
496}
497
498static inline void CompositeIn(const MagickPixelPacket *p,
499  const MagickRealType alpha,const MagickPixelPacket *q,
500  const MagickRealType beta,MagickPixelPacket *composite)
501{
502  MagickRealType
503    gamma;
504
505  gamma=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta);
506  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
507  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
508  composite->red=gamma*In(p->red,alpha,q->red,beta);
509  composite->green=gamma*In(p->green,alpha,q->green,beta);
510  composite->blue=gamma*In(p->blue,alpha,q->blue,beta);
511  if (q->colorspace == CMYKColorspace)
512    composite->index=gamma*In(p->index,alpha,q->index,beta);
513}
514
515static inline MagickRealType Lighten(const MagickRealType p,
516  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
517{
518  MagickRealType
519    pixel;
520
521  if (((1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)) >
522      ((1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha)))
523    {
524      pixel=(1.0-QuantumScale*alpha)*p+(1.0-QuantumScale*beta)*q*QuantumScale*
525        alpha;
526      return(pixel);
527    }
528  pixel=(1.0-QuantumScale*beta)*q+(1.0-QuantumScale*alpha)*p*QuantumScale*beta;
529  return(pixel);
530}
531
532static inline void CompositeLighten(const MagickPixelPacket *p,
533  const MagickRealType alpha,const MagickPixelPacket *q,
534  const MagickRealType beta,MagickPixelPacket *composite)
535{
536  MagickRealType
537    gamma;
538
539  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
540    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
541  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
542  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
543  composite->red=gamma*Lighten(p->red,alpha,q->red,beta);
544  composite->green=gamma*Lighten(p->green,alpha,q->green,beta);
545  composite->blue=gamma*Lighten(p->blue,alpha,q->blue,beta);
546  if (q->colorspace == CMYKColorspace)
547    composite->index=gamma*Lighten(p->index,alpha,q->index,beta);
548}
549
550static inline MagickRealType LinearLight(const MagickRealType p,
551  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
552{
553  return((1.0-QuantumScale*beta)*q+2.0*(1.0-QuantumScale*alpha)*p-1.0);
554}
555
556static inline void CompositeLinearLight(const MagickPixelPacket *p,
557  const MagickRealType alpha,const MagickPixelPacket *q,
558  const MagickRealType beta,MagickPixelPacket *composite)
559{
560  MagickRealType
561    gamma;
562
563  gamma=RoundToUnity((1.0-QuantumScale*beta)+2.0*(1.0-QuantumScale*alpha)-1.0);
564  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
565  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
566  composite->red=gamma*LinearLight(p->red,alpha,q->red,beta);
567  composite->green=gamma*LinearLight(p->green,alpha,q->green,beta);
568  composite->blue=gamma*LinearLight(p->blue,alpha,q->blue,beta);
569  if (q->colorspace == CMYKColorspace)
570    composite->index=gamma*LinearLight(p->index,alpha,q->index,beta);
571}   
572
573static inline MagickRealType Minus(const MagickRealType p,
574  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
575{
576  return((1.0-QuantumScale*alpha)*p-(1.0-QuantumScale*beta)*q);
577}
578
579static inline void CompositeMinus(const MagickPixelPacket *p,
580  const MagickRealType alpha,const MagickPixelPacket *q,
581  const MagickRealType beta,MagickPixelPacket *composite)
582{
583  MagickRealType
584    gamma;
585
586  gamma=RoundToUnity((1.0-QuantumScale*alpha)-(1.0-QuantumScale*beta));
587  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
588  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
589  composite->red=gamma*Minus(p->red,alpha,q->red,beta);
590  composite->green=gamma*Minus(p->green,alpha,q->green,beta);
591  composite->blue=gamma*Minus(p->blue,alpha,q->blue,beta);
592  if (q->colorspace == CMYKColorspace)
593    composite->index=gamma*Minus(p->index,alpha,q->index,beta);
594}
595
596static inline MagickRealType Multiply(const MagickRealType p,
597  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
598{
599  MagickRealType
600    pixel;
601
602  pixel=QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-QuantumScale*beta)*q+
603    (1.0-QuantumScale*alpha)*p*QuantumScale*beta+(1.0-QuantumScale*beta)*q*
604    QuantumScale*alpha;
605  return(pixel);
606}
607
608static inline void CompositeMultiply(const MagickPixelPacket *p,
609  const MagickRealType alpha,const MagickPixelPacket *q,
610  const MagickRealType beta,MagickPixelPacket *composite)
611{
612  MagickRealType
613    gamma;
614
615  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
616    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
617  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
618  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
619  composite->red=gamma*Multiply(p->red,alpha,q->red,beta);
620  composite->green=gamma*Multiply(p->green,alpha,q->green,beta);
621  composite->blue=gamma*Multiply(p->blue,alpha,q->blue,beta);
622  if (q->colorspace == CMYKColorspace)
623    composite->index=gamma*Multiply(p->index,alpha,q->index,beta);
624}
625
626static inline MagickRealType Out(const MagickRealType p,
627  const MagickRealType alpha,const MagickRealType magick_unused(q),
628  const MagickRealType beta)
629{
630  return((1.0-QuantumScale*alpha)*p*QuantumScale*beta);
631}
632
633static inline void CompositeOut(const MagickPixelPacket *p,
634  const MagickRealType alpha,const MagickPixelPacket *q,
635  const MagickRealType beta,MagickPixelPacket *composite)
636{
637  MagickRealType
638    gamma;
639
640  gamma=(1.0-QuantumScale*alpha)*QuantumScale*beta;
641  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
642  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
643  composite->red=gamma*Out(p->red,alpha,q->red,beta);
644  composite->green=gamma*Out(p->green,alpha,q->green,beta);
645  composite->blue=gamma*Out(p->blue,alpha,q->blue,beta);
646  if (q->colorspace == CMYKColorspace)
647    composite->index=gamma*Out(p->index,alpha,q->index,beta);
648}
649
650static inline void CompositeOver(const MagickPixelPacket *p,
651  const MagickRealType alpha,const MagickPixelPacket *q,
652  const MagickRealType beta,MagickPixelPacket *composite)
653{
654  MagickRealType
655    gamma;
656
657  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
658  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
659  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
660  composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
661  composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
662  composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
663  if (q->colorspace == CMYKColorspace)
664    composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
665}
666
667static MagickRealType Overlay(const MagickRealType p,const MagickRealType alpha,
668  const MagickRealType q,const MagickRealType beta)
669{
670  MagickRealType
671    pixel;
672
673  if ((2.0*QuantumScale*(1.0-QuantumScale*beta)*q) < (1.0-QuantumScale*beta))
674    {
675      pixel=2.0*QuantumScale*(1.0-QuantumScale*alpha)*p*QuantumScale*
676        (1.0-QuantumScale*beta)*q+QuantumScale*(1.0-QuantumScale*alpha)*p*
677        (1.0-(1.0-QuantumScale*beta))+QuantumScale*(1.0-QuantumScale*beta)*q*
678        (1.0-(1.0-QuantumScale*alpha));
679      return((MagickRealType) QuantumRange*pixel);
680    }
681  pixel=(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta)-2.0*
682    ((1.0-QuantumScale*beta)-QuantumScale*(1.0-QuantumScale*beta)*q)*
683    ((1.0-QuantumScale*alpha)-QuantumScale*(1.0-QuantumScale*alpha)*p)+
684    QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+
685    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha));
686  return((MagickRealType) QuantumRange*pixel);
687}
688
689static inline void CompositeOverlay(const MagickPixelPacket *p,
690  const MagickRealType alpha,const MagickPixelPacket *q,
691  const MagickRealType beta,MagickPixelPacket *composite)
692{
693  MagickRealType
694    gamma;
695
696  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
697    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
698  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
699  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
700  composite->red=gamma*Overlay(p->red,alpha,q->red,beta);
701  composite->green=gamma*Overlay(p->green,alpha,q->green,beta);
702  composite->blue=gamma*Overlay(p->blue,alpha,q->blue,beta);
703  if (q->colorspace == CMYKColorspace)
704    composite->index=gamma*Overlay(p->index,alpha,q->index,beta);
705}
706
707static inline MagickRealType Plus(const MagickRealType p,
708  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
709{
710  return((1.0-QuantumScale*alpha)*p+(1.0-QuantumScale*beta)*q);
711}
712
713static inline void CompositePlus(const MagickPixelPacket *p,
714  const MagickRealType alpha,const MagickPixelPacket *q,
715  const MagickRealType beta,MagickPixelPacket *composite)
716{
717  MagickRealType
718    gamma;
719
720  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta));
721  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
722  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
723  composite->red=gamma*Plus(p->red,alpha,q->red,beta);
724  composite->green=gamma*Plus(p->green,alpha,q->green,beta);
725  composite->blue=gamma*Plus(p->blue,alpha,q->blue,beta);
726  if (q->colorspace == CMYKColorspace)
727    composite->index=gamma*Plus(p->index,alpha,q->index,beta);
728}
729
730static inline MagickRealType Screen(const MagickRealType p,
731  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
732{
733  MagickRealType
734    pixel;
735
736  pixel=QuantumScale*(1.0-QuantumScale*alpha)*p+QuantumScale*
737    (1.0-QuantumScale*beta)*q-QuantumScale*(1.0-QuantumScale*alpha)*p*
738    QuantumScale*(1.0-QuantumScale*beta)*q;
739  return((MagickRealType) QuantumRange*pixel);
740}
741
742static inline void CompositeScreen(const MagickPixelPacket *p,
743  const MagickRealType alpha,const MagickPixelPacket *q,
744  const MagickRealType beta,MagickPixelPacket *composite)
745{
746  MagickRealType
747    gamma;
748
749  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
750    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
751  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
752  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
753  composite->red=gamma*Screen(p->red,alpha,q->red,beta);
754  composite->green=gamma*Screen(p->green,alpha,q->green,beta);
755  composite->blue=gamma*Screen(p->blue,alpha,q->blue,beta);
756  if (q->colorspace == CMYKColorspace)
757    composite->index=gamma*Screen(p->index,alpha,q->index,beta);
758}
759
760static MagickRealType SoftLight(const MagickRealType p,
761  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
762{
763  MagickRealType
764    pixel;
765
766  if ((2.0*QuantumScale*(1.0-QuantumScale*alpha)*p) < (1.0-QuantumScale*alpha))
767    {
768      pixel=QuantumScale*(1.0-QuantumScale*beta)*q*((1.0-QuantumScale*alpha)-
769        (1.0-QuantumScale*(1.0-QuantumScale*beta)*q/(1.0-QuantumScale*beta))*
770        (2.0*QuantumScale*(1.0-QuantumScale*alpha)*p-(1.0-QuantumScale*alpha)))+
771        QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+
772        QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha));
773      return((MagickRealType) QuantumRange*pixel);
774    }
775  if ((8.0*QuantumScale*(1.0-QuantumScale*beta)*q) <= (1.0-QuantumScale*beta))
776    {
777      pixel=QuantumScale*(1.0-QuantumScale*beta)*q*((1.0-QuantumScale*alpha)-
778        (1.0-QuantumScale*(1.0-QuantumScale*beta)*q/(1.0-QuantumScale*beta))*
779        (2.0*QuantumScale*(1.0-QuantumScale*alpha)*p-(1.0-QuantumScale*alpha))*
780        (3.0-8.0*QuantumScale*(1.0-QuantumScale*beta)*q/
781        (1.0-QuantumScale*beta)))+QuantumScale*(1.0-QuantumScale*alpha)*p*
782        (1.0-(1.0-QuantumScale*beta))+QuantumScale*(1.0-QuantumScale*beta)*q*
783        (1.0-(1.0-QuantumScale*alpha));
784      return((MagickRealType) QuantumRange*pixel);
785    }
786  pixel=(QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-QuantumScale*alpha)+
787    (pow(QuantumScale*(1.0-QuantumScale*beta)*q/(1.0-QuantumScale*beta),0.5)*
788    (1.0-QuantumScale*beta)-QuantumScale*(1.0-QuantumScale*beta)*q)*
789    (2.0*QuantumScale*(1.0-QuantumScale*alpha)*p-(1.0-QuantumScale*alpha)))+
790    QuantumScale*(1.0-QuantumScale*alpha)*p*(1.0-(1.0-QuantumScale*beta))+
791    QuantumScale*(1.0-QuantumScale*beta)*q*(1.0-(1.0-QuantumScale*alpha));
792  return((MagickRealType) QuantumRange*pixel);
793}
794
795static inline void CompositeSoftLight(const MagickPixelPacket *p,
796  const MagickRealType alpha,const MagickPixelPacket *q,
797  const MagickRealType beta,MagickPixelPacket *composite)
798{
799  MagickRealType
800    gamma;
801
802  gamma=RoundToUnity((1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
803    (1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta));
804  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
805  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
806  composite->red=gamma*SoftLight(p->red,alpha,q->red,beta);
807  composite->green=gamma*SoftLight(p->green,alpha,q->green,beta);
808  composite->blue=gamma*SoftLight(p->blue,alpha,q->blue,beta);
809  if (q->colorspace == CMYKColorspace)
810    composite->index=gamma*SoftLight(p->index,alpha,q->index,beta);
811}
812
813static inline MagickRealType Subtract(const MagickRealType p,
814  const MagickRealType magick_unused(alpha),const MagickRealType q,
815  const MagickRealType magick_unused(beta))
816{
817  MagickRealType
818    pixel;
819
820  pixel=p-q;
821  if (pixel < 0.0)
822    pixel+=(QuantumRange+1.0);
823  return(pixel);
824}
825
826static inline void CompositeSubtract(const MagickPixelPacket *p,
827  const MagickRealType alpha,const MagickPixelPacket *q,
828  const MagickRealType beta,MagickPixelPacket *composite)
829{
830  composite->red=Subtract(p->red,alpha,q->red,beta);
831  composite->green=Subtract(p->green,alpha,q->green,beta);
832  composite->blue=Subtract(p->blue,alpha,q->blue,beta);
833  if (q->colorspace == CMYKColorspace)
834    composite->index=Subtract(p->index,alpha,q->index,beta);
835}
836
837static inline MagickRealType Threshold(const MagickRealType p,
838  const MagickRealType magick_unused(alpha),const MagickRealType q,
839  const MagickRealType magick_unused(beta),const MagickRealType threshold,
840  const MagickRealType amount)
841{
842  MagickRealType
843    pixel;
844
845  pixel=p-q;
846  if ((MagickRealType) fabs((double) (2.0*pixel)) < threshold)
847    {
848      pixel=q;
849      return(pixel);
850    }
851  pixel=q+(pixel*amount);
852  return(pixel);
853}
854
855static inline void CompositeThreshold(const MagickPixelPacket *p,
856  const MagickRealType alpha,const MagickPixelPacket *q,
857  const MagickRealType beta,const MagickRealType threshold,
858  const MagickRealType amount,MagickPixelPacket *composite)
859{
860  composite->red=Threshold(p->red,alpha,q->red,beta,threshold,amount);
861  composite->green=Threshold(p->green,alpha,q->green,beta,threshold,amount);
862  composite->blue=Threshold(p->blue,alpha,q->blue,beta,threshold,amount);
863  composite->opacity=(MagickRealType) QuantumRange-
864    Threshold(p->opacity,alpha,q->opacity,beta,threshold,amount);
865  if (q->colorspace == CMYKColorspace)
866    composite->index=Threshold(p->index,alpha,q->index,beta,threshold,amount);
867}
868
869static inline MagickRealType Xor(const MagickRealType p,
870  const MagickRealType alpha,const MagickRealType q,const MagickRealType beta)
871{
872  MagickRealType
873    pixel;
874
875  pixel=(1.0-QuantumScale*alpha)*p*QuantumScale*beta+(1.0-QuantumScale*beta)*q*
876    QuantumScale*alpha;
877  return(pixel);
878}
879
880static inline void CompositeXor(const MagickPixelPacket *p,
881  const MagickRealType alpha,const MagickPixelPacket *q,
882  const MagickRealType beta,MagickPixelPacket *composite)
883{
884  MagickRealType
885    gamma;
886
887  gamma=(1.0-QuantumScale*alpha)+(1.0-QuantumScale*beta)-
888    2*(1.0-QuantumScale*alpha)*(1.0-QuantumScale*beta);
889  composite->opacity=(MagickRealType) QuantumRange*(1.0-gamma);
890  gamma=1.0/(fabs(gamma) <= MagickEpsilon ? 1.0 : gamma);
891  composite->red=gamma*Xor(p->red,alpha,q->red,beta);
892  composite->green=gamma*Xor(p->green,alpha,q->green,beta);
893  composite->blue=gamma*Xor(p->blue,alpha,q->blue,beta);
894  if (q->colorspace == CMYKColorspace)
895    composite->index=gamma*Xor(p->index,alpha,q->index,beta);
896}
897
898static void HSBComposite(const double hue,const double saturation,
899  const double brightness,MagickRealType *red,MagickRealType *green,
900  MagickRealType *blue)
901{
902  MagickRealType
903    f,
904    h,
905    p,
906    q,
907    t;
908
909  /*
910    Convert HSB to RGB colorspace.
911  */
912  assert(red != (MagickRealType *) NULL);
913  assert(green != (MagickRealType *) NULL);
914  assert(blue != (MagickRealType *) NULL);
915  if (saturation == 0.0)
916    {
917      *red=(MagickRealType) QuantumRange*brightness;
918      *green=(*red);
919      *blue=(*red);
920      return;
921    }
922  h=6.0*(hue-floor(hue));
923  f=h-floor((double) h);
924  p=brightness*(1.0-saturation);
925  q=brightness*(1.0-saturation*f);
926  t=brightness*(1.0-saturation*(1.0-f));
927  switch ((int) h)
928  {
929    case 0:
930    default:
931    {
932      *red=(MagickRealType) QuantumRange*brightness;
933      *green=(MagickRealType) QuantumRange*t;
934      *blue=(MagickRealType) QuantumRange*p;
935      break;
936    }
937    case 1:
938    {
939      *red=(MagickRealType) QuantumRange*q;
940      *green=(MagickRealType) QuantumRange*brightness;
941      *blue=(MagickRealType) QuantumRange*p;
942      break;
943    }
944    case 2:
945    {
946      *red=(MagickRealType) QuantumRange*p;
947      *green=(MagickRealType) QuantumRange*brightness;
948      *blue=(MagickRealType) QuantumRange*t;
949      break;
950    }
951    case 3:
952    {
953      *red=(MagickRealType) QuantumRange*p;
954      *green=(MagickRealType) QuantumRange*q;
955      *blue=(MagickRealType) QuantumRange*brightness;
956      break;
957    }
958    case 4:
959    {
960      *red=(MagickRealType) QuantumRange*t;
961      *green=(MagickRealType) QuantumRange*p;
962      *blue=(MagickRealType) QuantumRange*brightness;
963      break;
964    }
965    case 5:
966    {
967      *red=(MagickRealType) QuantumRange*brightness;
968      *green=(MagickRealType) QuantumRange*p;
969      *blue=(MagickRealType) QuantumRange*q;
970      break;
971    }
972  }
973}
974
975MagickExport MagickBooleanType CompositeImage(Image *image,
976  const CompositeOperator compose,const Image *composite_image,
977  const long x_offset,const long y_offset)
978{
979  MagickBooleanType
980    status;
981
982  status=CompositeImageChannel(image,DefaultChannels,compose,composite_image,
983    x_offset,y_offset);
984  return(status);
985}
986
987MagickExport MagickBooleanType CompositeImageChannel(Image *image,
988  const ChannelType magick_unused(channel),const CompositeOperator compose,
989  const Image *composite_image,const long x_offset,const long y_offset)
990{
991  const char
992    *value;
993
994  const PixelPacket
995    *pixels;
996
997  double
998    brightness,
999    hue,
1000    sans,
1001    saturation;
1002
1003  GeometryInfo
1004    geometry_info;
1005
1006  Image
1007    *displace_image;
1008
1009  IndexPacket
1010    *composite_indexes,
1011    *indexes;
1012
1013  long
1014    y;
1015
1016  MagickBooleanType
1017    modify_outside_overlay;
1018
1019  MagickPixelPacket
1020    composite,
1021    destination,
1022    source;
1023
1024  MagickRealType
1025    amount,
1026    destination_dissolve,
1027    midpoint,
1028    percent_brightness,
1029    percent_saturation,
1030    quantum_sans,