[WinAPI] DC and pixel data

BlitzMax Forums/BlitzMax Programming/[WinAPI] DC and pixel data

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Good evening
I have a problem. I need my desktop in a pixmap and the GDI function "GetPixel" is too slow. After hours of search I have found this code.
<Click>
Sounds logical, i need a pointer to the pixel data, easy.
The Blitz Max version:

Strict 

Extern "Win32"
	Function GetDIBits(hdc:Int, bitmap:Int, Start:Int, Num:Int, bits:Byte Ptr, lpbi:Byte Ptr, usage:Int)
	Function CreateCompatibleBitmap(hdc:Int, Width:Int, Height:Int)
	Function CreateDIBSection(hdc:Int, pbmi:Byte Ptr, usage:Int, Bits:Byte Ptr, hSection:Int, Offset:Int)
	Function SelectObject(hdc:Int, obj:Int)
	Function CreateCompatibleDC(hdc:Int)
	Function GetDesktopWindow()
	Function GetWindowDC(hwnd:Int)
	Function GetDeviceCaps(hdc:Int, index:Int)
	Function DeleteDC(hdc:Int)
	Function DeleteObject(obj:Int)
	Function ReleaseDC(hwdn:Int, hdc:Int)
End Extern 


Type RGBQuad
	Field R:Byte
	Field G:Byte
	Field B:Byte
	Field Res:Byte
End Type


Type BITMAPINFOHEADER
	Field biSize:Int
	Field biWidth:Long
	Field biHeight:Long
	Field biPlanes:Short
	Field biBitCount:Short
	Field biCompression:Int
	Field biSizeImage:Int
	Field biXPelsPerMeter:Long
	Field biYPelsPerMeter:Long
	Field biClrUsed:Int
	Field biClrImportant:Int
End Type


Type BITMAPINFO
	Field bmiHeader:Byte Ptr
	Field bmiColors:Byte Ptr
End Type


Const HORZRES:Int = 8
Const VERTRES:Int = 10


Local HwndDesktop:Int
Local hdcDesktop:Int
Local hdcMem:Int
Local DesktopWidth:Int
Local DesktopHeight:Int
Local bmpMem:Int
Local Header:BITMAPINFOHEADER
Local INFO:BITMAPINFO
Local Buf:Byte Ptr 

DebugLog ""

HwndDesktop = GetDesktopWindow()

If HwndDesktop
	DebugLog "Desktop Hwnd found"
EndIf



hdcDesktop = GetWindowDC(HwndDesktop)

If hdcDesktop
	DebugLog "Desktop DC found"
EndIf


hdcMem = CreateCompatibleDC(hdcDesktop)

If hdcMem
	DebugLog "Compatible dc created"
EndIf



DesktopWidth = GetDeviceCaps(hdcDesktop, HORZRES)
DebugLog "DesktopWidth: "+DesktopWidth


DesktopHeight = GetDeviceCaps(hdcDesktop, VERTRES)
DebugLog "DesktopHeight: "+DesktopHeight


bmpMem  = CreateCompatibleBitmap(hdcDesktop, DesktopWidth, DesktopHeight)

If bmpMem
	DebugLog "Compatible bitmap created"
EndIf

If SelectObject(HdcMem, bmpMem)
	DebugLog "bmpMem selected into the dcMem"
EndIf



Header = New BITMAPINFOHEADER
Header.biSize         = SizeOf(Header)
Header.biWidth        = DesktopWidth
Header.biheight       = DesktopHeight
Header.biPlanes       = 1
Header.biBitCount     = 24
Header.biCompression  = 0


INFO                  = New BITMAPINFO
Info.bmiHeader        = Header


If BitBlt(hdcMem,0,0,Header.biWidth,Header.biHeight, hdcDesktop,0,0,ROP_SRCCOPY)	
	DebugLog "BitBlt successful"
EndIf



If GetDIBits(hdcMem, bmpMem, 0, Header.biHeight, Buf, info, 0)
	DebugLog "GetDIBits successful"
Else
	DebugLog "WHY...WHYYYY?????"
EndIf


DebugLog ""

DeleteDC(HdcMem)
DeleteObject(bmpMem)
ReleaseDC(hwndDesktop, hdcDesktop)


I´m tired and disappointed.
The GetDIBits function returns 0 and I dont know where the problem is (Wrong Type structure, Wrong Ptr?)
Thx for help.
Mfg Suco

