This is my method for loading a transparent PNG file into a buffer:
/* 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);
}
}
And this is the rendering code:
/* 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();
}
It is not drawing the transparent PNG file correctly. I always end up with a black background.
I am using the ISSource libraries for rendering. But the company is now out of business. I am using version 6 library.
Update
Based on the answer I am now loading and rendering the image like this:
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));
But why do I still get black for where the transparency was set?
If I don't pass RGB(255,255,255) as the last parameter
and use the default I get an exception.
Update
According to the documentation for TransparentBit:
TransparentBltis supported for source bitmaps of 4 bits per pixel and 8 bits per pixel. UseCImage::AlphaBlendto specify 32 bits-per-pixel bitmaps with transparency.
So, I have stopped using:
img.TransparentBlt(rDC.GetSafeHdc(), rct);
Now I am using:
img.AlphaBlend(rDC.GetSafeHdc(), rct.left, rct.top, rct.Width(), rct.Height(), rct.left, rct.top, rct.Width(), rct.Height(), 0xff, AC_SRC_OVER);
I don't see anything. I confirm the coordinates are right by doing:
CBrush br;
br.CreateStockObject(BLACK_BRUSH);
rDC.FrameRect(rct, &br);
Why do I not see anything?
This is much to complicate. There are existing methods in CImage.
Check out CImage::AlphaBlend or CImage::TransparentBlt.
AlphaBlend: The Dst fields are the coordinates in your DC. the Src values are inside your picture. Usually they start with 0,0 and have the width and height as values. Is xSrc/ySrc are not 0 you have an offset in the source.