]> granicus.if.org Git - imagemagick/blob - MagickCore/composite-private.h
27033a592e9804332371e2dca2fa5f8b6245f476
[imagemagick] / MagickCore / composite-private.h
1 /*
2   Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization
3   dedicated to making software imaging solutions freely available.
4
5   You may not use this file except in compliance with the License.
6   obtain a copy of the License at
7
8     http://www.imagemagick.org/script/license.php
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15
16   MagickCore image composite private methods.
17 */
18 #ifndef _MAGICKCORE_COMPOSITE_PRIVATE_H
19 #define _MAGICKCORE_COMPOSITE_PRIVATE_H
20
21 #if defined(__cplusplus) || defined(c_plusplus)
22 extern "C" {
23 #endif
24
25 /*
26   ImageMagick Alpha Composite Inline Methods (special export)
27 */
28
29 #include "MagickCore/color.h"
30 #include "MagickCore/image.h"
31 #include "MagickCore/image-private.h"
32 #include "MagickCore/pixel-accessor.h"
33 #include "MagickCore/pixel-private.h"
34
35 static inline double MagickOver_(const double p,
36   const double alpha,const double q,const double beta)
37 {
38   double
39     Da,
40     Sa;
41
42   Sa=QuantumScale*alpha;
43   Da=QuantumScale*beta;
44   return(Sa*p-Sa*Da*q+Da*q);
45 }
46
47 static inline void CompositePixelOver(const Image *image,const PixelInfo *p,
48   const double alpha,const Quantum *q,const double beta,Quantum *composite)
49 {
50   double
51     Da,
52     gamma,
53     Sa;
54
55   register ssize_t
56     i;
57
58   /*
59     Compose pixel p over pixel q with the given alpha.
60   */
61   Sa=QuantumScale*alpha;
62   Da=QuantumScale*beta,
63   gamma=Sa*(-Da)+Sa+Da;
64   gamma=PerceptibleReciprocal(gamma);
65   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
66   {
67     PixelChannel
68       channel;
69
70     PixelTrait
71       traits;
72
73     channel=GetPixelChannelChannel(image,i);
74     traits=GetPixelChannelTraits(image,channel);
75     if (traits == UndefinedPixelTrait)
76       continue;
77     switch (channel)
78     {
79       case RedPixelChannel:
80       {
81         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->red,
82           alpha,(double) q[i],beta));
83         break;
84       }
85       case GreenPixelChannel:
86       {
87         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->green,
88           alpha,(double) q[i],beta));
89         break;
90       }
91       case BluePixelChannel:
92       {
93         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->blue,
94           alpha,(double) q[i],beta));
95         break;
96       }
97       case BlackPixelChannel:
98       {
99         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->black,
100           alpha,(double) q[i],beta));
101         break;
102       }
103       case AlphaPixelChannel:
104       {
105         composite[i]=ClampToQuantum(QuantumRange*(Sa*(-Da)+Sa+Da));
106         break;
107       }
108       default:
109         break;
110     }
111   }
112 }
113
114 static inline void CompositePixelInfoOver(const PixelInfo *p,
115   const double alpha,const PixelInfo *q,const double beta,PixelInfo *composite)
116 {
117   double
118     Da,
119     gamma,
120     Sa;
121
122   /*
123     Compose pixel p over pixel q with the given opacities.
124   */
125   if (fabs(alpha-OpaqueAlpha) < MagickEpsilon)
126     {
127       *composite=(*p);
128       return;
129     }
130   Sa=QuantumScale*alpha;
131   Da=QuantumScale*beta,
132   gamma=Sa*(-Da)+Sa+Da;
133   composite->alpha=(double) QuantumRange*gamma;
134   gamma=PerceptibleReciprocal(gamma);
135   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
136   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
137   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
138   if (q->colorspace == CMYKColorspace)
139     composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
140 }
141
142 static inline double RoundToUnity(const double value)
143 {
144   return(value < 0.0 ? 0.0 : (value > 1.0) ? 1.0 : value);
145 }
146
147 static inline void CompositePixelInfoPlus(const PixelInfo *p,
148   const double alpha,const PixelInfo *q,const double beta,PixelInfo *composite)
149 {
150   double
151     Da,
152     gamma,
153     Sa;
154
155   /*
156     Add two pixels with the given opacities.
157   */
158   Sa=QuantumScale*alpha;
159   Da=QuantumScale*beta;
160   gamma=RoundToUnity(Sa+Da);  /* 'Plus' blending -- not 'Over' blending */
161   composite->alpha=(double) QuantumRange*gamma;
162   gamma=PerceptibleReciprocal(gamma);
163   composite->red=gamma*(Sa*p->red+Da*q->red);
164   composite->green=gamma*(Sa*p->green+Da*q->green);
165   composite->blue=gamma*(Sa*p->blue+Da*q->blue);
166   if (q->colorspace == CMYKColorspace)
167     composite->black=gamma*(Sa*p->black+Da*q->black);
168 }
169
170 static inline void CompositePixelInfoAreaBlend(const PixelInfo *p,
171   const double alpha,const PixelInfo *q,const double beta,const double area,
172   PixelInfo *composite)
173 {
174   /*
175     Blend pixel colors p and q by the amount given and area.
176   */
177   CompositePixelInfoPlus(p,(double) (1.0-area)*alpha,q,(double) (area*beta),
178     composite);
179 }
180
181 static inline void CompositePixelInfoBlend(const PixelInfo *p,
182   const double alpha,const PixelInfo *q,const double beta,PixelInfo *composite)
183 {
184   /*
185     Blend pixel colors p and q by the amount given.
186   */
187   CompositePixelInfoPlus(p,(double) (alpha*p->alpha),q,(double) (beta*q->alpha),
188     composite);
189 }
190
191 #if defined(__cplusplus) || defined(c_plusplus)
192 }
193 #endif
194
195 #endif