writing Bitmap within a c++ console application - c++

i am trying to create a bitmap in mfc dll and i am writting
CDC *pDC = GetDC();
CDC memDC ;
memDC.CreateCompatibleDC(pDC);
CBitmap newbmp;
newbmp.CreateCompatibleBitmap(pDC, 300, 300);
ReleaseDC(pDC);
CBitmap *pOldBitmap = memDC.SelectObject(&newbmp);
memDC.FillSolidRect(0,0,300,300,RGB(255,255,255));
CBrush brush;
CBrush *pOldBrush = memDC.SelectObject(&brush);
memDC.Rectangle(10, 10, 80, 80);
memDC.Ellipse(60,60,220,220);
memDC.SelectObject(pOldBrush);
memDC.SelectObject(pOldBitmap);
CImage img;
img.Attach((HBITMAP)newbmp.Detach());
img.Save(_T("C:\\atest.bmp"),Gdiplus::ImageFormatBMP);
although this works properly in a Cwindows application i cannot make it works in a console application how can i get a Device conext in a console application ?
i cannot get getDC to work

Before you call GetDC(),you must have a handle or point of CWnd.But in a console application, you can't call this.

This works for me:
CDC *pDC;
pDC = CDC::FromHandle(::GetDC(NULL));
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap newbmp;
newbmp.CreateCompatibleBitmap(pDC, 300, 300);
CBitmap *pOldBitmap = memDC.SelectObject(&newbmp);
memDC.FillSolidRect(0,0,300,300,RGB(255,255,255));
CBrush brush;
CBrush *pOldBrush = memDC.SelectObject(&brush);
memDC.Rectangle(10, 10, 80, 80);
memDC.Ellipse(60,60,220,220);
memDC.SelectObject(pOldBrush);
memDC.SelectObject(pOldBitmap);
CImage img;
img.Attach((HBITMAP)newbmp.Detach());
img.Save(_T("C:\\atest.bmp"),Gdiplus::ImageFormatBMP);
::ReleaseDC( NULL,
*pDC);
::ReleaseDC( NULL,
memDC);
Of course to use CDC and CBitmap you need to use MFC as a shared DLL and add some headers to the stdafx.h:
#include <afxwin.h>
#include <atlimage.h>
Hope it helps,
Javier

Related

How to get a 32bpp bitmap/image from a GDI Device Context?

