How to get an file-loaded bitmap to fit a static image container using StretchBlt ?
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10

Thread: How to get an file-loaded bitmap to fit a static image container using StretchBlt ?

  1. #1
    Join Date
    May 2002
    Posts
    1,727

    How to get an file-loaded bitmap to fit a static image container using StretchBlt ?

    The code below will load a bitmap from a disk file. How can I get the loaded bitmap, regardless of it's original size, to fit into an existing interface static image container?
    Code:
    void CMyDlg::OnFileOpen()
    {
    	CString m_csPathname, m_csFilename;
    
    	const wchar_t fileDialogFilter[] = 
    	_T("Bitmap Files(*.bmp)|*.bmp||");
    	const wchar_t fileDialogExt[] = _T("bmp");
    
    	CFileDialog fileDialog(TRUE, 
    		fileDialogExt, NULL,
    		OFN_FILEMUSTEXIST, fileDialogFilter);
    
    	if (fileDialog.DoModal() == IDOK)
        {
    		CWaitCursor wait;
    
    		m_csPathname = fileDialog.GetPathName();
    		m_csFilename = fileDialog.GetFileName();
    		SetWindowText(m_csFilename);
    
    	}
    
    	CWaitCursor wait;
    
    	// Load the Image File
    	HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, m_csPathname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    
    	// The StretchBlt function copies a bitmap from a source rectangle into a destination rectangle, stretching or 
    	// compressing the bitmap to fit the dimensions of the destination rectangle, if necessary. The system stretches or 
    	// compresses the bitmap according to the stretching mode currently set in the destination device context.
    	//
    	// BOOL StretchBlt(
    	// __in  HDC hdcDest,			// A handle to the destination device context.
    	// __in  int nXOriginDest,		// The x-coordinate, in logical units, of the upper-left corner of the destination rectangle.
    	// __in  int nYOriginDest,		// The y-coordinate, in logical units, of the upper-left corner of the destination rectangle.
    	// __in  int nWidthDest,		// The width, in logical units, of the destination rectangle.
    	// __in  int nHeightDest,		// The height, in logical units, of the destination rectangle.
    	// __in  HDC hdcSrc,			// A handle to the source device context.
    	// __in  int nXOriginSrc,		// The x-coordinate, in logical units, of the upper-left corner of the source rectangle.
    	// __in  int nYOriginSrc,		// The y-coordinate, in logical units, of the upper-left corner of the source rectangle.
    	// __in  int nWidthSrc,			// The width, in logical units, of the source rectangle.
    	// __in  int nHeightSrc,		// The height, in logical units, of the source rectangle.
    	// __in  DWORD dwRop			// The raster operation to be performed. Raster operation codes define how the system combines colors in output operations that involve a brush, a source bitmap, and a destination bitmap.
    	// );
    
    
    	m_cImage.SetBitmap(hBmp);
    
    	m_csEdit1.Empty();
    	m_csEdit2.Empty();
    	m_csEdit3.Empty();
    	UpdateData(FALSE);
    
    }// OnFileOpen()
    It is my understanding that the StretchBlt(...) function pertains to the destination device context. I am unclear as to how to determine the rectangle of the bitmap that has been loaded and what the dwRop is supposed to be. I have not found a suitable example.
    mpliam

  2. #2
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,070

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    What StretchBlt does is single blitting of a source dc rect to destination dc rect along with proper image scaling up or down. It does not create a bitmap object, therefore you should take care of that yourself. Actually you have two options here:
    • subclass your static control and provide custom WM_PAINT handler that will do StretchBlt inside
    • create on the fly a "thumbnail" bitmap object (by means of StretchBlt between two memory DCs) that would fit into static control size
    Which way would you like to go?
    Best regards,
    Igor

  3. #3
    Join Date
    May 2002
    Posts
    1,727

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    create on the fly a "thumbnail" bitmap object (by means of StretchBlt between two memory DCs) that would fit into static control size
    This sounds as though it would be simplest for my current purpose. Could I impose upon you to provide some code?
    mpliam

  4. #4
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,070

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    Could I impose upon you to provide some code?
    Believe it or not but I have a rule for CG forums: I never give a ready-to-use code. And seems this is the case: I want you do it yourself.

    Besides, I do not understand where your problem is, as I already gave you all the hints. Repeating the plan with a bit more details:
    • create compatible memory context Dst (compatible with dialog dc, or static control dc which in fact is the same)
    • create compatible thumbnail bitmap of the size of your static control (compatible with the dc)
    • select the thumbnail bitmap into Dst
    • prepare thumbnail bitmap background (optional, 1) (using FillRect)
    • create compatible memory context Src (compatible with dialog/control dc)
    • select your previously loaded image bitmap into Src
    • pre-calculate Dst target rectangle (optional, 2)
    • do StrechBlt to Dst from Src
    • unselect the loaded bitmap from Src (by selecting the bitmap released by previous selection to Src)
    • unselect the thumbnail bitmap from Dst (by selecting the bitmap released by previous selection to Dst)
    • destroy Dst context (with appropriate DeleteDC method)
    • destroy Src context (with appropriate DeleteDC method)
    • set thumbnail bitmap to static control


    Optional steps (1) and (2) are needed in case when loaded bitmap aspect ratio/orientation differs from your static rectangle, and you want the image to go there undistorted. In (1) you fill the whole bitmap rect with the dialog background (or any other you prefer) color. In (2) you correct the destination rect to be of the aspect the current source image has and centered along one of the axes, vertically or horizontally.
    Last edited by Igor Vartanov; July 8th, 2012 at 07:27 AM.
    Best regards,
    Igor

  5. #5
    Join Date
    May 2002
    Posts
    1,727

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    Sounds easy. But it's not. Here's my attempt. It crashes the app apparently due to heap corruption related to byte counts. Inspection of my code will reveal that I am confused about how to create compatible device contexts (DC), what dimensions to use, how to get the dimensions of the newly loaded bitmap, how to create a thumbnail bitmap (rather than just the handle ?), how to 'deselect' an object, how to 'destroy' a DC, and just about everything else.

    Code:
    	// Load the Image File
    	HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, m_csPathname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    
    	// create a compatible memory context
    	HDC memDCdst; 
    	CDC * pDC = m_cImage.GetDC();
    	memDCdst = CreateCompatibleDC(pDC->m_hDC);
    
    	// create compatible thumbnail bitmap of the size of your static control 
    	CRect rect;
    	m_cImage.GetWindowRect(rect);
    	ScreenToClient(rect);
    	int bmpWidth = rect.Width();
    	int bmpHeight = rect.Height();
    	HBITMAP hBmpDst = CreateCompatibleBitmap(memDCdst, bmpWidth, bmpHeight);
    
    	// select the thumbnail bitmap into Dst 
    	SelectObject(memDCdst, hBmpDst);
    
    	// create compatible memory context Src 
    	HDC memDCsrc;
    	memDCsrc = CreateCompatibleDC(memDCdst);   // use the destination DC (or what ??)
    
    	// select your previously loaded image bitmap into Src 
    	SelectObject(memDCsrc, hBmp);
    
    	// pre-calculate Dst target rectangle (optional, 2) - done above
    	int xDest = rect.TopLeft().x;
    	int yDest = rect.TopLeft().y;
    	int wDest = rect.Width();
    	int hDest = rect.Height();
    	
    	// do StrechBlt to Dst from Src 
    	StretchBlt(memDCdst, xDest, yDest, wDest, hDest, memDCsrc, 0, 0, bmpWidth, bmpHeight, SRCCOPY);
    
    	// unselect the loaded bitmap from Src 
    	// The SelectObject function selects an object into the specified device context (DC). 
    	// The new object replaces the previous object of the same type.
    	SelectObject(memDCsrc, hBmpDst);
    
    	// unselect the thumbnail bitmap from Dst 
    	SelectObject(memDCdst, hBmpDst);
    
    	// destroy Dst context 
    	delete memDCdst;
    	memDCdst = NULL;
    
    	// destroy Src context 
    	delete memDCsrc;
    	memDCsrc = NULL;
    
    	// set thumbnail bitmap to static control 
    	m_cImage.SetBitmap(hBmpDst);
    mpliam

  6. #6
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,070

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    Sounds easy. But it's not.
    Yeah, no surprise, you know, as this is regular professional hazard. This is what debugger and documentation is for.

    And Mike, you definitely have to decide about the style you operate with GDI objects. Now your code is a horrible mess of MFC and plain GDI objects, and seems you're lost in the jungles. You need to take some tutorials on GDI programming. Seems you cannot afford anymore to not understand in details what your code does. Or you are to buy some commercial graphic library that would handle such primitive operations like this one for you.

    Inspection of my code will reveal that I am confused about how to create compatible device contexts (DC), what dimensions to use, how to get the dimensions of the newly loaded bitmap, how to create a thumbnail bitmap (rather than just the handle ?), how to 'deselect' an object, how to 'destroy' a DC, and just about everything else.
    Sounds like a good plan for research.
    Last edited by Igor Vartanov; July 6th, 2012 at 04:14 PM.
    Best regards,
    Igor

  7. #7
    Join Date
    May 2002
    Posts
    1,727

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    May I ask a couple of very basic questions?

    Q: When one uses a 'CreateCompatible.. DC or Bitmap function, I understand that the the device context struct of the object created will be 'compatible' with that of the HDC input parameter. But when loading a bitmap from a file, if one only has the handle (HBITMAP), what is the 'compatible' DC reference to use since the newly loaded bitmap handle has no DC initially associated with it. Since the newly loaded bitmap is to be set into the existing interface, it should presumably have a compatible DC associated with it, but that is just the DC of the interface image container, so why do I need a separate DC for it. Why not just get the interface image container DC and use that for both?

    Q: What is the precise meaning of 'compatible' in the above context? This sounds as though the newly created DC is not necessarily 'identical' with the input DC, but rather only 'compatible'. I would like a clear explanation of what is meant here by 'compatible'.

    Q: Getting the size of the newly loaded bitmap appears to be essential to using StretchBlt to fit the bitmap into the interface image container, the size of which is obviously known. As far as mixing MFC and GDI stuff, while it may not be pretty, I couldn't find any pure way to accomplish basic things like getting the size of the newly loaded bitmap. For example, the following code works:
    Code:
    	BITMAP bm;	
    	::GetObject( hBmp, sizeof( bm ), &bm );	
    	int bmWidth = bm.bmWidth;
    	int bmHeight = bm.bmHeight;
    but I could not find how to use the MFC CBitmap or CImage classes to do this. I spent alot of time hunting for code examples but none found worked for me. As a pragmatist, I feel whatever works is OK with me. But I agree with your comment in this regard. The reason is that the internet is full of code that is mostly GDI and much of which doesnt work.
    Last edited by Mike Pliam; July 7th, 2012 at 03:33 PM.
    mpliam

  8. #8
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,070

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    Quote Originally Posted by Mike Pliam View Post
    May I ask a couple of very basic questions?
    Sure.

    Q: When one uses a 'CreateCompatible.. DC or Bitmap function, I understand that the the device context struct of the object created will be 'compatible' with that of the HDC input parameter. But when loading a bitmap from a file, if one only has the handle (HBITMAP), what is the 'compatible' DC reference to use since the newly loaded bitmap handle has no DC initially associated with it. Since the newly loaded bitmap is to be set into the existing interface, it should presumably have a compatible DC associated with it, but that is just the DC of the interface image container, so why do I need a separate DC for it. Why not just get the interface image container DC and use that for both?
    One DC can select only one bitmap object (same to any other types of GDI objects like pens, brushes, fonts, etc.), and object selection releases previously selected object. Bitmap copying can be done only between two DCs that selected destination and source bitmaps each. To be able to copy/stretch a loaded bitmap you have to create a DC compatible with the target DC to select the bitmap to the DC.

    Q: What is the precise meaning of 'compatible' in the above context? This sounds as though the newly created DC is not necessarily 'identical' with the input DC, but rather only 'compatible'. I would like a clear explanation of what is meant here by 'compatible'.
    Real device can have a fixed palette. Memory context must be just compatible with the one, but this never means it should be identical to it. When copying between DCs is performed, the bitmap bits get transformed to comply with the target device capabilities. E.g. this way non-palette 24-bit RGB bitmap can be copied to grey-scale palette printer DC. This process of copying from memory DC to printer DC is called printing.

    Q: Getting the size of the newly loaded bitmap appears to be essential to using StretchBlt to fit the bitmap into the interface image container, the size of which is obviously known. As far as mixing MFC and GDI stuff, while it may not be pretty, I couldn't find any pure way to accomplish basic things like getting the size of the newly loaded bitmap. For example, the following code works:
    Code:
    	BITMAP bm;	
    	::GetObject( hBmp, sizeof( bm ), &bm );	
    	int bmWidth = bm.bmWidth;
    	int bmHeight = bm.bmHeight;
    but I could not find how to use the MFC CBitmap or CImage classes to do this. I spent alot of time hunting for code examples but none found worked for me. As a pragmatist, I feel whatever works is OK with me. But I agree with your comment in this regard. The reason is that the internet is full of code that is mostly GDI and much of which doesnt work.
    Mike, I can understand your approach of hunting for code snippets. But sometimes it's much easier to browse through documentation first.

    CBitmap::GetBitmap internally does exactly what you showed here. CImage::GetWidth and CImage::GetHeight names are self-explaining enough. Besides, even with C++ objects like MFC CBitmap and ATL CImage you can fall back to plain GDI any time you want. You just need for that to retrieve the original GDI object handle the mentioned class objects wrap:
    CBitmap:: operator HBITMAP
    CImage:: operator HBITMAP
    Best regards,
    Igor

  9. #9
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,070

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    As a pragmatist, I feel whatever works is OK with me.
    As a pragmatist I don't like to make my code by combining some pieces of a quality I'm uncertain of, that seemingly work for me now but may stop working at any time in future, which situation I won't be able to fix just because I hardly understand how the pieces really work. As a pragmatist I prefer to rework the snippets to meet my code styles and standards to be able to read the code a few months later. As a pragmatist I prefer to rework the snippets to get rid of any excessive steps the original code may have. And all the above inevitably makes me to understand what every borrowed code piece really does and how it works with my original code.

    One more thing, to accomplish this pragmatist memorandum. As a pragmatist, I never put somewhat complex piece of code right into my main project. Every time I create a 'toy' project (I call it 'monkey' ) where I check the solution and do its preliminary analysis and see how it gets along with existing documentation. BTW, quite often I have to explain to other teamers how it's gonna work, and my monkey usually serves the purpose very good. I never delete the monkey to be able to find something I did before rather fast, that's why my monkey folder has about seven hundred monkeys now.
    Best regards,
    Igor

  10. #10
    ovidiucucu's Avatar
    ovidiucucu is offline Moderator/Reviewer Power Poster
    Join Date
    Feb 2003
    Location
    Iasi - Romania
    Posts
    8,059

    Re: How to get an file-loaded bitmap to fit a static image container using StretchBlt

    Just completing what Igor already said.
    Everytime I asked a linux-fellow something like "How to draw a circle on my ceiling?" the answer was of this kind: "Google search and/or download CircleOnMyCeilingLib. It's free, it's open-source and it worked for me".
    Windows programming is pretty different: first of all, you have to think about and finally, understand what you are doing there.
    Last edited by ovidiucucu; July 8th, 2012 at 11:17 AM. Reason: typo
    Ovidiu Cucu
    "When in Rome, do as Romans do."
    Visit: Microsoft Virtual Academy
    Follow: https://twitter.com/#!/ovidiucucu
    My blog: http://codexpert.ro/blog/author/ovidiu-cucu/

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center