Click here to Skip to main content
15,887,596 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
C++11. Not .net. Not VC++.

I can create a region with the following and pick parts of it to use as a custom shaped region for a DIALOG.

I am using a large graphic bmp that takes the following a long time to convert to a custom shaped region that I use for a custom shaped DIALOG.

My question is for the following

C++
void createSomeRegion(HWND hwndDlg) // This handle is of the DialogBox.
    {
        //Get the destination device context
        hdcDestDC = GetDC(hwndDlg);

        //Create a memory DC
        hdcMem_001 = CreateCompatibleDC(nullptr);

//        //To Load from resource.rc as a DIB Device Independent Bitmap
//            HANDLE hBitmap__001 = LoadImage (GetModuleHandle(nullptr), MAKEINTRESOURCE( IDB_TestMasked02), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
//
//            if(hBitmap__001 == NULL)
//                {
//                    MessageBox(hwndDlg, L"Could not load BITMAP from resource!", L"Error", MB_OK | MB_ICONEXCLAMATION);
//                }

        //To Load from a file.
            // HANDLE hBitmap__001 = (HBITMAP)LoadImage(GetModuleHandle(nullptr), L"a.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
            //if(!hBitmap__001)
            //    {
            //        //handle error here
            //        return;
            //    }

        //Get information about the bitmap..
        GetObject(hBitmap__001, sizeof(bmpInfo_001), &bmpInfo_001);	// Get info about the bitmap

        //Select the bitmap into the dc
        SelectObject(hdcMem_001, hBitmap__001);

        //Create an empty region
        hRgn_001 = CreateRectRgn(0,0,0,0);

        //Create a region from a bitmap with transparency color of white
        //change the pixel values for a different transparency color
        //ex - RGB(0,0,0) will mean a transparency color of black.. so the areas
        //of the bitmap not used to create the window will be black

        COLORREF crTransparent = RGB(255, 255, 255);  // To be transparent.

        int iX = 0;
        int iY = 0;
        int iRet = 0;

        for ( iY = 0; iY < bmpInfo_001.bmHeight; iY++)
            {
                do
                    {
                        //skip over transparent pixels at start of lines.
                        while (iX < bmpInfo_001.bmWidth && GetPixel(hdcMem_001, iX, iY) == crTransparent)
                            {
                                iX++;
                            }

                        //remember this pixel
                        int iLeftX = iX;

                        //now find first non transparent pixel
                        while (iX < bmpInfo_001.bmWidth   && GetPixel(hdcMem_001, iX, iY) != crTransparent)
                            {
                                ++iX;
                            }

                        //create a temp region on this info
                        HRGN hRgnTemp = CreateRectRgn(iLeftX, iY, iX, iY+1);

                        //combine into main region.
                        //    int CombineRgn
                        //        (
                        //            HRGN hrgnDst,     // A handle to a new region with dimensions defined by combining two other regions. (This region must exist before CombineRgn is called.)
                        //            HRGN hrgnSrc1,    // A handle to the first of two regions to be combined.
                        //            HRGN hrgnSrc2,    // A handle to the second of two regions to be combined.
                        //            int  iMode        // A mode indicating how the two regions will be combined.
                        //
                        iRet = CombineRgn(hRgn_001, hRgn_001, hRgnTemp, RGN_OR);

                        if(iRet == ERROR)
                            {
                                return;
                            }
                        //delete the temp region for next pass
                        DeleteObject(hRgnTemp);
                    }
                while(iX < bmpInfo_001.bmWidth);    // Completing a Do While loop.
                                                // This is not a "while for the next line".

                iX = 0;
            }
//////
//////        //Center it on current desktop
//////        iRet = SetWindowRgn(hwndDlg, hRgn_001, TRUE);
//////
//////        if(!iRet)
//////            {
//////                // messagebox stating that this did not work...
//////                return;
//////            }


//// Create a reusable rectangular region.
//hReusableRectangularRegion = CreateRectRgn(0,0,100,100);
//
//// Create a temporary brush for a temporary rectangular region.
//HBRUSH hBrushTmporary1 = CreateSolidBrush(RGB(255, 0, 0));

//BOOL FillRgn(
//  HDC    hdc,
//  HRGN   hrgn,
//  HBRUSH hbr
//);

//FillRgn(HDC_of_MainWindow, hReusableRectangularRegion, hBrushTmporary1);
//
//// The temporary brush is no longer needed. Delete it to free the allocated memory that it is using.
//DeleteObject(hBrushTmporary1);


///


int x = 0;
int y = 4;
//int i = OffsetRgn(hReusableRectangularRegion, (n*47)+(n),(n*47)+(n));
int i = OffsetRgn(hReusableRectangularRegion, (x*47)-x,(y*47)-y);
//int i = OffsetRgn(hReusableRectangularRegion, 0,0);


iRet = CombineRgn(hRgn_001, hRgn_001, hReusableRectangularRegion, RGN_AND);



        //Center it on current desktop
        iRet = SetWindowRgn(hwndDlg, hRgn_001, TRUE);

        if(!iRet)
            {
                // messagebox stating that this did not work...
                return;
            }


//        iX = ((GetSystemMetrics(SM_CXSCREEN)) / 2) - (bmpInfo_001.bmWidth / 2 + 50);
//        iY = ((GetSystemMetrics(SM_CYSCREEN)) / 2) - (bmpInfo_001.bmHeight / 2 + 50);

//        iRet = SetWindowPos(hwndDlg, HWND_TOPMOST, iX, iY, bmpInfo_001.bmWidth, bmpInfo_001.bmHeight, 0);
        iRet = SetWindowPos(hwndDlg, HWND_TOPMOST, 300, 300, bmpInfo_001.bmWidth, bmpInfo_001.bmHeight, 0);

        //Copy the memory dc into hdcDestDC
        paintRegion_001();

        //delete the bitmap
        DeleteObject(hBitmap__001);
    }


