预乘透明度是什么?
预乘透明度(Premultiplied Alpha)是计算机图形中一种常用的颜色表示方式,用于处理图像和图形的透明度效果。它是一种颜色编码模型,结合了颜色值和透明度值,以提供更准确的颜色混合和合成效果。
在预乘透明度中,每个像素的颜色值(红、绿、蓝通道)都乘以一个透明度值(通常在0到1之间),然后再进行渲染。这样做的目的是在保持透明度效果的同时,避免颜色混合时产生不可预期的结果。预乘透明度可以减少图像合成和混合过程中的伽马校正计算,提高图形渲染的性能。
与预乘透明度相对的是直接透明度(Straight Alpha),在直接透明度中,颜色值和透明度值是独立的,它们分开存储并在渲染时进行合成。直接透明度更容易理解和处理,但在某些情况下,如图像合成、混合和过渡效果等,预乘透明度能够提供更好的视觉结果和效率。
总结起来,预乘透明度是一种在计算机图形中处理透明度效果的方法,通过将颜色值乘以透明度值来实现,以提供更准确和高效的颜色混合和合成。
说简单点就是透过玻璃等半透明后的物质的颜色。
直接分享代码,重点想说的就是中文注释部分
HRESULT NativeContextMenuNgPlugin::CreateHBitmapFromPNGBytes(const std::vector<uint8_t>& pngBytes, HBITMAP& hBitmap, int width, int height) {
HRESULT hr = S_OK;
IWICImagingFactory* pFactory = nullptr;
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
IWICFormatConverter* pConverter = nullptr;
IWICBitmapScaler* pScaler = nullptr;
// Create a WIC factory.
hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void**>(&pFactory)
);
// Create a decoder.
hr = pFactory->CreateDecoderFromStream(
SHCreateMemStream(pngBytes.data(), static_cast<UINT>(pngBytes.size())),
nullptr,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
// Retrieve the first frame of the image
hr = pDecoder->GetFrame(0, &pFrame);
// Create a format converter
hr = pFactory->CreateFormatConverter(&pConverter);
// Initialize a format converter.
hr = pConverter->Initialize(
pFrame,
GUID_WICPixelFormat32bppBGRA, // The target pixel format, 32-bit BGRA.
WICBitmapDitherTypeNone,
nullptr,
0.0,
WICBitmapPaletteTypeCustom
);
// Create a bitmap scaler
hr = pFactory->CreateBitmapScaler(&pScaler);
// Set the target size of the scaler
hr = pScaler->Initialize(pConverter, width, height, WICBitmapInterpolationModeLinear);
// Retrieve the scaled image data.
UINT scaledWidth = 0;
UINT scaledHeight = 0;
hr = pScaler->GetSize(&scaledWidth, &scaledHeight);
// create bitmap
HDC hdc = GetDC(nullptr);
HDC hdcMem = CreateCompatibleDC(hdc);
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = static_cast<LONG>(scaledWidth);
bmi.bmiHeader.biHeight = -static_cast<LONG>(scaledHeight);
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
void* pBits = nullptr;
HBITMAP hBitmapTemp = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS, &pBits, nullptr, 0);
ReleaseDC(nullptr, hdcMem);
ReleaseDC(nullptr, hdc);
DeleteDC(hdcMem);
if (hBitmapTemp) {
std::vector<uint8_t> tmpBits(scaledWidth * scaledHeight * 4);
hr = pScaler->CopyPixels(nullptr, scaledWidth * 4, scaledWidth * scaledHeight * 4, tmpBits.data());
if (SUCCEEDED(hr)) {
// 预乘透明度。没有它的话图标会有毛刺,这个问题困扰了我好久好久。
for (size_t i = 0; i < tmpBits.size(); i += 4) {
float alpha = tmpBits[i + 3] / 255.0f;
tmpBits[i] = static_cast<uint8_t>(tmpBits[i] * alpha); // Blue
tmpBits[i + 1] = static_cast<uint8_t>(tmpBits[i + 1] * alpha); // Green
tmpBits[i + 2] = static_cast<uint8_t>(tmpBits[i + 2] * alpha); // Red
}
memcpy(pBits, tmpBits.data(), tmpBits.size());
hBitmap = hBitmapTemp;
return S_OK;
}
}
return E_FAIL;
}