Ok, I have found the solution. The problem ist on the BITMAPINFO Type. If I copy the BITMAPINFOHEADER directly into the BITMAPINFO type, it runs fine.

My small GetDesktopPixmap function

Rem 
DesktopPixmap function by Suco-X
End Rem 

Strict 


Function GetDesktopPixmap:TPixmap()
	
	Extern "Win32"
		Function GetDIBits(hdc:Int, bitmap:Int, Start:Int, Num:Int, bits:Byte Ptr, lpbi:Byte Ptr, usage:Int)
		Function CreateCompatibleBitmap(hdc:Int, Width:Int, Height:Int)
		Function CreateDIBSection(hdc:Int, pbmi:Byte Ptr, usage:Int, Bits:Byte Ptr, hSection:Int, Offset:Int)
		Function SelectObject(hdc:Int, obj:Int)
		Function CreateCompatibleDC(hdc:Int)
		Function GetDesktopWindow()
		Function GetWindowDC(hwnd:Int)
		Function GetDeviceCaps(hdc:Int, index:Int)
		Function DeleteDC(hdc:Int)
		Function DeleteObject(obj:Int)
		Function ReleaseDC(hwdn:Int, hdc:Int)
		Function BitBlt(hdc,x,y,w,h,src_dc,src_x,src_y,dwrop)
	End Extern 


	?Win32
	
		Type BITMAPINFO
			Field biSize:Int
			Field biWidth:Int
			Field biHeight:Int
			Field biPlanes:Short
			Field biBitCount:Short
			Field biCompression:Int
			Field biSizeImage:Int
			Field biXPelsPerMeter:Int
			Field biYPelsPerMeter:Int
			Field biClrUsed:Int
			Field biClrImportant:Int
			
			Field R:Byte
			Field G:Byte
			Field B:Byte
			Field Res:Byte
		End Type
		
		
		Const HORZRES:Int = 8
		Const VERTRES:Int = 10
	
		Local HwndDesktop:Int
		Local hdcDesktop:Int
		Local hdcMem:Int
		Local DesktopWidth:Int
		Local DesktopHeight:Int
		Local bmpMem:Int
		Local INFO:BITMAPINFO
		Local FinalPixmap:TPixmap
	
		HwndDesktop = GetDesktopWindow()
	
		If Not HwndDesktop
			Return Null
		EndIf
		
		
		hdcDesktop = GetWindowDC(HwndDesktop)
		
		If Not HdcDesktop
			Return Null
		EndIf
		
		
		hdcMem = CreateCompatibleDC(hdcDesktop)
		
		If Not HdcMem
			Return Null
		EndIf
		
		
		DesktopWidth = GetDeviceCaps(hdcDesktop, HORZRES)
		DesktopHeight = GetDeviceCaps(hdcDesktop, VERTRES)
	
		If DesktopWidth = 0 Or DesktopHeight = 0
			Return Null
		EndIf
		
		
		bmpMem  = CreateCompatibleBitmap(hdcDesktop, DesktopWidth, DesktopHeight)
	
		If Not BmpMem
			Return Null
		EndIf
		
		
		If Not SelectObject(HdcMem, bmpMem)
			Return Null
		EndIf
		
		Info                = New BITMAPINFO
		Info.bisize         = SizeOf(INFO)
		info.BiWidth        = DesktopWidth
		Info.biHeight       = DesktopHeight
		Info.biPlanes       = 1
		info.biBitCount     = 32
		Info.biCompression  = 0
		
		
		If Not BitBlt(hdcMem,0,0,Info.biWidth,Info.biHeight, hdcDesktop,0,0,ROP_SRCCOPY)	
			Return Null
		EndIf
		
		FinalPixmap = CreatePixmap(info.biWidth, info.biHeight, PF_BGRA8888)
		
		If Not GetDIBits(hdcMem, bmpMem, 0, Info.biHeight, FinalPixmap.PixelPtr(0,0), info, 0)
			Return Null
		EndIf
		
		FinalPixmap = YFlipPixmap(FinalPixmap)
		
		DeleteDC(HdcMem)
		DeleteObject(bmpMem)
		ReleaseDC(hwndDesktop, hdcDesktop)
		
		Return FinalPixmap
		
	?
	
	?Linux
		Return Null
	?
	
	?MacOs
		Return Null
	?
End Function



Local Time:Int = MilliSecs()

Local DesktopScreen:TPixmap = GetDesktopPixmap()

Time = MilliSecs()-Time

Print ""
Print "PixmapsPerSecond: "+(1000/Time)
Print ""

