1 /*
2   Copyright 1999-2021 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.  You may
6   obtain a copy of the License at
7 
8     https://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 
22 #include "MagickCore/color.h"
23 #include "MagickCore/image.h"
24 #include "MagickCore/image-private.h"
25 #include "MagickCore/pixel-accessor.h"
26 
27 #if defined(__cplusplus) || defined(c_plusplus)
28 extern "C" {
29 #endif
30 
31 /*
32   ImageMagick Alpha Composite Inline Methods (special export)
33 */
MagickOver_(const double p,const double alpha,const double q,const double beta)34 static inline double MagickOver_(const double p,const double alpha,
35   const double q,const double beta)
36 {
37   double
38     Da,
39     Sa;
40 
41   Sa=QuantumScale*alpha;
42   Da=QuantumScale*beta;
43   return(Sa*p+Da*q*(1.0-Sa));
44 }
45 
RoundToUnity(const double value)46 static inline double RoundToUnity(const double value)
47 {
48   return(value < 0.0 ? 0.0 : (value > 1.0) ? 1.0 : value);
49 }
50 
CompositePixelOver(const Image * image,const PixelInfo * p,const double alpha,const Quantum * q,const double beta,Quantum * composite)51 static inline void CompositePixelOver(const Image *image,const PixelInfo *p,
52   const double alpha,const Quantum *q,const double beta,Quantum *composite)
53 {
54   double
55     Da,
56     gamma,
57     Sa;
58 
59   ssize_t
60     i;
61 
62   /*
63     Compose pixel p over pixel q with the given alpha.
64   */
65   Sa=QuantumScale*alpha;
66   Da=QuantumScale*beta;
67   gamma=Sa+Da-Sa*Da;
68   gamma=PerceptibleReciprocal(gamma);
69   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
70   {
71     PixelChannel
72       channel;
73 
74     PixelTrait
75       traits;
76 
77     channel=GetPixelChannelChannel(image,i);
78     traits=GetPixelChannelTraits(image,channel);
79     if (traits == UndefinedPixelTrait)
80       continue;
81     switch (channel)
82     {
83       case RedPixelChannel:
84       {
85         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->red,alpha,
86           (double) q[i],beta));
87         break;
88       }
89       case GreenPixelChannel:
90       {
91         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->green,alpha,
92           (double) q[i],beta));
93         break;
94       }
95       case BluePixelChannel:
96       {
97         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->blue,alpha,
98           (double) q[i],beta));
99         break;
100       }
101       case BlackPixelChannel:
102       {
103         composite[i]=ClampToQuantum(gamma*MagickOver_((double) p->black,alpha,
104           (double) q[i],beta));
105         break;
106       }
107       case AlphaPixelChannel:
108       {
109         composite[i]=ClampToQuantum(QuantumRange*RoundToUnity(Sa+Da-Sa*Da));
110         break;
111       }
112       default:
113       {
114         composite[i]=q[i];
115         break;
116       }
117     }
118   }
119 }
120 
CompositePixelInfoOver(const PixelInfo * p,const double alpha,const PixelInfo * q,const double beta,PixelInfo * composite)121 static inline void CompositePixelInfoOver(const PixelInfo *p,const double alpha,
122   const PixelInfo *q,const double beta,PixelInfo *composite)
123 {
124   double
125     Da,
126     gamma,
127     Sa;
128 
129   /*
130     Compose pixel p over pixel q with the given opacities.
131   */
132   Sa=QuantumScale*alpha;
133   Da=QuantumScale*beta,
134   gamma=Sa+Da-Sa*Da;
135   composite->alpha=(double) QuantumRange*RoundToUnity(gamma);
136   gamma=PerceptibleReciprocal(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 
CompositePixelInfoPlus(const PixelInfo * p,const double alpha,const PixelInfo * q,const double beta,PixelInfo * composite)144 static inline void CompositePixelInfoPlus(const PixelInfo *p,
145   const double alpha,const PixelInfo *q,const double beta,PixelInfo *composite)
146 {
147   double
148     Da,
149     gamma,
150     Sa;
151 
152   /*
153     Add two pixels with the given opacities.
154   */
155   Sa=QuantumScale*alpha;
156   Da=QuantumScale*beta;
157   gamma=RoundToUnity(Sa+Da);  /* 'Plus' blending -- not 'Over' blending */
158   composite->alpha=(double) QuantumRange*RoundToUnity(gamma);
159   gamma=PerceptibleReciprocal(gamma);
160   composite->red=gamma*(Sa*p->red+Da*q->red);
161   composite->green=gamma*(Sa*p->green+Da*q->green);
162   composite->blue=gamma*(Sa*p->blue+Da*q->blue);
163   if (q->colorspace == CMYKColorspace)
164     composite->black=gamma*(Sa*p->black+Da*q->black);
165 }
166 
CompositePixelInfoAreaBlend(const PixelInfo * p,const double alpha,const PixelInfo * q,const double beta,const double area,PixelInfo * composite)167 static inline void CompositePixelInfoAreaBlend(const PixelInfo *p,
168   const double alpha,const PixelInfo *q,const double beta,const double area,
169   PixelInfo *composite)
170 {
171   /*
172     Blend pixel colors p and q by the amount given and area.
173   */
174   CompositePixelInfoPlus(p,(double) (1.0-area)*alpha,q,(double) (area*beta),
175     composite);
176 }
177 
CompositePixelInfoBlend(const PixelInfo * p,const double alpha,const PixelInfo * q,const double beta,PixelInfo * composite)178 static inline void CompositePixelInfoBlend(const PixelInfo *p,
179   const double alpha,const PixelInfo *q,const double beta,PixelInfo *composite)
180 {
181   /*
182     Blend pixel colors p and q by the amount given.
183   */
184   CompositePixelInfoPlus(p,(double) (alpha*p->alpha),q,(double) (beta*q->alpha),
185     composite);
186 }
187 
GetCompositeClipToSelf(const CompositeOperator compose)188 static inline MagickBooleanType GetCompositeClipToSelf(
189   const CompositeOperator compose)
190 {
191   switch (compose)
192   {
193     case ClearCompositeOp:
194     case SrcCompositeOp:
195     case InCompositeOp:
196     case SrcInCompositeOp:
197     case OutCompositeOp:
198     case SrcOutCompositeOp:
199     case DstInCompositeOp:
200     case DstAtopCompositeOp:
201     case CopyAlphaCompositeOp:
202     case ChangeMaskCompositeOp:
203     {
204       return(MagickFalse);
205       break;
206     }
207     default:
208       break;
209   }
210   return(MagickTrue);
211 }
212 
213 #if defined(__cplusplus) || defined(c_plusplus)
214 }
215 #endif
216 
217 #endif
218