-
July 23rd, 2015, 08:49 AM
#1
[RESOLVED] GDI - can i speed up the DIB code?
i have these 2 functions for create regions:
Code:
BYTE* Get24BitPixels(HBITMAP pBitmap, WORD *pwWidth, WORD *pwHeight)
{
// a bitmap object just to get bitmap width and height
BITMAP bmpBmp;
// pointer to original bitmap info
LPBITMAPINFO pbmiInfo;
// bitmap info will hold the new 24bit bitmap info
BITMAPINFO bmiInfo;
// width and height of the bitmap
WORD wBmpWidth, wBmpHeight;
// ---------------------------------------------------------
// get some info from the bitmap
// ---------------------------------------------------------
GetObject(pBitmap, sizeof(bmpBmp),&bmpBmp);
pbmiInfo = (LPBITMAPINFO)&bmpBmp;
// get width and height
wBmpWidth = (WORD)pbmiInfo->bmiHeader.biWidth;
wBmpWidth -= (wBmpWidth%4); // width is 4 byte boundary aligned.
wBmpHeight = (WORD)pbmiInfo->bmiHeader.biHeight;
// copy to caller width and height parms
*pwWidth = wBmpWidth;
*pwHeight = wBmpHeight;
// ---------------------------------------------------------
// allocate width * height * 24bits pixels
//BYTE *pPixels = new BYTE[wBmpWidth*wBmpHeight*3];
BYTE *pPixels = new (std::nothrow) BYTE[wBmpWidth*wBmpHeight*3];
if (pPixels==0)
return NULL;
// get user desktop device context to get pixels from
HDC hDC = GetWindowDC(NULL);
// fill desired structure
bmiInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmiInfo.bmiHeader.biWidth = wBmpWidth;
bmiInfo.bmiHeader.biHeight = -wBmpHeight;
bmiInfo.bmiHeader.biPlanes = 1;
bmiInfo.bmiHeader.biBitCount = 24;
bmiInfo.bmiHeader.biCompression = BI_RGB;
bmiInfo.bmiHeader.biSizeImage = wBmpWidth*wBmpHeight*3;
bmiInfo.bmiHeader.biXPelsPerMeter = 0;
bmiInfo.bmiHeader.biYPelsPerMeter = 0;
bmiInfo.bmiHeader.biClrUsed = 0;
bmiInfo.bmiHeader.biClrImportant = 0;
// get pixels from the original bitmap converted to 24bits
int iRes = GetDIBits(hDC,pBitmap,0,wBmpHeight,(LPVOID)pPixels,&bmiInfo,DIB_RGB_COLORS);
// release the device context
ReleaseDC(NULL,hDC);
// if failed, cancel the operation.
if (!iRes)
{
delete[] pPixels;
return NULL;
};
// return the pixel array
return pPixels;
}
HRGN RegionbyBitmap(HBITMAP pBitmap,COLORREF clrTransparent=-1 )
{
BYTE jTranspR = GetRValue(clrTransparent), jTranspG=GetGValue(clrTransparent), jTranspB=GetBValue(clrTransparent);
// bitmap width and height
WORD wBmpWidth,wBmpHeight;
// the final region and a temporary region
HRGN hRgn, hTmpRgn;
// 24bit pixels from the bitmap
BYTE *pPixels = Get24BitPixels(pBitmap, &wBmpWidth, &wBmpHeight);
if (!pPixels) return NULL;
// create our working region
hRgn = CreateRectRgn(0,0,wBmpWidth,wBmpHeight);
if (!hRgn)
{
delete[] pPixels;
return NULL;
}
// ---------------------------------------------------------
// scan the bitmap
// ---------------------------------------------------------
DWORD p=0;
for (WORD y=0; y<wBmpHeight; y++)
{
for (WORD x=0; x<wBmpWidth; x++)
{
BYTE jRed = pPixels[p+2];
BYTE jGreen = pPixels[p+1];
BYTE jBlue = pPixels[p+0];
if ((jRed == jTranspR && jGreen == jTranspG && jBlue == jTranspB))
{
// remove transparent color from region
hTmpRgn = CreateRectRgn(x,y,x+1,y+1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
DeleteObject(hTmpRgn);
}
// next pixel
p+=3;
}
}
// release pixels
delete[] pPixels;
return hRgn;
}
they work fine. but if i have images with 100X40, it can be very slow
so imagine if the control region is 200X200.
anotherthing: whe it's very slow(i use a timer on animation), i can lose the window control messages(freezes the application).
can i speed up the DIB's code?
Last edited by Cambalinho; July 24th, 2015 at 08:39 AM.
-
July 23rd, 2015, 10:18 AM
#2
Re: GDI - can i speed up the DIB code?
Did you profile your code? Do you know which part takes most of the time? Is it Get24BitPixels() or RegionbyBitmap()?
Do you have a lot of transparent pixels in your bitmap?
I assume that most of the time is spent in the inner-most loop, where you repeatedly create and destroy a one-pixel region.
I would try to create that region once (outside of the loop) and use OffsetRgn function to move it to the current transparent point.
Next, you can try to look ahead and see if there are multiple consecutive transparent pixels in your bitmap, then you can create a bigger region and combine it once instead of for each pixel.
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
July 23rd, 2015, 02:01 PM
#3
Re: GDI - can i speed up the DIB code?
Originally Posted by VladimirF
Did you profile your code? Do you know which part takes most of the time? Is it Get24BitPixels() or RegionbyBitmap()?
Do you have a lot of transparent pixels in your bitmap?
I assume that most of the time is spent in the inner-most loop, where you repeatedly create and destroy a one-pixel region.
I would try to create that region once (outside of the loop) and use OffsetRgn function to move it to the current transparent point.
Next, you can try to look ahead and see if there are multiple consecutive transparent pixels in your bitmap, then you can create a bigger region and combine it once instead of for each pixel.
i belive the problem is on my region code:
Code:
// create our working region
hRgn = CreateRectRgn(0,0,wBmpWidth,wBmpHeight);
if (!hRgn)
{
delete[] pPixels;
return NULL;
}
// ---------------------------------------------------------
// scan the bitmap
// ---------------------------------------------------------
DWORD p=0;
for (WORD y=0; y<wBmpHeight; y++)
{
for (WORD x=0; x<wBmpWidth; x++)
{
BYTE jRed = pPixels[p+2];
BYTE jGreen = pPixels[p+1];
BYTE jBlue = pPixels[p+0];
if ((jRed == jTranspR && jGreen == jTranspG && jBlue == jTranspB))
{
// remove transparent color from region
hTmpRgn = CreateRectRgn(x,y,x+1,y+1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
DeleteObject(hTmpRgn);
}
// next pixel
p+=3;
}
}
// release pixels
delete[] pPixels;
because using the CombineRgn() in pixel way is slow. maybe with time, i can change it, but isn't easy
-
July 23rd, 2015, 03:49 PM
#4
Re: GDI - can i speed up the DIB code?
Originally Posted by Cambalinho
maybe with time, i can change it, but isn't easy
Try this in place of your scanning code:
Code:
// ---------------------------------------------------------
// scan the bitmap
// ---------------------------------------------------------
DWORD p = 0;
int xStart = 0;
bool bTransp(false);
hTmpRgn = CreateRectRgn(0, 0, 1, 1);
for (WORD y = 0; y<wBmpHeight; y++)
{
for (WORD x = 0; x<wBmpWidth; x++)
{
BYTE jRed = pPixels[p + 2];
BYTE jGreen = pPixels[p + 1];
BYTE jBlue = pPixels[p + 0];
if ((jRed == jTranspR && jGreen == jTranspG && jBlue == jTranspB))
{
if (!bTransp)
{
xStart = x;
bTransp = true;
}
}
else
{
if (bTransp)
{
SetRectRgn(hTmpRgn, xStart, y, x - xStart, y + 1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
bTransp = false;
}
}
// next pixel
p += 3;
}
if (bTransp)
{
SetRectRgn(hTmpRgn, xStart, y, wBmpWidth - xStart, y + 1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
bTransp = false;
}
}
DeleteObject(hTmpRgn);
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
July 23rd, 2015, 03:55 PM
#5
Re: GDI - can i speed up the DIB code?
Originally Posted by VladimirF
Try this in place of your scanning code:
Code:
// ---------------------------------------------------------
// scan the bitmap
// ---------------------------------------------------------
DWORD p = 0;
int xStart = 0;
bool bTransp(false);
hTmpRgn = CreateRectRgn(0, 0, 1, 1);
for (WORD y = 0; y<wBmpHeight; y++)
{
for (WORD x = 0; x<wBmpWidth; x++)
{
BYTE jRed = pPixels[p + 2];
BYTE jGreen = pPixels[p + 1];
BYTE jBlue = pPixels[p + 0];
if ((jRed == jTranspR && jGreen == jTranspG && jBlue == jTranspB))
{
if (!bTransp)
{
xStart = x;
bTransp = true;
}
}
else
{
if (bTransp)
{
SetRectRgn(hTmpRgn, xStart, y, x - xStart, y + 1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
bTransp = false;
}
}
// next pixel
p += 3;
}
if (bTransp)
{
SetRectRgn(hTmpRgn, xStart, y, wBmpWidth - xStart, y + 1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
bTransp = false;
}
}
DeleteObject(hTmpRgn);
seems much more faster, but very pixels aren't transparent
see the image:
Last edited by Cambalinho; July 23rd, 2015 at 03:58 PM.
-
July 23rd, 2015, 04:08 PM
#6
Re: GDI - can i speed up the DIB code?
Originally Posted by Cambalinho
seems much more faster, but very pixels aren't transparent
see the image:
Could you please attach the original bitmap you are trying to convert?
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
July 23rd, 2015, 04:14 PM
#7
Re: GDI - can i speed up the DIB code?
heres the original transparent:
-
July 23rd, 2015, 04:32 PM
#8
Re: GDI - can i speed up the DIB code?
This is JPEG (compressed).
Do you have the original BMP image? And what color is used to convert to transparent?
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
July 23rd, 2015, 04:58 PM
#9
Re: GDI - can i speed up the DIB code?
Originally Posted by VladimirF
This is JPEG (compressed).
Do you have the original BMP image? And what color is used to convert to transparent?
that image is drawed with WM_PAINT, i draw the image and then the text. my last image was the transparent, but it's very slow. and your code don't do the transparent correctly
Last edited by Cambalinho; July 23rd, 2015 at 05:02 PM.
-
July 24th, 2015, 07:52 AM
#10
Re: GDI - can i speed up the DIB code?
Originally Posted by Cambalinho
that image is drawed with WM_PAINT, i draw the image and then the text. my last image was the transparent, but it's very slow. and your code don't do the transparent correctly
I might have missed something.
Could you please upload your zipped test project (without Debug/Release folders) here?
What bitmap do you pass to function HRGN RegionbyBitmap(HBITMAP pBitmap,COLORREF clrTransparent)? And what color?
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
July 24th, 2015, 08:19 AM
#11
Re: GDI - can i speed up the DIB code?
Originally Posted by VladimirF
I might have missed something.
Could you please upload your zipped test project (without Debug/Release folders) here?
What bitmap do you pass to function HRGN RegionbyBitmap(HBITMAP pBitmap,COLORREF clrTransparent)? And what color?
the h files it's to big for add here
in these case, don't matter what bitmap is used... realy. the image is drawed using GDI functions(of course with objective is accept all diferent images)
the funcion do:
- create the pixels array, using the Get24BitPixels() function;
- then i create a new region for add all data and for return it;
- i cycle the pixels for test if the color is for be transparent or not;
- return the region
Last edited by Cambalinho; July 24th, 2015 at 08:23 AM.
-
July 24th, 2015, 08:38 AM
#12
Re: GDI - can i speed up the DIB code?
with more search, i found 1 code much more faster:
Code:
HRGN RegionbyBitmap( HBITMAP hBmp, COLORREF color =-1)
{
// get image properties
BITMAP bmp = { 0 };
GetObject( hBmp, sizeof(BITMAP), &bmp );
// allocate memory for extended image information
LPBITMAPINFO bi = (LPBITMAPINFO) new BYTE[ sizeof(BITMAPINFO) + 8 ];
memset( bi, 0, sizeof(BITMAPINFO) + 8 );
bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// set window size
int m_dwWidth = bmp.bmWidth; // bitmap width
int m_dwHeight = bmp.bmHeight; // bitmap height
// create temporary dc
HDC dc = CreateIC( "DISPLAY",NULL,NULL,NULL );
// get extended information about image (length, compression, length of color table if exist, ...)
DWORD res = GetDIBits( dc, hBmp, 0, bmp.bmHeight, 0, bi, DIB_RGB_COLORS );
// allocate memory for image data (colors)
LPBYTE pBits = new BYTE[ bi->bmiHeader.biSizeImage + 4 ];
// allocate memory for color table
if ( bi->bmiHeader.biBitCount == 8 )
{
// actually color table should be appended to this header(BITMAPINFO),
// so we have to reallocate and copy it
LPBITMAPINFO old_bi = bi;
// 255 - because there is one in BITMAPINFOHEADER
bi = (LPBITMAPINFO)new char[ sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD) ];
memcpy( bi, old_bi, sizeof(BITMAPINFO) );
// release old header
delete old_bi;
}
// get bitmap info header
BITMAPINFOHEADER& bih = bi->bmiHeader;
// get color table (for 256 color mode contains 256 entries of RGBQUAD(=DWORD))
LPDWORD clr_tbl = (LPDWORD)&bi->bmiColors;
// fill bits buffer
res = GetDIBits( dc, hBmp, 0, bih.biHeight, pBits, bi, DIB_RGB_COLORS );
DeleteDC( dc );
BITMAP bm;
GetObject( hBmp, sizeof(BITMAP), &bm );
// shift bits and byte per pixel (for comparing colors)
LPBYTE pClr = (LPBYTE)&color;
// swap red and blue components
BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp;
// convert color if curent DC is 16-bit (5:6:5) or 15-bit (5:5:5)
if ( bih.biBitCount == 16 )
{
// for 16 bit
color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
((DWORD)(pClr[1] & 0xfc) << 3) |
((DWORD)(pClr[2] & 0xf8) << 8);
// for 15 bit
// color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
// ((DWORD)(pClr[1] & 0xf8) << 2) |
// ((DWORD)(pClr[2] & 0xf8) << 7);
}
const DWORD RGNDATAHEADER_SIZE = sizeof(RGNDATAHEADER);
const DWORD ADD_RECTS_COUNT = 40; // number of rects to be appended
// to region data buffer
// BitPerPixel
BYTE Bpp = bih.biBitCount >> 3; // bytes per pixel
// bytes per line in pBits is DWORD aligned and bmp.bmWidthBytes is WORD aligned
// so, both of them not
DWORD m_dwAlignedWidthBytes = (bmp.bmWidthBytes & ~0x3) + (!!(bmp.bmWidthBytes & 0x3) << 2);
// DIB image is flipped that's why we scan it from the last line
LPBYTE pColor = pBits + (bih.biHeight - 1) * m_dwAlignedWidthBytes;
DWORD dwLineBackLen = m_dwAlignedWidthBytes + bih.biWidth * Bpp; // offset of previous scan line
// (after processing of current)
DWORD dwRectsCount = bih.biHeight; // number of rects in allocated buffer
INT i, j; // current position in mask image
INT first = 0; // left position of current scan line
// where mask was found
bool wasfirst = false; // set when mask has been found in current scan line
bool ismask; // set when current color is mask color
// allocate memory for region data
// region data here is set of regions that are rectangles with height 1 pixel (scan line)
// that's why first allocation is <bm.biHeight> RECTs - number of scan lines in image
RGNDATAHEADER* pRgnData =
(RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
// get pointer to RECT table
LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
// zero region data header memory (header part only)
memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) );
// fill it by default
pRgnData->dwSize = RGNDATAHEADER_SIZE;
pRgnData->iType = RDH_RECTANGLES;
for ( i = 0; i < bih.biHeight; i++ )
{
for ( j = 0; j < bih.biWidth; j++ )
{
// get color
switch ( bih.biBitCount )
{
case 8:
ismask = (clr_tbl[ *pColor ] != color);
break;
case 16:
ismask = (*(LPWORD)pColor != (WORD)color);
break;
case 24:
ismask = ((*(LPDWORD)pColor & 0x00ffffff) != color);
break;
case 32:
ismask = (*(LPDWORD)pColor != color);
}
// shift pointer to next color
pColor += Bpp;
// place part of scan line as RECT region if transparent color found after mask color or
// mask color found at the end of mask image
if ( wasfirst )
{
if ( !ismask )
{
// save current RECT
pRects[ pRgnData->nCount++ ] ={first, i, j, i + 1 };
// if buffer full reallocate it with more room
if ( pRgnData->nCount >= dwRectsCount )
{
dwRectsCount += ADD_RECTS_COUNT;
// allocate new buffer
LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
// copy current region data to it
memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
// delte old region data buffer
delete pRgnData;
// set pointer to new regiondata buffer to current
pRgnData = (RGNDATAHEADER*)pRgnDataNew;
// correct pointer to RECT table
pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
}
wasfirst = false;
}
}
else if ( ismask ) // set wasfirst when mask is found
{
first = j;
wasfirst = true;
}
}
if ( wasfirst && ismask )
{
// save current RECT
pRects[ pRgnData->nCount++ ] = {first, i, j, i + 1 };
// if buffer full reallocate it with more room
if ( pRgnData->nCount >= dwRectsCount )
{
dwRectsCount += ADD_RECTS_COUNT;
// allocate new buffer
LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
// copy current region data to it
memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
// delte old region data buffer
delete pRgnData;
// set pointer to new regiondata buffer to current
pRgnData = (RGNDATAHEADER*)pRgnDataNew;
// correct pointer to RECT table
pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
}
wasfirst = false;
}
pColor -= dwLineBackLen;
}
// release image data
delete pBits;
delete bi;
// create region
HRGN hRgn = ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
// release region data
delete pRgnData;
return hRgn;
}
maybe i need more work for correct the color=-1. but works fine.
i found it(on source code): http://www.********.net/VC_Library_C...VC_Example.htm
thanks for all
-
July 24th, 2015, 08:44 AM
#13
Re: [RESOLVED] GDI - can i speed up the DIB code?
VladimirF : i'm sorry, but i can't rate you
but thanks for help me
-
July 24th, 2015, 08:48 AM
#14
Re: GDI - can i speed up the DIB code?
Oops... I incorrectly used SetRectRgn() function by passing the width of the rectangle instead of its right coordinate.
Here is corrected code:
Code:
DWORD p = 0;
int xStart = 0;
bool bTransp(false);
hTmpRgn = CreateRectRgn(0, 0, 1, 1);
for (WORD y = 0; y<wBmpHeight; y++)
{
for (WORD x = 0; x<wBmpWidth; x++)
{
BYTE jRed = pPixels[p + 2];
BYTE jGreen = pPixels[p + 1];
BYTE jBlue = pPixels[p + 0];
if ((jRed == jTranspR && jGreen == jTranspG && jBlue == jTranspB))
{
if (!bTransp)
{
xStart = x;
bTransp = true;
}
}
else
{
if (bTransp)
{
SetRectRgn(hTmpRgn, xStart, y, x, y + 1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
bTransp = false;
}
}
// next pixel
p += 3;
}
if (bTransp)
{
SetRectRgn(hTmpRgn, xStart, y, wBmpWidth, y + 1);
CombineRgn(hRgn, hRgn, hTmpRgn, RGN_XOR);
bTransp = false;
}
}
DeleteObject(hTmpRgn);
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
July 24th, 2015, 08:54 AM
#15
Re: [RESOLVED] GDI - can i speed up the DIB code?
thanks... yes works fine.. greate.
thank you for all
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|