What I have tried:

C++11. Not .net. Not VC++.

I tried searching for a faster custom region creation but did not find that.

I tried testing the time that it takes for the large bitmap to be converted to a custom region and to be used for the modeless dialog, and it looks like about 10 to 15 seconds. That is too long.

I tried to figure out how to pre-process the custom region, but I am not clear how to do this.

I tried #void createSomeRegion(HWND hwndDlg), but that did not work.

I want to be able to process a large graphic (bmp) into a custom region, and have that already-processed region included in my final stand-alone executable, which I can use without having to go pixel by pixel when the exe runs.

I wandered through various wastelands of .net and VC++ starving for real C++ code.

Thanks for your help with C or up to C++11 answers.
Posted
Updated 7-Jul-20 17:06pm
v2
Comments
Patrice T 7-Jul-20 0:05am    
What ikind of shape do you expect for custom region ?
Rectangular? Concave ? Convex? with holes? Bubble? Starfish?

Here's another possibility : MaskBlt function (wingdi.h) - Win32 apps | Microsoft Docs[^]

That function performs raster operations with bitmaps. You could use a bitmap mask to define the region. As for graphics, it performs the operation very quickly and involves just one function call for the region, not one per pixel.

You could generate an in-memory, monochrome bitmap to use for hit testing if you wanted. A one can be in the region and a zero can be out of it.
 
Share this answer
 
Comments
PotatoSoup 9-Jul-20 10:45am    
Response to Solution 4:

Hours of trying to get that to work. I am lost in examples and I get errors like cannot convert BITMAP to HBITMAP, etc. That looks like the best option, but I feel like giving up and just using the long way of per pixel checking.

Thanks, but my compiler reassures me over and over that I am incompetetentt for that process.

I tried using the following with various adjustments:

HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
    {
        HDC hdcMem;
        HDC hdcMem2;
        HBITMAP hbmMask;
        BITMAP bm;

        GetObject(hbmColour, sizeof(BITMAP), &bm);
        hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, nullptr);

        hdcMem = CreateCompatibleDC(nullptr);
        hdcMem2 = CreateCompatibleDC(nullptr);

        SelectObject(hdcMem, hbmColour);
        SelectObject(hdcMem2, hbmMask);

        SetBkColor(hdcMem, crTransparent);

        BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

        BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT);

        DeleteDC(hdcMem);
        DeleteDC(hdcMem2);

        //MessageBox(Handle_of_MainWindow, L"Created a bitmap mask", L"Created a bitmap mask", MB_OK | MB_ICONEXCLAMATION);

        return hbmMask;
    }


I tried to replace the per pixel process with that, but no.

