Add alpha blending for wxImage::Paste
Add test cases for wxImage::Paste. Closes #12458. Co-Authored-By: Rachel Mark <kramdar@gmail.com>
This commit is contained in:
committed by
Vadim Zeitlin
parent
8ae9987a29
commit
6e8da8641c
@@ -1608,7 +1608,9 @@ wxImage wxImage::Size( const wxSize& size, const wxPoint& pos,
|
||||
return image;
|
||||
}
|
||||
|
||||
void wxImage::Paste( const wxImage &image, int x, int y )
|
||||
void
|
||||
wxImage::Paste(const wxImage & image, int x, int y,
|
||||
wxImageAlphaBlendMode alphaBlend)
|
||||
{
|
||||
wxCHECK_RET( IsOk(), wxT("invalid image") );
|
||||
wxCHECK_RET( image.IsOk(), wxT("invalid image") );
|
||||
@@ -1639,15 +1641,18 @@ void wxImage::Paste( const wxImage &image, int x, int y )
|
||||
if (width < 1) return;
|
||||
if (height < 1) return;
|
||||
|
||||
bool copiedPixels = false;
|
||||
|
||||
// If we can, copy the data using memcpy() as this is the fastest way. But
|
||||
// for this the image being pasted must have "compatible" mask with this
|
||||
// one meaning that either it must not have one at all or it must use the
|
||||
// same masked colour.
|
||||
if ( !image.HasMask() ||
|
||||
// for this we must not do alpha compositing and the image being pasted
|
||||
// must have "compatible" mask with this one meaning that either it must
|
||||
// not have one at all or it must use the same masked colour.
|
||||
if (alphaBlend == wxIMAGE_ALPHA_BLEND_OVER &&
|
||||
(!image.HasMask() ||
|
||||
((HasMask() &&
|
||||
(GetMaskRed()==image.GetMaskRed()) &&
|
||||
(GetMaskGreen()==image.GetMaskGreen()) &&
|
||||
(GetMaskBlue()==image.GetMaskBlue()))) )
|
||||
(GetMaskBlue()==image.GetMaskBlue())))) )
|
||||
{
|
||||
const unsigned char* source_data = image.GetData() + 3*(xx + yy*image.GetWidth());
|
||||
int source_step = image.GetWidth()*3;
|
||||
@@ -1660,6 +1665,8 @@ void wxImage::Paste( const wxImage &image, int x, int y )
|
||||
source_data += source_step;
|
||||
target_data += target_step;
|
||||
}
|
||||
|
||||
copiedPixels = true;
|
||||
}
|
||||
|
||||
// Copy over the alpha channel from the original image
|
||||
@@ -1668,21 +1675,69 @@ void wxImage::Paste( const wxImage &image, int x, int y )
|
||||
if ( !HasAlpha() )
|
||||
InitAlpha();
|
||||
|
||||
const unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth();
|
||||
int source_step = image.GetWidth();
|
||||
const unsigned char*
|
||||
alpha_source_data = image.GetAlpha() + xx + yy * image.GetWidth();
|
||||
const int source_step = image.GetWidth();
|
||||
|
||||
unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width;
|
||||
int target_step = M_IMGDATA->m_width;
|
||||
unsigned char*
|
||||
alpha_target_data = GetAlpha() + (x + xx) + (y + yy) * M_IMGDATA->m_width;
|
||||
const int target_step = M_IMGDATA->m_width;
|
||||
|
||||
for (int j = 0; j < height; j++,
|
||||
source_data += source_step,
|
||||
target_data += target_step)
|
||||
switch (alphaBlend)
|
||||
{
|
||||
memcpy( target_data, source_data, width );
|
||||
case wxIMAGE_ALPHA_BLEND_OVER:
|
||||
{
|
||||
// Copy just the alpha values.
|
||||
for (int j = 0; j < height; j++,
|
||||
alpha_source_data += source_step,
|
||||
alpha_target_data += target_step)
|
||||
{
|
||||
memcpy(alpha_target_data, alpha_source_data, width);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wxIMAGE_ALPHA_BLEND_COMPOSE:
|
||||
{
|
||||
const unsigned char*
|
||||
source_data = image.GetData() + 3 * (xx + yy * image.GetWidth());
|
||||
|
||||
unsigned char*
|
||||
target_data = GetData() + 3 * ((x + xx) + (y + yy) * M_IMGDATA->m_width);
|
||||
|
||||
// Combine the alpha values but also apply alpha blending to
|
||||
// the pixels themselves while we copy them.
|
||||
for (int j = 0; j < height; j++,
|
||||
alpha_source_data += source_step,
|
||||
alpha_target_data += target_step,
|
||||
source_data += 3 * source_step,
|
||||
target_data += 3 * target_step)
|
||||
{
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
float source_alpha = alpha_source_data[i] / 255.0f;
|
||||
float light_left = (alpha_target_data[i] / 255.0f) * (1.0f - source_alpha);
|
||||
float result_alpha = source_alpha + light_left;
|
||||
alpha_target_data[i] = (unsigned char)((result_alpha * 255) +0.5);
|
||||
for (int c = 3 * i; c < 3 * (i + 1); c++)
|
||||
{
|
||||
target_data[c] =
|
||||
(unsigned char)(((source_data[c] * source_alpha +
|
||||
target_data[c] * light_left) /
|
||||
result_alpha) + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
copiedPixels = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!HasMask() && image.HasMask())
|
||||
// If we hadn't copied them yet we must need to take the mask of the image
|
||||
// being pasted into account.
|
||||
if (!copiedPixels)
|
||||
{
|
||||
unsigned char r = image.GetMaskRed();
|
||||
unsigned char g = image.GetMaskGreen();
|
||||
|
||||
Reference in New Issue
Block a user