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