c++ - 带有透明图像的 wxSplashScreen
问题描述
我有以下代码用于使用 WxWidgets 显示启动画面:
wxImage::AddHandler(new wxPNGHandler);
wxBitmap splashBm;
if (splashBm.LoadFile(_T("splash.png"), wxBITMAP_TYPE_PNG)) {
wxSplashScreen scrn{splashBm,
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT,
5000, frame.get(), wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxSIMPLE_BORDER | wxSTAY_ON_TOP};
wxYield();
//Sleep for two seconds before destroying the splash screen and showing main frame
wxSleep(2);
//Now destroy the splashscreen
scrn.Destroy();
}
问题是对于具有透明背景的 PNG 图像,将显示启动窗口的背景。我在带有 XFCE 的 Linux 上。我该如何解决这个问题?
解决方案
经过一番研究,我发现可以使用该方法设置wxNonOwnedWindow
(wxSplashScreen
继承自)的形状bool wxNonOwnedWindow::SetShape(const wxRegion & region)
。并且wxFrame
(继承自wxNonOwnedWindow
和 的父级wxSplashScreen
)必须具有样式wxFRAME_SHAPED
。
SetShape
接收wxRegion
可以从位图的不透明像素构造的对象。
wxRegion::wxRegion(const wxBitmap & bmp,
const wxColour & transColour,
int tolerance = 0
)
因此,我们可以将图像中的所有透明像素设置为白色,其余的设置为黑色。然后我们构造一个wxRegion
使用wxWHITE
颜色作为透明色。为此,我做了以下功能:
// Doesn't work well for alpha compositing
wxImage alphaToBlackAndWhiteMask (wxImage img) {
// Some image types (e.g. gif) have a mask for the transparent pixels
// instead of an alpha channel.
if (!img.HasAlpha() && img.HasMask()) {
img.InitAlpha();
}
if (img.HasAlpha()) {
unsigned char *rgb = img.GetData();
unsigned char *alpha = img.GetAlpha();
for (int x = 0, y = 0; x < img.GetWidth()*img.GetHeight()*3; x+=3, y++) {
// If alpha pixel, make white. Else make black.
// An alpha value of 0 corresponds to a transparent pixel (null opacity)
// while a value of 255 means that the pixel is 100% opaque.
if (alpha[y] < 20) { // Using some threshold for almost transparent pixels.
rgb[x] = 0xff;// red
rgb[x+1] = 0xff;// green
rgb[x+2] = 0xff;// blue
} else {
rgb[x] = 0x00;// red
rgb[x+1] = 0x00;// green
rgb[x+2] = 0x00;// blue
}
}
// Remove alpha channel so that the pixels turned white will show
img.ClearAlpha();
}
return img;
}
然后,我按如下方式创建启动画面:
wxImage::AddHandler(new wxGIFHandler);
wxImage splashImg;
if (splashImg.LoadFile(_T("resources/splash.gif"), wxBITMAP_TYPE_GIF)) {
bool hasAlpha = splashImg.HasAlpha() || splashImg.HasMask();
wxRegion splashRgn;
if (hasAlpha) {
splashRgn = wxRegion(alphaToBlackAndWhiteMask(splashImg), *wxWHITE);
}
wxSplashScreen scrn{ splashImg,
wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_TIMEOUT,
5000, nullptr, -1, wxDefaultPosition, wxDefaultSize,
wxBORDER_NONE | wxSTAY_ON_TOP | (hasAlpha ? wxFRAME_SHAPED : 0x00) };
if (hasAlpha) {
scrn.SetShape(splashRgn);
}
// yield main loop so splash screen can show
wxAppConsole::Yield();
//Sleep for two seconds before destroying the splash screen and showing main frame
wxSleep(2);
}
不幸的是,这个解决方案不适用于 alpha 合成。这意味着我们不能拥有具有一定透明度但不完全透明的像素。
我确实偶然发现了这个解决方案,它允许通过将图层堆叠在框架中并在框架上使用wxWindow
'virtual bool SetTransparent (wxByte alpha)
方法(某些系统可能不支持透明窗口)来实现具有透明度的图层。但正如它所说,alpha 混合并不是真正可行的,因为拥有大量具有不同透明度的像素将需要每个 alpha 级别的帧层和内存中的图像。
如果有人知道允许 alpha 合成的更好解决方案,请告诉我。
推荐阅读
- javascript - 为什么我会收到“意外使用 'location' no-restricted-globals”?
- python - 在 Python 列表中使用一个字符串两次
- gcc - 为什么 `bool` 数据类型会使我的数据结构对 avr-gdb 不可读?
- python - 将 TriangulatePoints 与 SFM 与 Python 结合使用
- python - 如何减少我的代码的运行时间来计算 20000000 以下的所有素数的总和
- android - 为 cmake 执行外部原生构建,
- python - 为 CentOS 7 安装 python-dev|python-devel(安装 matplotlib 错误)
- .net - 当我将 Web 应用程序发布到 IIS 并将其部署到另一台设备上时,为什么会出现 System.StackOverflowException?
- wso2 - RegistryEventingServiceComponent 错误实例化注册表事件源和 CarbonServerManager WSO2 Carbon 初始化失败
- distributed-computing - 在监控主机之间分配子元素或顶级父元素