I am using code from this Project http://www.codeproject.com/Articles/9064/Yet-Another-Transparent-Static-Control in order to draw transparent button images from my subclassed Button control onto my CDialogEx.
This code is meant for legacy 24bpp GDI functions:
BOOL CTransparentStatic2::OnEraseBkgnd(CDC* pDC)
{
if (m_Bmp.GetSafeHandle() == NULL)
{
CRect Rect;
GetWindowRect(&Rect);
CWnd *pParent = GetParent();
ASSERT(pParent);
pParent->ScreenToClient(&Rect); //convert our corrdinates to our parents
//copy what's on the parents at this point
CDC *pDC = pParent->GetDC();
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
m_Bmp.CreateCompatibleBitmap(pDC,Rect.Width(),Rect.Height());
CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);
MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),pDC,Rect.left,Rect.top,SRCCOPY);
MemDC.SelectObject(pOldBmp);
pParent->ReleaseDC(pDC);
}
else //copy what we copied off the parent the first time back onto the parent
{
CRect Rect;
GetClientRect(Rect);
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);
pDC->BitBlt(0,0,Rect.Width(),Rect.Height(),&MemDC,0,0,SRCCOPY);
MemDC.SelectObject(pOldBmp);
}
return TRUE;
}
However the background of my CDialogEx is being drawn with GDI+ 32bpp rendering like this:
BOOL CParentDialogEx::OnEraseBkgnd(CDC* pDC)
{
// Get GDI+ Graphics for the current Device Context
Graphics gr(*pDC);
// Get the client area
CRect clientRect;
GetClientRect(&clientRect);
// Draw the dialog background
// PLEASE NOTE: m_imgDlgBkgnd is a Gdiplus::Image with PNG format ==> 32bpp Image
gr.DrawImage(m_imgDlgBkgnd, 0, 0, clientRect.Width(), clientRect.Height());
}
This causes the first code snippet to make a backup of a black rectangle instead of the 32bpp drawn content to it. This again causes my button control to always have a black background.
To make my problem clear, please see the pictures below:
Button images are being drawn onto the CDialogEx background (normally):
Button images are being drawn with the first code snippet
As you can see GDI 24bpp cannot see the dialog background. It just assumes plain black background. Only GDI+ could see it. However I was not able to find a way to get a bitmap from a Gdiplus::Graphics object.
How can I get a 32bpp background backup in order to draw my transparent images correctly?
Using no backup images at all causes the alpha blending of GDI+ to blur the background more and more on every draw.
After 3 days of figuring around I found something by testing. This can actually be done way easier and with 32bpp rendering!
// Get the client area on the parent
CRect Rect;
GetWindowRect(&Rect);
CWnd *pParent = GetParent();
ASSERT(pParent);
pParent->ScreenToClient(&Rect);
// Get the Parent's DC
CDC *parentDC = pParent->GetDC();
// GDI Code (only 24bpp support)
//CDC MemDC;
//CBitmap bmp;
//MemDC.CreateCompatibleDC(parentDC);
//bmp.CreateCompatibleBitmap(parentDC,Rect.Width(),Rect.Height());
//CBitmap *pOldBmp = MemDC.SelectObject(&bmp);
//MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),parentDC,Rect.left,Rect.top,SRCCOPY);
//MemDC.SelectObject(pOldBmp);
// GDI+ Code with 32 bpp support (here comes the important change)
Bitmap* bmp = new Bitmap(Rect.Width(), Rect.Height());
Graphics bmpGraphics(bmp);
HDC hBmpDC = bmpGraphics.GetHDC();
BitBlt(hBmpDC, 0, 0, Rect.Width(), Rect.Height(), parentDC->GetSafeHdc(), Rect.left, Rect.top, SRCCOPY); // BitBlt is actually capable of doing 32bpp blts
// Release DCs
bmpGraphics.ReleaseDC(hBmpDC);
pParent->ReleaseDC(parentDC);
Here you go! 4 lines of code and you get a 32bpp Gdiplus::Bitmap! Which you can draw later on in OnEraseBkgnd:
// Get client Area
CRect rect;
GetClientRect(&rect);
// Draw copied background back onto the parent
Graphics gr(*pDC);
gr.DrawImage(bmp, 0, 0, rect.Width(), rect.Height());
Please note that the Bitmap should be a member variable for performance increase. It also has to be freed on the controls destruction.
Instead of Gdiplus::Image, use Gdiplus::Bitmap which has GetHBITMAP
In this example the background is set to red for png image with transparent background:
Gdiplus::Bitmap gdi_bitmap(L"c:\\test\\filename.png");
HBITMAP hbitmap = NULL;
gdi_bitmap.GetHBITMAP(Gdiplus::Color(128, 0, 0), &hbitmap);
CBitmap bmp;
bmp.Attach(hbitmap);
CDC memdc;
memdc.CreateCompatibleDC(pDC);
memdc.SelectObject(&bmp);
pDC->StretchBlt(0, 0, clientRect.Width(), clientRect.Height(), &memdc, 0, 0,
gdi_bitmap.GetWidth(), gdi_bitmap.GetHeight(), SRCCOPY);
Alternatively, you can use a brush to handle the painting:
CBrush m_Brush;
BOOL CMyDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
Gdiplus::Bitmap bitmap(L"c:\\test\\filename.png");
HBITMAP hbitmap = NULL;
bitmap.GetHBITMAP(Gdiplus::Color(128, 0, 0), &hbitmap);
CBitmap bmp;
bmp.Attach(hbitmap);
m_Brush.CreatePatternBrush(&bmp);
return 1;
}
HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor)
{
//uncomment these two lines if you only want to change dialog background
//if (wnd != this)
// return CDialogEx::OnCtlColor(pDC, wnd, nCtlColor);
if (nCtlColor == CTLCOLOR_STATIC)
{
pDC->SetTextColor(RGB(0, 128, 128));
pDC->SetBkMode(TRANSPARENT);
}
CPoint pt(0, 0);
if (wnd != this)
MapWindowPoints(wnd, &pt, 1);
pDC->SetBrushOrg(pt);
return m_Brush;
}
BOOL CMyDialog::OnEraseBkgnd(CDC* pDC)
{//don't do anything
return CDialogEx::OnEraseBkgnd(pDC);
}

