Page 1 of 1
Quickly grab hDc image.
Posted: Sun May 22, 2011 3:07 am
by JustinJack
Code: Select all
Procedure CreateBitmapFromHDC( hDc )
SizeOfBitMapInfoHeader = SizeOf(BITMAPINFOHEADER)
SizeOfBitMapFileHeader = SizeOf(BITMAPFILEHEADER)
hBitmap = GetCurrentObject_(hDc, #OBJ_BITMAP)
GetObject_(hBitmap, SizeOf(BITMAP), @bm.BITMAP)
myBMBytes = (54) + (((bm\bmWidth * 3) + (bm\bmWidth % 4)) * bm\bmHeight)
bmfh.BITMAPFILEHEADER
bmih.BITMAPINFOHEADER
bmfh\bfOffBits = 54
bmfh\bfReserved1 = 0
bmfh\bfReserved2 = 0
bmfh\bfSize = myBMBytes
bmfh\bfType= $4D42
bmih\biSize = SizeOfBitMapInfoHeader
bmih\biBitCount = 24
bmih\biClrImportant = 0
bmih\biClrUsed = 0
bmih\biCompression = 0
bmih\biHeight = bm\bmHeight
bmih\biPlanes = bm\bmPlanes
bmih\biSizeImage = (3 * (bm\bmWidth * bm\bmHeight) )
bmih\biWidth = bm\bmWidth
bmih\biXPelsPerMeter = 0
bmih\biYPelsPerMeter = 0
*bmpBuffer = AllocateMemory( myBMBytes )
*bmpBits = *bmpBuffer + (54)
CopyMemory(@bmfh, *bmpBuffer, SizeOfBitMapFileHeader)
CopyMemory(@bmih, *bmpBuffer + SizeOfBitMapFileHeader, SizeOfBitMapInfoHeader)
hResult = GetDIBits_(hDc, hBitmap, 0, bm\bmHeight, *bmpBits, @bmih, #DIB_RGB_COLORS)
Select hResult
Case 0
FreeMemory(*bmpBuffer)
*bmpBuffer = 0
Case #ERROR_INVALID_PARAMETER
FreeMemory(*bmpBuffer)
*bmpBuffer = 0
Case bm\bmHeight
Default
FreeMemory(*bmpBuffer)
*bmpBuffer = 0
EndSelect
ProcedureReturn *bmpBuffer
EndProcedure
This is pretty useful. I use this to grab images from an hDc and send it to network locations. It creates a bitmap "CatchImage()"-able, and that can be saved to a file or whatever.
Don't forget to FreeMemory() the pointer returned by this function.....
Example:
Code: Select all
hWnd = OpenWindow(1, 0, 0, 500, 500, "Test Window", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
StringGadget(1, 10, 10, 150, 20, "This is a test!")
hdc = GetDC_(hWnd)
Repeat : Until WaitWindowEvent() = 16
*myImgPtr = CreateBitmapFromHDC(hDc)
CloseWindow(1)
myImage = CatchImage(#PB_Any, *myImgPtr)
SaveImage(myImage, "c:\users\justin\desktop\Test.bmp")
FreeImage(myImage)
FreeMemory(*myImgPtr)
Re: Quickly grab hDc image.
Posted: Sun May 22, 2011 3:09 am
by JustinJack
You can also use this for getting info from a web-cam window or a VideoRenderer class window, just get that window's dc, and there you go!
Re: Quickly grab hDc image.
Posted: Sun May 22, 2011 12:22 pm
by netmaestro
bmfh\bfSize = (54) + ((bm\bmHeight * bm\bmWidth) * 3)
Here you are calculating the needed total size by making room for the headers and then adding (bm\bmHeight * bm\bmWidth) * 3 for the colorbits. This will usually work without a problem but it does ignore one important feature of 24bit image colorbits: They are dword-aligned. This means that the number of bytes in the width of one horizontal line is going to be a multiple of 4. If the basic <width in pixels> * 3 doesn't yield a multiple of 4, from one to three bytes must be added to pad the line to the needed size. Here is code from srod which will do the trick:
then you can multiply by height and add for the headers and bob's your uncle.
Here's a simple case to illustrate the point:
1. Run the snippet below as-is without the purifier. It will probably work, with GetDIBits_() returning the desired 19 lines. Yet there was a problem, an invisible one.
2. Enable the purifier and rerun the code. It will raise an error at the GetDIBits_() line.
3. With the purifier still enabled, uncomment the second calculation for colorsize and rerun. The error is gone.
Code: Select all
CreateImage(0, 19,19,24)
colorsize = ImageWidth(0)*ImageHeight(0)*3
;colorsize = (4*((3*ImageWidth(0)+3)/4)) * ImageHeight(0)
With bmih.BITMAPINFOHEADER
\biSize = SizeOf(BITMAPINFOHEADER)
\biBitCount = 24
\biHeight = ImageHeight(0)
\biPlanes = 1
\biSizeImage = colorsize
\biWidth = ImageWidth(0)
EndWith
*colorbitsBuffer = AllocateMemory(colorsize)
hDC = CreateCompatibleDC_(0)
hResult = GetDIBits_(hDc, ImageID(0), 0, ImageHeight(0), *colorbitsBuffer, @bmih, #DIB_RGB_COLORS)
DeleteDC_(hDC)
Debug hResult
Re: Quickly grab hDc image.
Posted: Mon May 23, 2011 9:22 am
by JustinJack
Interesting, y'know what...I actually had a problem with that very issue a while back. I was getting funky colors coming out, and I fleetingly thought about that, so my quick-on-the-fly solution was to changed the header to a 32bpp map and used all 4's for the calculations and allocations, and it worked great. Since then I had forgotton why I did that, and changed this code back to 3's to try and save packet size and qty in sending images via the network, and it was working fine so i shrugged and didn't give it any more thought. Would that work fine all the time? what do you think?
Re: Quickly grab hDc image.
Posted: Mon May 23, 2011 2:07 pm
by netmaestro
Omitting the padding is one of those errors that can lead to insidious bug behavior. As it's a matter of chance whether the expected row width is out by 0,1,2 or 3 bytes, the severity of the problem will bounce around between perfect results, colors somewhat garbled, colors very garbled and as an added bonus, the occasional outright crash. If you implement the padding formula it'll all clear up because your color alignment will be correct and you will never overwrite the boundaries of your allocated memory.
Re: Quickly grab hDc image.
Posted: Mon May 23, 2011 9:10 pm
by JustinJack
bytesPerRow = (width * 3) + (width % 4)
This seems to do the trick, huh? It's a little easier on the eyes too!
I changed that 1st post to have this added...question for netmaestro..
If GetDIBBits() put the bits into our memory 3 bytes (24 bits) at a time, and the bitmap is actually saved that way, either to the disk, in memory or in a video buffer, or wherever, doesn't some process have to shift those bits right or basically PARSE somehow that data. I mean, the quickest way on a 32 bit machine would be to read those as DWORD's, but it almost seems like they'd have to be read as bytes...That's why I was originally just calculating by buffer size as (Width * Height) * 4...period, but I tried whittling it down to move the data as quickly as possible, but it seems like it'd be easier for the computer to load a 32bit bitmap than a 24...Thoughts? Ideas? Wisdom?