I tried creating a black and white two-color mask manually then loading it and using that like the following (replacing the per pixel process, but no.

//////        for ( iY = 0; iY < bmpInfo_001.bmHeight; iY++)
//////            {
//////                do
//////                    {
//////                        //skip over transparent pixels at start of lines.
//////                        while (iX < bmpInfo_001.bmWidth && GetPixel(hdcMem_001, iX, iY) == crTransparent)
//////                            {
//////                                iX++;
//////                            }
//////
//////                        //remember this pixel
//////                        int iLeftX = iX;
//////
//////                        //now find first non transparent pixel
//////                        while (iX < bmpInfo_001.bmWidth   && GetPixel(hdcMem_001, iX, iY) != crTransparent)
//////                            {
//////                                ++iX;
//////                            }
//////
//////                        //create a temp region on this info
//////                        HRGN hRgnTemp = CreateRectRgn(iLeftX, iY, iX, iY+1);
//////
//////                        //combine into main region.
//////                        //    int CombineRgn
//////                        //        (
//////                        //            HRGN hrgnDst,     // A handle to a new region with dimensions defined by combining two other regions. (This region must exist before CombineRgn is called.)
//////                        //            HRGN hrgnSrc1,    // A handle to the first of two regions to be combined.
//////                        //            HRGN hrgnSrc2,    // A handle to the second of two regions to be combined.
//////                        //            int  iMode        // A mode indicating how the two regions will be combined.
//////                        //
//////                        iRet = CombineRgn(hRgn_001, hRgn_001, hRgnTemp, RGN_OR);


                        HBITMAP hSkinMBmp = NULL;

                                                
                        iRet = CombineRgn(hRgn_001, hRgn_001, hBitmap_SOME_MASK_001, RGN_OR);

                        if(iRet == ERROR)
                            {
                                return;
                            }

//////
//////                        if(iRet == ERROR)
//////                            {
//////                                return;
//////
PotatoSoup 9-Jul-20 10:50am    
Continuing:

Help. What am I doing wrong? It seems logical to have the program create a mask or to load a pre-created mask, then use that. I am having trouble with this.

Would someone fix my code (with explaining of what they did) please?
PotatoSoup 16-Jul-20 9:06am    
I tried this with a large bitmap with many very many small transparent areas and used a pre-made mask. It was fast. I have been studying why it worked and trying to learn from that.

Thank you.
Rick York 16-Jul-20 12:33pm    
I am very glad to read that you got it to work. I am not at all an expert on this stuff. I just remembered something about this particular function. Best of luck with it.
The articel CContourBitmap - A Region Creator is a good information about regions.

If that doesnt help you need to streamline your code in the loop. The GetPixel needs somehow limited and the expensive CreateRegion and CombineRegion is called too often. A good starting point may be that if you found a transparent pixel you go on til the next nontransparent pixel is found and than create a region.

Isnt a BitBlt with transparent pixels possible?
 
Share this answer
 
Comments
PotatoSoup 7-Jul-20 19:03pm    
The referenced article says that it has a known bug: "Needs a conversion from the 24 bit color space to the 16 bit color space."

My code works well with 8 bits per pixel. I use the 256 color pattern of 8 bpp so that I can manually adjust parts of the image quickly via selecting a single color in the pattern. I appreciate the offer of help. You did not know this limiting factor and I did not anticipate it being an issue. Thank you.

I like your idea of limiting the GetPixel. I will probably work on that. I do not know if I can do it, but I like that idea.

"the expensive CreateRegion and CombineRegion" Working on that looks promising.

"Isnt a BitBlt with transparent pixels possible?" I do not know if it can be used in this process. And, alpha-blending (which I think is required) has been difficult for me, thus I gave up on it for now.

You did not give me code, but you gave me logic to apply to my code, which might be almost better. I will be considering you advice. Thank you.
 
Share this answer
 
Comments
PotatoSoup 7-Jul-20 18:51pm    
Thank you Rick York.

Your first link says on the page: "The dialog is NOT a real shaped one, i.e. the hit testing is NOT based on the shape and transparency of the dialog. This means that the areas of the dialog that are color-keyed or whose alpha value is zero will NOT let the mouse messages through." I want to be able to mouse click through the transparent areas. Therefore I might not be able to use that example. But, thank you. I am studying it now.

Thank you for the second (multiple) link. I am studying it now.

I have not found what I asked for at this time on these links, so I cannot, at this time accept this answer, other than to say thank you for the offer.
I responded to each solution with the "Have a Question or Comment?" button and neither of those responses show up. What is that button for if not to question or comment?
 
Share this answer
 
Comments
Richard MacCutchan 8-Jul-20 3:22am    
I can see both of your comments.
PotatoSoup 9-Jul-20 11:24am    
Would administration please remove Solution 3 as I now see the responses. Now that comment that I made just takes up space. Thanks.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900