在 DC 中正确显示 s 32 位透明 PNG 文件
Correctly displaying s 32 bit transparent PNG file in a DC
这是我将透明 PNG 文件加载到缓冲区的方法:
/* static */ void CRibbonButton::LoadImageFromRelativeFilespec(HGLOBAL& rhDIB, bool bLarge,
const CString& rstrImageRelFilespec, UINT32& ruDIBW, int& ruDIBH)
{
USES_CONVERSION;
using namespace RibbonBar ;
// Clear any existing image away.
if (rhDIB != NULL)
::GlobalFree(rhDIB);
// Build the correct filespec.
CString strThisEXE = _T("");
::GetModuleFileName(AfxGetInstanceHandle(),
strThisEXE.GetBuffer(_MAX_PATH + 1),_MAX_PATH);
strThisEXE.ReleaseBuffer();
LPCTSTR lpszPath = (LPCTSTR)strThisEXE ;
LPTSTR lpszFilename = ::PathFindFileName(lpszPath);
CString strPath = strThisEXE.Left( (int)(lpszFilename - lpszPath) );
CString strFilespec = strPath ;
::PathAppend(strFilespec.GetBuffer(_MAX_PATH + 1), rstrImageRelFilespec);
strFilespec.ReleaseBuffer();
HISSRC hSrc = is6_OpenFileSource(CT2A((LPCTSTR)strFilespec));
if (hSrc)
{
// read it
UINT32 w, h;
rhDIB = is6_ReadImage(hSrc, &w, &h, 2, 0); // the "2" = load directly to DIB, in the lowest bit depth possible.
if (rhDIB)
{
// get the dimensions
is6_DIBWidth((BITMAPINFOHEADER *)rhDIB, &ruDIBW);
is6_DIBHeight((BITMAPINFOHEADER *)rhDIB, &ruDIBH);
UINT32 bc;
is6_DIBBitCount((BITMAPINFOHEADER *)rhDIB, &bc);
is6_ClearJPGInputMarkers();
}
else
{
AfxMessageBox(_T("Can't read that image"));
}
is6_CloseSource(hSrc);
}
}
这是渲染代码:
/* virtual */ void CRibbonButton::PaintData(CDC& rDC)
{
CDC dcMem ;
dcMem.CreateCompatibleDC(NULL); // Screen.
const CRect& rrctImage = GetImageBounds();
if (m_hDIB)
{
// draw to a memory DC
CDC memDC;
if (memDC.CreateCompatibleDC(&rDC))
{
CBitmap bmp;
if (bmp.CreateCompatibleBitmap(&rDC, rrctImage.Width(), rrctImage.Height()))
{
CBitmap *ob = memDC.SelectObject(&bmp);
if (ob)
{
// dark red background
memDC.FillSolidRect(CRect(rrctImage.left, rrctImage.top, rrctImage.Width(), rrctImage.Height()), RibbonBar::kBackColour);
// stretchDrawDIB is typically the fastest way to draw an image from ImgSource.
BOOL ok = is6_StretchDrawDIB(memDC.m_hDC, (BITMAPINFOHEADER *)m_hDIB, 0, 0, m_uDIBW, m_uDIBH);
if (!ok)
{
memDC.SetBkMode(TRANSPARENT);
memDC.SetTextColor(RGB(255, 255, 255));
memDC.TextOut(rrctImage.left, rrctImage.top, _T("X"));
}
// copy this to the window
rDC.BitBlt(rrctImage.left, rrctImage.top, rrctImage.Width(), rrctImage.Height(), &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(ob);
}
}
}
}
dcMem.DeleteDC();
}
没有正确绘制透明PNG文件。我总是以黑色背景结束。
我正在使用 ISSource 库进行渲染。但该公司现在倒闭了。我正在使用版本 6 库。
更新
根据答案我现在加载和渲染图像是这样的:
CRect rct;
CImage img;
img.Load(_T("d:\Publishers.png"));
rct.SetRect(rrctImage.left, rrctImage.top, rrctImage.left + img.GetWidth(), rrctImage.top + img.GetHeight());
img.TransparentBlt(rDC.GetSafeHdc(), rct, RGB(255,255,255));
但是为什么设置透明度的地方还是变黑了?
如果我不传递 RGB(255,255,255)
作为最后一个参数
并使用默认值我得到一个异常。
更新
根据 TransparentBit
的文档:
TransparentBlt
is supported for source bitmaps of 4 bits per pixel and 8 bits per pixel. Use CImage::AlphaBlend
to specify 32 bits-per-pixel bitmaps with transparency.
所以,我已经停止使用:
img.TransparentBlt(rDC.GetSafeHdc(), rct);
现在我正在使用:
img.AlphaBlend(rDC.GetSafeHdc(), rct.left, rct.top, rct.Width(), rct.Height(), rct.left, rct.top, rct.Width(), rct.Height(), 0xff, AC_SRC_OVER);
我什么也没看到。我确认坐标是正确的:
CBrush br;
br.CreateStockObject(BLACK_BRUSH);
rDC.FrameRect(rct, &br);
为什么我什么都没看到?
这很复杂。 CImage中已有方法。
查看 CImage::AlphaBlend or CImage::TransparentBlt。
AlphaBlend:Dst 字段是您 DC 中的坐标。 Src 值在您的图片内。通常它们以 0,0 开头,并以宽度和高度作为值。 xSrc/ySrc 不是 0 你在源中有一个偏移量。
这是我将透明 PNG 文件加载到缓冲区的方法:
/* static */ void CRibbonButton::LoadImageFromRelativeFilespec(HGLOBAL& rhDIB, bool bLarge,
const CString& rstrImageRelFilespec, UINT32& ruDIBW, int& ruDIBH)
{
USES_CONVERSION;
using namespace RibbonBar ;
// Clear any existing image away.
if (rhDIB != NULL)
::GlobalFree(rhDIB);
// Build the correct filespec.
CString strThisEXE = _T("");
::GetModuleFileName(AfxGetInstanceHandle(),
strThisEXE.GetBuffer(_MAX_PATH + 1),_MAX_PATH);
strThisEXE.ReleaseBuffer();
LPCTSTR lpszPath = (LPCTSTR)strThisEXE ;
LPTSTR lpszFilename = ::PathFindFileName(lpszPath);
CString strPath = strThisEXE.Left( (int)(lpszFilename - lpszPath) );
CString strFilespec = strPath ;
::PathAppend(strFilespec.GetBuffer(_MAX_PATH + 1), rstrImageRelFilespec);
strFilespec.ReleaseBuffer();
HISSRC hSrc = is6_OpenFileSource(CT2A((LPCTSTR)strFilespec));
if (hSrc)
{
// read it
UINT32 w, h;
rhDIB = is6_ReadImage(hSrc, &w, &h, 2, 0); // the "2" = load directly to DIB, in the lowest bit depth possible.
if (rhDIB)
{
// get the dimensions
is6_DIBWidth((BITMAPINFOHEADER *)rhDIB, &ruDIBW);
is6_DIBHeight((BITMAPINFOHEADER *)rhDIB, &ruDIBH);
UINT32 bc;
is6_DIBBitCount((BITMAPINFOHEADER *)rhDIB, &bc);
is6_ClearJPGInputMarkers();
}
else
{
AfxMessageBox(_T("Can't read that image"));
}
is6_CloseSource(hSrc);
}
}
这是渲染代码:
/* virtual */ void CRibbonButton::PaintData(CDC& rDC)
{
CDC dcMem ;
dcMem.CreateCompatibleDC(NULL); // Screen.
const CRect& rrctImage = GetImageBounds();
if (m_hDIB)
{
// draw to a memory DC
CDC memDC;
if (memDC.CreateCompatibleDC(&rDC))
{
CBitmap bmp;
if (bmp.CreateCompatibleBitmap(&rDC, rrctImage.Width(), rrctImage.Height()))
{
CBitmap *ob = memDC.SelectObject(&bmp);
if (ob)
{
// dark red background
memDC.FillSolidRect(CRect(rrctImage.left, rrctImage.top, rrctImage.Width(), rrctImage.Height()), RibbonBar::kBackColour);
// stretchDrawDIB is typically the fastest way to draw an image from ImgSource.
BOOL ok = is6_StretchDrawDIB(memDC.m_hDC, (BITMAPINFOHEADER *)m_hDIB, 0, 0, m_uDIBW, m_uDIBH);
if (!ok)
{
memDC.SetBkMode(TRANSPARENT);
memDC.SetTextColor(RGB(255, 255, 255));
memDC.TextOut(rrctImage.left, rrctImage.top, _T("X"));
}
// copy this to the window
rDC.BitBlt(rrctImage.left, rrctImage.top, rrctImage.Width(), rrctImage.Height(), &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(ob);
}
}
}
}
dcMem.DeleteDC();
}
没有正确绘制透明PNG文件。我总是以黑色背景结束。
我正在使用 ISSource 库进行渲染。但该公司现在倒闭了。我正在使用版本 6 库。
更新
根据答案我现在加载和渲染图像是这样的:
CRect rct;
CImage img;
img.Load(_T("d:\Publishers.png"));
rct.SetRect(rrctImage.left, rrctImage.top, rrctImage.left + img.GetWidth(), rrctImage.top + img.GetHeight());
img.TransparentBlt(rDC.GetSafeHdc(), rct, RGB(255,255,255));
但是为什么设置透明度的地方还是变黑了?
如果我不传递 RGB(255,255,255)
作为最后一个参数
并使用默认值我得到一个异常。
更新
根据 TransparentBit
的文档:
TransparentBlt
is supported for source bitmaps of 4 bits per pixel and 8 bits per pixel. UseCImage::AlphaBlend
to specify 32 bits-per-pixel bitmaps with transparency.
所以,我已经停止使用:
img.TransparentBlt(rDC.GetSafeHdc(), rct);
现在我正在使用:
img.AlphaBlend(rDC.GetSafeHdc(), rct.left, rct.top, rct.Width(), rct.Height(), rct.left, rct.top, rct.Width(), rct.Height(), 0xff, AC_SRC_OVER);
我什么也没看到。我确认坐标是正确的:
CBrush br;
br.CreateStockObject(BLACK_BRUSH);
rDC.FrameRect(rct, &br);
为什么我什么都没看到?
这很复杂。 CImage中已有方法。
查看 CImage::AlphaBlend or CImage::TransparentBlt。
AlphaBlend:Dst 字段是您 DC 中的坐标。 Src 值在您的图片内。通常它们以 0,0 开头,并以宽度和高度作为值。 xSrc/ySrc 不是 0 你在源中有一个偏移量。