If DesktopScreen = Null
	Print "TEST FEHLGESCHLAGEN"
EndIf



Graphics 1024, 768,0

DrawPixmap DesktopScreen,0,0
Flip
WaitKey()


Please test, Win32 only

Mfg Suco

This is absolutely perfect for my form-editor project, and if you don't mind I would appreciate it if I could use a modifed version of it (with credits) :-)

With this one you pass in *any* gadget, and it makes a pixmap copy of whatever it is displaying.
?win32
Rem
bbdoc: Modified from an original example by Suco-X
End Rem
Function GetGadgetPixmap:TPixmap(gad:TGadget)
	
	Extern "Win32"
		Function GetDIBits(hdc:Int, bitmap:Int, Start:Int, Num:Int, bits:Byte Ptr, lpbi:Byte Ptr, usage:Int)
		Function CreateCompatibleBitmap(hdc:Int, Width:Int, Height:Int)
		Function CreateDIBSection(hdc:Int, pbmi:Byte Ptr, usage:Int, Bits:Byte Ptr, hSection:Int, Offset:Int)
		Function SelectObject(hdc:Int, obj:Int)
		Function CreateCompatibleDC(hdc:Int)
		Function GetGadgetWindow()
		Function GetWindowDC(hwnd:Int)
		Function GetDeviceCaps(hdc:Int, index:Int)
		Function DeleteDC(hdc:Int)
		Function DeleteObject(obj:Int)
		Function ReleaseDC(hwdn:Int, hdc:Int)
		Function BitBlt(hdc:Int,x:Int,y:Int,w:Int,h:Int,src_dc:Int,src_x:Int,src_y:Int,dwrop:Int)
		Function GetDC(hwnd:Int)
	End Extern 


	Type BITMAPINFO
		Field biSize:Int
		Field biWidth:Int
		Field biHeight:Int
		Field biPlanes:Short
		Field biBitCount:Short
		Field biCompression:Int
		Field biSizeImage:Int
		Field biXPelsPerMeter:Int
		Field biYPelsPerMeter:Int
		Field biClrUsed:Int
		Field biClrImportant:Int
		
		Field R:Byte
		Field G:Byte
		Field B:Byte
		Field Res:Byte
	End Type
	
	
	Const HORZRES:Int = 8
	Const VERTRES:Int = 10

	Local HwndGadget:Int
	Local hdcGadget:Int
	Local hdcMem:Int
	Local width:Int
	Local height:Int
	Local bmpMem:Int
	Local INFO:BITMAPINFO
	Local FinalPixmap:TPixmap

	HwndGadget = QueryGadget(gad, QUERY_HWND)

	If Not HwndGadget
		Return Null
	EndIf
	
	
	hdcGadget = GetDC(HwndGadget)
	
	If Not HdcGadget
		Return Null
	EndIf
	
	
	hdcMem = CreateCompatibleDC(hdcGadget)
	
	If Not HdcMem
		Return Null
	EndIf
	
	
	width = GadgetWidth(gad)
	height = GadgetHeight(gad)

	If width = 0 Or height = 0
		Return Null
	EndIf
	
	
	bmpMem  = CreateCompatibleBitmap(hdcGadget, width, height)

	If Not BmpMem
		Return Null
	EndIf
	
	
	If Not SelectObject(HdcMem, bmpMem)
		Return Null
	EndIf
	
	Info                = New BITMAPINFO
	Info.bisize         = SizeOf(INFO)
	info.BiWidth        = width
	Info.biHeight       = height
	Info.biPlanes       = 1
	info.biBitCount     = 32
	Info.biCompression  = 0
	
	
	If Not BitBlt(hdcMem,0,0,Info.biWidth,Info.biHeight, hdcGadget,0,0,ROP_SRCCOPY)	
		Return Null
	EndIf
	
	FinalPixmap = CreatePixmap(info.biWidth, info.biHeight, PF_BGRA8888)
	
	If Not GetDIBits(hdcMem, bmpMem, 0, Info.biHeight, FinalPixmap.PixelPtr(0,0), info, 0)
		Return Null
	EndIf
	
	FinalPixmap = YFlipPixmap(FinalPixmap)
	
	DeleteDC(HdcMem)
	DeleteObject(bmpMem)
	ReleaseDC(hwndGadget, hdcGadget)
	
	Return FinalPixmap
End Function
?

It allows me to get around the win32 problem of not being able to have a button on the window that I don't want to click on.

Excellent :-D