オリジナル映像編集ソフトにレイヤーモードを切り替えられる機能をつけました。
下記の15種類のレイヤーモードをとりあえず実装しました。
説明とか何も入ってないですが、どなたかのお役に立つかもしれないので、レイヤーモードごとの画像ブレンドをする関数のC++ソースコードを載せておきます。
ただし、Photoshopなどのレイヤーモードと比べると結果が異なる可能性は十分にありますのでご注意ください。
typedef float BlendCalcType;
inline BlendCalcType BlendValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return blend_value;
}
inline BlendCalcType DarkenValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return base_value < blend_value? base_value : blend_value;
}
inline BlendCalcType MultiplyValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value = blend_value/255.0f;
if( tmp_value > 1.0f)
{
tmp_value = 1.0f;
}
return base_value * tmp_value;
}
inline BlendCalcType BurnValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value;
if (blend_value == 0) tmp_value = 0;
else tmp_value = 255 - ((255 - base_value) * 255 / blend_value);
return (tmp_value < 0)? 0 : tmp_value;
}
inline BlendCalcType LightenValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return base_value > blend_value? base_value : blend_value;
}
inline BlendCalcType AddValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value = base_value + blend_value;
if( tmp_value > 255.0 )
{
tmp_value = 255.0;
}
return tmp_value;
}
inline BlendCalcType ScreenValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return 255 - ((255 - base_value) * (255 - blend_value)) / 255;
}
inline BlendCalcType DodgeValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value;
if (blend_value == 255){ tmp_value = 255; }
else{ tmp_value = base_value * 255 / (255 - blend_value); }
return (tmp_value > 255)? 255 : tmp_value;
}
inline BlendCalcType OverlayValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value;
if (base_value < 128){ tmp_value = base_value * blend_value * 2 / 255; }
else{ tmp_value = 2 * (base_value + blend_value - base_value * blend_value / 255) - 255; }
return (tmp_value > 255)? 255 : tmp_value;
}
inline BlendCalcType SoftLightValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return blend_value < 128?
(pow((base_value / 255), ((255 - blend_value)) / 128)) * 255
: pow((base_value / 255), (128 / blend_value)) * 255;
}
inline BlendCalcType HardLightValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value;
if (blend_value < 128){ tmp_value = base_value * blend_value * 2 / 255; }
else{ tmp_value = 2 * (base_value + blend_value - base_value * blend_value / 255) - 255; }
return (tmp_value > 255)? 255: tmp_value;
}
inline BlendCalcType SubtractValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
BlendCalcType tmp_value = base_value - blend_value;
return tmp_value < 0? 0 : tmp_value;
}
inline BlendCalcType DifferenceValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return fabs(base_value - blend_value);
}
inline BlendCalcType DivideValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
if( blend_value==0 ){ return 255; }
BlendCalcType tmp_value = base_value * 255 / blend_value;
return tmp_value>255? 255: tmp_value;
}
inline BlendCalcType ExclusionValue(
BlendCalcType base_value, BlendCalcType blend_value
)
{
return base_value + blend_value - 2 * base_value * blend_value / 255;
}
template<typename _Type>
void BlendMain(
_Type *io_base_img,
const _Type *in_overlay_img,
const u8 *in_alpha_data,
u32 width_step, u32 height, u32 num_channels,
BlendCalcType (*BlendFunc) ( BlendCalcType, BlendCalcType )
)
{
float transmittance;
const _Type *blend_ptr = in_overlay_img;
const u8 *alpha_ptr = in_alpha_data;
_Type *dst_ptr = io_base_img;
_Type *dst_end_ptr = dst_ptr + width_step * height;
_Type *c_ep;
double tmp_value;
for( ; dst_ptr!=dst_end_ptr; ++alpha_ptr )
{
transmittance = (*alpha_ptr)/255.0f;
for( c_ep = dst_ptr + num_channels; dst_ptr!=c_ep; ++dst_ptr, ++blend_ptr)
{
*dst_ptr = *dst_ptr * (1.0f-transmittance) +
(_Type)BlendFunc( (BlendCalcType)*dst_ptr, (BlendCalcType)*blend_ptr ) * transmittance;
}
}
}