]> granicus.if.org Git - imagemagick/blob - MagickCore/composite-private.h
(no commit message)
[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,
49   Quantum *composite)
50 {
51   double
52     Da,
53     gamma,
54     Sa;
55
56   register ssize_t
57     i;
58
59   /*
60     Compose pixel p over pixel q with the given alpha.
61   */
62   Sa=QuantumScale*alpha;
63   Da=QuantumScale*beta,
64   gamma=Sa*(-Da)+Sa+Da;
65   gamma=MagickEpsilonReciprocal(gamma);
66   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
67   {
68     PixelChannel
69       channel;
70
71     PixelTrait
72       traits;
73
74     channel=GetPixelChannelChannel(image,i);
75     traits=GetPixelChannelTraits(image,channel);
76     if (traits == UndefinedPixelTrait)
77       continue;
78     switch (channel)
79     {
80       case RedPixelChannel:
81       {
82         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->red,
83           alpha,(double) q[i],beta));
84         break;
85       }
86       case GreenPixelChannel:
87       {
88         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->green,
89           alpha,(double) q[i],beta));
90         break;
91       }
92       case BluePixelChannel:
93       {
94         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->blue,
95           alpha,(double) q[i],beta));
96         break;
97       }
98       case BlackPixelChannel:
99       {
100         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->black,
101           alpha,(double) q[i],beta));
102         break;
103       }
104       case AlphaPixelChannel:
105       {
106         composite[i]=ClampToQuantum(QuantumRange*(Sa*(-Da)+Sa+Da));
107         break;
108       }
109       default:
110         break;
111     }
112   }
113 }
114
115 static inline void CompositePixelInfoOver(const PixelInfo *p,
116   const double alpha,const PixelInfo *q,const double beta,
117   PixelInfo *composite)
118 {
119   double
120     Da,
121     gamma,
122     Sa;
123
124   /*
125     Compose pixel p over pixel q with the given opacities.
126   */
127   if (fabs(alpha-OpaqueAlpha) < MagickEpsilon)
128     {
129       *composite=(*p);
130       return;
131     }
132   Sa=QuantumScale*alpha;
133   Da=QuantumScale*beta,
134   gamma=Sa*(-Da)+Sa+Da;
135   composite->alpha=(double) QuantumRange*gamma;
136   gamma=MagickEpsilonReciprocal(gamma);
137   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
138   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
139   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
140   if (q->colorspace == CMYKColorspace)
141     composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
142 }
143
144 static inline double RoundToUnity(const double value)
145 {
146   return(value < 0.0 ? 0.0 : (value > 1.0) ? 1.0 : value);
147 }
148
149 static inline void CompositePixelInfoPlus(const PixelInfo *p,
150   const double alpha,const PixelInfo *q,const double beta,
151   PixelInfo *composite)
152 {
153   double
154     Da,
155     gamma,
156     Sa;
157
158   /*
159     Add two pixels with the given opacities.
160   */
161   Sa=QuantumScale*alpha;
162   Da=QuantumScale*beta;
163   gamma=RoundToUnity(Sa+Da);  /* 'Plus' blending -- not 'Over' blending */
164   composite->alpha=(double) QuantumRange*gamma;
165   gamma=MagickEpsilonReciprocal(gamma);
166   composite->red=gamma*(Sa*p->red+Da*q->red);
167   composite->green=gamma*(Sa*p->green+Da*q->green);
168   composite->blue=gamma*(Sa*p->blue+Da*q->blue);
169   if (q->colorspace == CMYKColorspace)
170     composite->black=gamma*(Sa*p->black+Da*q->black);
171 }
172
173 static inline void CompositePixelInfoAreaBlend(const PixelInfo *p,
174   const double alpha,const PixelInfo *q,const double beta,
175   const double area,PixelInfo *composite)
176 {
177   /*
178     Blend pixel colors p and q by the amount given and area.
179   */
180   CompositePixelInfoPlus(p,(double) (1.0-area)*alpha,q,(double)
181     (area*beta),composite);
182 }
183
184 static inline void CompositePixelInfoBlend(const PixelInfo *p,
185   const double alpha,const PixelInfo *q,const double beta,
186   PixelInfo *composite)
187 {
188   /*
189     Blend pixel colors p and q by the amount given.
190   */
191   CompositePixelInfoPlus(p,(double) (alpha*p->alpha),q,(double)
192     (beta*q->alpha),composite);
193 }
194
195 #if defined(__cplusplus) || defined(c_plusplus)
196 }
197 #endif
198
199 #endif