MFC: How to copy bitmap using OLE clipboard

Now I have a CImage img, and I wanted to copy the bitmap to the OLE clipboard.
What I did is the following
HBITMAP hImage = img.Detach();
CBitmap *pBitmap = CBitmap::FromHandle(hImage);
BITMAP bm;
pBitmap->GetObject(sizeof(bm), &bm);
HBITMAP hImage = Detach();
// the bitmap src
CBitmap *pBitmap = CBitmap::FromHandle(hImage);
BITMAP bm;
pBitmap->GetObject(sizeof(bm), &bm);
// the copy (dest)
CBitmap bitmap;
bitmap.CreateBitmapIndirect(&bm);
// create mem dc and select src and dest bitmaps
CDC dcMemSrc, dcMemDest;
dcMemSrc.CreateCompatibleDC(NULL);
CBitmap* pOldBitmapSrc = dcMemSrc.SelectObject(pBitmap);
dcMemDest.CreateCompatibleDC(NULL);
CBitmap* pOldBitmapDest = dcMemDest.SelectObject(&bitmap);
// bit-blt
dcMemDest.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcMemSrc,
0, 0, SRCCOPY);
HBITMAP hBitmap = (HBITMAP)bitmap.Detach();
// restore mem dc
dcMemDest.SelectObject(pOldBitmapDest);
dcMemSrc.SelectObject(pOldBitmapSrc);
// Place the copy on the clipboard.
AfxOleInit();
CoInitialize(NULL);
COleDataSource* pods = new COleDataSource;
pods->CacheGlobalData(CF_BITMAP, hBitmap);
pods->SetClipboard();
CoUninitialize();
I tested the program, it just doesn't work, I tried to CTRL+V to the Windows Paint program, but it complained the data cannot be pasted in it. If I use the Legacy Clipboard(just replace the last 6 lines with ::OpenClipboard(hWnd), ::EmptyClipboard(), ::SetClipboardData(CF_BITMAP, hBitmap), ::CloseClipboard() ), it works fine. I have no experience working with COM and OLE, can anyone help? Many thanks.

Screen capture only returns a black image

I'm trying to take a screen capture of the main dialog in my MFC application and save it as an image file. I tried about every example I could find online and always end up with the same result: the image file has the correct dimensions (I tried this with dialogs other than the main one just to be sure), but it is all black. My most recent solution is using the CBitmap class to transfer the main dialog handle to a CImage. Here is my code:
CWnd* mainWindow;
CDC* mainWindowDC;
CBitmap bitmapToSave;
CImage imageToSave;
CRect windowRect;
//Get main window context and create bitmap from it
mainWindow = AfxGetMainWnd();
mainWindowDC = mainWindow->GetWindowDC();
mainWindow->GetWindowRect(&windowRect);
bitmapToSave.CreateCompatibleBitmap(mainWindowDC, windowRect.Width(), windowRect.Height());
imageToSave.Attach(bitmapToSave);
imageToSave.Save("C:\\Capture\\image.bmp", Gdiplus::ImageFormatBMP);
Here is the way to do it:
HRESULT CaptureScreen(const CString& sImageFilePath)
{
CWnd* pMainWnd = AfxGetMainWnd();
CRect rc;
pMainWnd->GetWindowRect(rc);
CImage img;
img.Create(rc.Width(), rc.Height(), 24);
CDC memdc;
CDC* pDC = pMainWnd->GetWindowDC();
memdc.CreateCompatibleDC(pDC);
CBitmap* pOldBitmap = memdc.SelectObject(CBitmap::FromHandle((HBITMAP)img));
memdc.BitBlt(0, 0, rc.Width(), rc.Height(), pDC, 0, 0, SRCCOPY);
memdc.SelectObject(pOldBitmap);
return img.Save(sImageFilePath, Gdiplus::ImageFormatPNG);
}
Please also take a look at this nice implementation: http://www.codeguru.com/cpp/article.php/c18347/C-Programming-Easy-Screen-Capture-Using-MFCATL.htm
You created the bitmap, but you didn't put anything into it. You need to blit from one DC to another to make a copy of what's on the screen.
// ...
CMemDC dcMem;
dcMem.CreateCompatibleDC(&mainWindowDC);
CBitmap * pOld = dcMem.SelectObject(&bitmapToSave);
dcMem.BitBlt(0, 0, windowRect.Width(), windowRect.Height(), &mainWindowDC, windowRect.left, windowRect.top, SRCCOPY);
dcMem.SelectObject(pOld);
// ...

