compositeMethod: introduced LumaMask

Introduced CompositeMethod::LumaMask that converts the source pixels to the
grayscale (luma value) before alpha blending. Thanks to it, mask works more like
typical mask in graphics editor software.
Grayscale is calculated with  weighted method:
(0.0721*B + 0.7154*G + 0.2125*R) * A
Introduced surface->blender.lumaValue function
This commit is contained in:
Michal Maciola 2021-12-30 09:28:27 +01:00 committed by Hermet Park
parent 906679cbeb
commit 4cbeb5e3df
3 changed files with 54 additions and 6 deletions

View file

@ -145,8 +145,9 @@ enum class TVG_EXPORT CompositeMethod
{ {
None = 0, ///< No composition is applied. None = 0, ///< No composition is applied.
ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered. ClipPath, ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered.
AlphaMask, ///< The pixels of the source and the target are alpha blended. As a result, only the part of the source, which intersects with the target is visible. AlphaMask, ///< The pixels of the source and the target are alpha blended. As a result, only the part of the source, which alpha intersects with the target is visible.
InvAlphaMask ///< The pixels of the source and the complement to the target's pixels are alpha blended. As a result, only the part of the source which is not covered by the target is visible. InvAlphaMask, ///< The pixels of the source and the complement to the target's pixels are alpha blended. As a result, only the part of the source which alpha is not covered by the target is visible.
LumaMask ///< @BETA_API The source pixels are converted to the grayscale (luma value) and alpha blended with the target. As a result, only the part of the source, which intersects with the target is visible.
}; };
/** /**

View file

@ -235,6 +235,7 @@ struct SwImage
struct SwBlender struct SwBlender
{ {
uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a); uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
uint32_t (*lumaValue)(uint32_t c);
}; };
struct SwCompositor; struct SwCompositor;

View file

@ -47,6 +47,18 @@ static inline uint32_t _ialpha(uint32_t c)
} }
static inline uint32_t _abgrLumaValue(uint32_t c)
{
return ((((c&0xff)*54) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
}
static inline uint32_t _argbLumaValue(uint32_t c)
{
return ((((c&0xff)*19) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
}
static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a) static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{ {
return (a << 24 | b << 16 | g << 8 | r); return (a << 24 | b << 16 | g << 8 | r);
@ -139,7 +151,7 @@ static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t
auto w = static_cast<uint32_t>(region.max.x - region.min.x); auto w = static_cast<uint32_t>(region.max.x - region.min.x);
auto h = static_cast<uint32_t>(region.max.y - region.min.y); auto h = static_cast<uint32_t>(region.max.y - region.min.y);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h; ++y) { for (uint32_t y = 0; y < h; ++y) {
auto dst = &buffer[y * surface->stride]; auto dst = &buffer[y * surface->stride];
@ -173,6 +185,8 @@ static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color
return _rasterMaskedRect(surface, region, color, _alpha); return _rasterMaskedRect(surface, region, color, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterMaskedRect(surface, region, color, _ialpha); return _rasterMaskedRect(surface, region, color, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterMaskedRect(surface, region, color, surface->blender.lumaValue);
} }
} else { } else {
if (opacity == 255) { if (opacity == 255) {
@ -246,6 +260,8 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8
return _rasterMaskedRle(surface, rle, color, _alpha); return _rasterMaskedRle(surface, rle, color, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterMaskedRle(surface, rle, color, _ialpha); return _rasterMaskedRle(surface, rle, color, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterMaskedRle(surface, rle, color, surface->blender.lumaValue);
} }
} else { } else {
if (opacity == 255) { if (opacity == 255) {
@ -275,6 +291,8 @@ static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, c
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha); return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha); return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.lumaValue);
} }
} else { } else {
return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr); return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr);
@ -491,12 +509,16 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _alpha); return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha); return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
} }
} else { } else {
if (surface->compositor->method == CompositeMethod::AlphaMask) { if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha); return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha); return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
} }
} }
} else { } else {
@ -613,12 +635,16 @@ static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32
return _rasterDirectMaskedRleRGBAImage(surface, image, _alpha); return _rasterDirectMaskedRleRGBAImage(surface, image, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha); return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.lumaValue);
} }
} else { } else {
if (surface->compositor->method == CompositeMethod::AlphaMask) { if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _alpha); return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha); return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.lumaValue);
} }
} }
} else { } else {
@ -640,6 +666,8 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _alpha); return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _ialpha); return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, surface->blender.lumaValue);
} }
} else { } else {
return _rasterTexmapPolygon(surface, image, transform, &region, opacity, nullptr); return _rasterTexmapPolygon(surface, image, transform, &region, opacity, nullptr);
@ -826,12 +854,16 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _alpha); return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha); return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
} }
} else { } else {
if (surface->compositor->method == CompositeMethod::AlphaMask) { if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha); return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha); return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
} }
} }
} else { } else {
@ -855,7 +887,7 @@ static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* imag
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x); auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox); auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h2; ++y) { for (uint32_t y = 0; y < h2; ++y) {
auto dst = buffer; auto dst = buffer;
@ -882,7 +914,7 @@ static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
auto w2 = static_cast<uint32_t>(region.max.x - region.min.x); auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox); auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
for (uint32_t y = 0; y < h2; ++y) { for (uint32_t y = 0; y < h2; ++y) {
auto dst = buffer; auto dst = buffer;
@ -946,12 +978,16 @@ static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwB
return _rasterDirectMaskedRGBAImage(surface, image, region, _alpha); return _rasterDirectMaskedRGBAImage(surface, image, region, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha); return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.lumaValue);
} }
} else { } else {
if (surface->compositor->method == CompositeMethod::AlphaMask) { if (surface->compositor->method == CompositeMethod::AlphaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _alpha); return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha); return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.lumaValue);
} }
} }
} else { } else {
@ -1056,6 +1092,8 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
return _rasterLinearGradientMaskedRect(surface, region, fill, _alpha); return _rasterLinearGradientMaskedRect(surface, region, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha); return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
} }
} else { } else {
if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill); if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
@ -1160,6 +1198,8 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c
return _rasterLinearGradientMaskedRle(surface, rle, fill, _alpha); return _rasterLinearGradientMaskedRle(surface, rle, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha); return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
} }
} else { } else {
if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill); if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
@ -1247,6 +1287,8 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
return _rasterRadialGradientMaskedRect(surface, region, fill, _alpha); return _rasterRadialGradientMaskedRect(surface, region, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha); return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
} }
} else { } else {
if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill); if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
@ -1350,6 +1392,8 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c
return _rasterRadialGradientMaskedRle(surface, rle, fill, _alpha); return _rasterRadialGradientMaskedRle(surface, rle, fill, _alpha);
} else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha); return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha);
} else if (surface->compositor->method == CompositeMethod::LumaMask) {
return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
} }
} else { } else {
if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill); if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
@ -1379,8 +1423,10 @@ bool rasterCompositor(SwSurface* surface)
{ {
if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) { if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
surface->blender.join = _abgrJoin; surface->blender.join = _abgrJoin;
surface->blender.lumaValue = _abgrLumaValue;
} else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) { } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
surface->blender.join = _argbJoin; surface->blender.join = _argbJoin;
surface->blender.lumaValue = _argbLumaValue;
} else { } else {
//What Color Space ??? //What Color Space ???
return false; return false;
@ -1494,4 +1540,4 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co
//TODO: case: _rasterGrayscaleImage() //TODO: case: _rasterGrayscaleImage()
//TODO: case: _rasterAlphaImage() //TODO: case: _rasterAlphaImage()
return _rasterRGBAImage(surface, image, transform, bbox, opacity); return _rasterRGBAImage(surface, image, transform, bbox, opacity);
} }