Displaying multiple bitmaps in MFC

I'm trying to display two bitmaps of the same image in the view at different location as shown below, but it's showing only the first one. If I comment out the first one then the other one is displayed.
void CChildView::OnPaint()
{
// Load the bitmap
CBitmap BmpLady;
// Load the bitmap from the resource
BmpLady.LoadBitmap(IDB_MB);
CPaintDC dc(this); // device context for painting
// Create a memory device compatible with the above CPaintDC variable
CDC MemDCLady;
MemDCLady.CreateCompatibleDC(&dc);
// Select the new bitmap
CBitmap *BmpPrevious = MemDCLady.SelectObject(&BmpLady);
// Copy the bits from the memory DC into the current dc
dc.BitBlt(20, 10, 436, 364, &MemDCLady, 0, 0, SRCCOPY);
// Restore the old bitmap
dc.SelectObject(BmpPrevious);
// Draw another bitmap for same image.
CPaintDC dc1(this);
CDC MemDCLady1;
MemDCLady1.CreateCompatibleDC(&dc1);
CBitmap *BmpPrevious1 = MemDCLady1.SelectObject(&BmpLady);
dc1.BitBlt(200, 100, 436, 364, &MemDCLady1, 0, 0, SRCCOPY);
dc1.SelectObject(BmpPrevious1);
}
How to display both the images simultaneously? Please help. Thanks in advance.
P.S: I'm fairly new to MFC.
There is no need to CreateCompatibleDC again for the second bitmap. With the following changes I'm able to display both the bitmaps simultaneously
void CChildView::OnPaint()
{
CBitmap BmpLady;
// Load the bitmap from the resource
BmpLady.LoadBitmap(IDB_MB);
CPaintDC dc(this);
CDC MemDCLady;
// Create a memory device compatible with the above CPaintDC variable
MemDCLady.CreateCompatibleDC(&dc);
// Select the new bitmap
//CBitmap *BmpPrevious = MemDCLady.SelectObject(&BmpLady);
MemDCLady.SelectObject(&BmpLady);
// Copy the bits from the memory DC into the current dc
dc.BitBlt(20, 10, 436, 364, &MemDCLady, 0, 0, SRCCOPY);
// MemDCLady.SelectObject(&BmpLady);
// Copy the bits from the memory DC into the current dc
dc.BitBlt(200, 100, 436, 364, &MemDCLady, 0, 0, SRCCOPY);
}

how to load image from file using MFC

My browse button code is
void CFileOpenDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CFileDialog dlg(TRUE);
int result=dlg.DoModal();
if(result==IDOK)
{
path=dlg.GetPathName();
UpdateData(FALSE);
}
}
and this is the code for loading an image from resource but that does not work for loading an image from file. i know LoadImage(); is used for this but how? how can i edit this code to load image from file. Plzz help.....
void CFileOpenDlg::OnBnClickedButton2()
{
// TODO: Add your control notification handler code here
CRect r;
CBitmap* m_bitmap;
CDC dc, *pDC;
BITMAP bmp;
m_bitmap = new CBitmap();
m_bitmap->LoadBitmapW(IDB_BITMAP1);
m_bitmap->GetBitmap(&bmp);
pDC = this->GetDC();
dc.CreateCompatibleDC(pDC);
dc.SelectObject(m_bitmap);
pDC->BitBlt(200, 200, bmp.bmWidth, bmp.bmHeight, &dc,0 , 0, SRCCOPY);
m_bitmap->DeleteObject();
m_bitmap->Detach();
}
MSDN LoadImage
HANDLE hBitMap = ::LoadImage(0, "c:\\mybmp.bmp",IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
CBitmap bmp;
bmp.Attach((HBITMAP)hBitMap);
If you want to open .JPG, .PNG ... eventually you can use CImage (is a shared class between MFC and ATL)
CImage image;
image.Load ( "picture.jpg" );
image.Draw ( pDC , 200, 200 );