How to capture a transparent window covered by another?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

How to capture a transparent window covered by another?

Post by Chappier » 16 Jan 2022, 13:20

Trying to capture the screen of Gui1 into the layered window, however, the image is drawn without transparency.

Code: Select all

; https://github.com/tariqporter/Gdip/blob/master/Gdip.ahk
;#Include gdip.ahk
SetBatchLines, -1

pToken := Gdip_Startup()
OnMessage(0x0201, "WM_LBUTTONDOWN")



Gui +HwndGui1 -Caption
Gui, Color, 0
Gui, Show, x300 w600 h400


VarSetCapacity(pBlurBehind,16,0)
NumPut(1,pBlurBehind) , NumPut(1,pBlurBehind,4)
hr := Dllcall("Dwmapi\DwmEnableBlurBehindWindow","uint", Gui1,"uint",&pBlurBehind)



Gui, 2: +HwndGui2 +E0x80000 +OwnDialogs +Resize -Caption

; Take a picture of the Gui1
pBitmap := Gdip_BitmapFromHWND(Gui1)

Gdip_GetImageDimension(pBitmap, W, H)
hbm := CreateDIBSection(W, H)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
G   := Gdip_GraphicsFromHDC(hdc)

Gdip_SetInterpolationMode(G,7)

; Draw the picture into the hdc.
Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)

; Draw the picture into the Layered Window.
UpdateLayeredWindow(Gui2, hdc, 0, 0, W, H)

Gui, 2: Show, NA x1000 w%W% h%H%
Return



Esc::ExitApp



WM_LBUTTONDOWN(wParam, lParam, Msg, Hwnd) {
   If (A_Gui)
      PostMessage, 0xA1, 2
}
The bitmap taken here: pBitmap := Gdip_BitmapFromHWND(Gui1) must not be saving the transparency.
What other way I could take a bitmap that stores the transparency info to draw into the LayeredWindow?

While searching about layered windows, I could find some topics by @Hellbent, let me know if you have any idea about it.




EDIT
--------------------
What I'm trying is to capture a transparent window even when it's covered by another window, the script above was just a draft.
Last edited by Chappier on 22 Jan 2022, 12:30, edited 2 times in total.

User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: How to capture a transparent window into a LayeredWindow?

Post by Hellbent » 16 Jan 2022, 13:50

I haven't done much altering transparency of an image after it is created. I normally create my own graphics and the transparency is baked in.

@boiler is more likely to be able to help you with changing the transparency of your image.

The only thing I have ever tried that is related is these two functions here.

viewtopic.php?f=76&t=92850&p=413738#p413738

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window into a LayeredWindow?

Post by Chappier » 16 Jan 2022, 14:09

My goal is not really to change the transparency of an image, I created the code more to reproduce the scenario.

I'm trying to capture a window that contains transparency and draw it into a Gui with the same transparency.

For that, I'm trying to find a way to capture the image from the first window while storing the transparency info and then draw it into the layered.

User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: How to capture a transparent window into a LayeredWindow?

Post by Hellbent » 16 Jan 2022, 14:41

I'm not sure of your purpose.

You can use BitmapFromScreen if you just want to get a image of what you see.

Code: Select all

WingetPos, x, y, w, h, % "ahk_id " Gui1
pBitmap := Gdip_BitmapFromScreen( x "|" y "|" w "|" h  )

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window into a LayeredWindow?

Post by Chappier » 16 Jan 2022, 14:53

Code: Select all

WinSet, Transparent, 150, Untitled - Paint

WinGet, Id, Id, Untitled - Paint
WinGetPos, X, Y, W, H, ahk_id %Id%

pBitmap := Gdip_BitmapFromHWND(Id)

Gui, 2: +HwndGui2 +E0x80000 +OwnDialogs -Caption -Resize
Gdip_GetImageDimension(pBitmap, W, H)
hbm := CreateDIBSection(W, H)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
G   := Gdip_GraphicsFromHDC(hdc)

Gdip_SetInterpolationMode(G,7)

; Draw the picture into the hdc.
Gdip_DrawImage(G, pBitmap, 0, 0, W, H, 0, 0, W, H)

; Draw the picture into the Layered Window.
UpdateLayeredWindow(Gui2, hdc, 0, 0, W, H)
X:= X+W+100
Gui, 2: Show, NA x%X% w%W% h%H%

Return
The Gui on Right doesn't contain the transparency from the Gui on Left
pic (3).png
pic (3).png (96.26 KiB) Viewed 889 times
I'm not sure of your purpose.
Im trying to capture a window containing transparency and draw it into a GUI with the same transparency.

User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: How to capture a transparent window into a LayeredWindow?

Post by Hellbent » 16 Jan 2022, 15:08

Chappier wrote:
16 Jan 2022, 14:53
The Gui on Right doesn't contain the transparency from the Gui on Left
Did you try the method I mentioned?

Code: Select all

WingetPos, x, y, w, h, % "ahk_id " Gui1
pBitmap := Gdip_BitmapFromScreen( x "|" y "|" w "|" h  )
20220116150736.png
20220116150736.png (188.58 KiB) Viewed 877 times

Code: Select all

#Include Gdip.ahk
#SingleInstance, Force
GDIP_STARTUP()

Gui +HwndGui1 -Caption +AlwaysOnTop
Gui, Color, 0
Gui, Show, x300 w600 h400

VarSetCapacity(pBlurBehind,16,0)
NumPut(1,pBlurBehind) , NumPut(1,pBlurBehind,4)
hr := Dllcall("Dwmapi\DwmEnableBlurBehindWindow","uint", Gui1,"uint",&pBlurBehind)

WingetPos, x, y, w, h, % "ahk_id " Gui1
pBitmap := Gdip_BitmapFromScreen( x "|" y "|" w "|" h  )

Gui2 := New PopUpWindow( { AutoShow: 1 , X: 0 , Y: 0 , W: GDIP_GetImageWidth( pBitmap ) , H: GDIP_GetImageHeight( pBitmap ) , Options: " -DPIScale +AlwaysOnTop " } )
Gui2.DrawBitmap( pBitmap , { X: 0 , Y: 0 , W: Gui2.W , H: Gui2.H } , dispose := 1 , AutoUpdate := 1 )

return
GuiContextMenu:
*ESC::ExitApp

RAlt::PopUpWindow.Helper()

;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
class PopUpWindow	{
;PopUpWindow v2
;Date Written: Oct 28th, 2021
;Written By: Hellbent aka CivReborn
;SpcThanks: teadrinker , malcev 
	static Index := 0 , Windows := [] , Handles := [] , EditHwnd , HelperHwnd
	__New( obj := "" ){
		This._SetDefaults()
		This.UpdateSettings( obj )
		This._CreateWindow()
		This._CreateWindowGraphics()
		if( This.AutoShow )
			This.ShowWindow( This.Title )
	}
	_SetDefaults(){
		This.X := 10
		This.Y := 10
		This.W := 10
		This.H := 10
		This.Smoothing := 2
		This.Options := " -DPIScale +AlwaysOnTop "
		This.AutoShow := 0
		This.GdipStartUp := 0
		This.Title := ""
		
		This.Controls := []
		This.Handles := []
		This.Index := 0 
	}
	AddTrigger( obj ){
		local k , v , cc , bd
		
		This.Controls[ ++This.Index ] := { 	X:		10
										,	Y:		10
										,	W:		10
										,	H:		10	}
		for k, v in obj
			This.Controls[ This.Index ][ k ] := obj[ k ] 
		cc := This.Controls[ This.Index ]
		Gui, % This.Hwnd ":Add", Text, % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " hwndhwnd"
		This.Handles[ hwnd ] := This.Index
		This.Controls[ This.Index ].Hwnd := hwnd
		return hwnd
		
	}
	DrawTriggers( color := "0xFFFF0000" , AutoUpdate := 0 ){
		local brush , cc 
		Brush := Gdip_BrushCreateSolid( color ) 
		Gdip_SetSmoothingMode( This.G , 3 )
		loop, % This.Controls.Length()	{
			cc := This.Controls[ A_Index ]
			Gdip_FillRectangle( This.G , Brush , cc.x , cc.y , cc.w , cc.h )
		
		}
		Gdip_DeleteBrush( Brush )
		Gdip_SetSmoothingMode( This.G , This.Smoothing )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	UpdateSettings( obj := "" , UpdateGraphics := 0 ){
		local k , v
		if( IsObject( obj ) )
			for k, v in obj
				This[ k ] := obj[ k ]
		( This.X = "Center" ) ? ( This.X := ( A_ScreenWidth - This.W ) / 2 ) 	
		( This.Y = "Center" ) ? ( This.Y := ( A_ScreenHeight - This.H ) / 2 ) 	
		if( UpdateGraphics ){
			This._DestroyWindowsGraphics()
			This._CreateWindowGraphics()
		}
	}
	_CreateWindow(){
		local hwnd
		Gui , New, % " +LastFound +E0x80000 hwndhwnd -Caption  " This.Options ;+E0x80000 = WS_EX_LAYERED
		PopUpWindow.Index++
		This.Index := PopUpWindow.Index
		PopUpWindow.Windows[ PopUpWindow.Index ] := This
		This.Hwnd := hwnd
		PopUpWindow.Handles[ hwnd ] := PopUpWindow.Index
		if( This.GdipStartUp && !PopUpWindow.pToken )
			PopUpWindow.pToken := GDIP_STARTUP()
	}
	_DestroyWindowsGraphics(){
		SelectObject( This.hdc , This.obm )
		DeleteObject( This.hbm )
		DeleteDC( This.hdc )
	}
	_CreateWindowGraphics(){
		This.hbm := CreateDIBSection( This.W , This.H )
		This.hdc := CreateCompatibleDC()
		This.obm := SelectObject( This.hdc , This.hbm )
		This.G := Gdip_GraphicsFromHDC( This.hdc )
		Gdip_SetSmoothingMode( This.G , This.Smoothing )
	}
	ShowWindow( Title := "" ){
		Gui , % This.Hwnd ":Show", % "x" This.X " y" This.Y " w" This.W " h" This.H " NA", % Title
	}
	HideWindow(){
		Gui , % This.Hwnd ":Hide",
	}
	UpdateWindow(){
		UpdateLayeredWindow( This.hwnd , This.hdc , This.X , This.Y , This.W , This.H )
	}
	ClearWindow( AutoUpdate := 0 ){
		Gdip_GraphicsClear( This.G )
		if( Autoupdate )
			This.UpdateWindow()
	}
	DrawBitmap( pBitmap , obj , dispose := 1 , AutoUpdate := 0 ){
		Gdip_DrawImage( This.G , pBitmap , obj.X , obj.Y , obj.W , obj.H )
		if( dispose )
			Gdip_DisposeImage( pBitmap )
		if( Autoupdate )
			This.UpdateWindow()
	}
	PaintBackground( color := "0xFF000000" , AutoUpdate := 0 ){
		if( isObject( color ) ){
			Brush := Gdip_BrushCreateSolid( ( color.HasKey( "Color" ) ) ? ( color.Color ) : ( "0xFF000000" ) ) 
			if( color.Haskey( "Round" ) )
				Gdip_FillRoundedRectangle( This.G , Brush , color.X , color.Y , color.W , color.H , color.Round )
			else
				Gdip_FillRectangle( This.G , Brush , color.X , color.Y , color.W , color.H ) 
		}else{
			Brush := Gdip_BrushCreateSolid( color ) 
			Gdip_FillRectangle( This.G , Brush , -1 , -1 , This.W + 2 , This.H + 2 ) 
		}
		Gdip_DeleteBrush( Brush )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	DeleteWindow( GDIPShutdown := 0 ){
		Gui, % This.Hwnd ":Destroy"
		SelectObject( This.hdc , This.obm )
		DeleteObject( This.hbm )
		DeleteDC( This.hdc )
		Gdip_DeleteGraphics( This.G )
		hwnd := This.Hwnd
		for k, v in PopUpWindow.Windows[ Hwnd ]
			This[k] := ""
		PopUpWindow.Windows[ Hwnd ] := ""
		if( GDIPShutdown ){
			Gdip_Shutdown( PopUpWindow.pToken )
			PopUpWindow.pToken := ""
		}
	}
	_OnClose( wParam ){
		if( wParam = 0xF060 ){	;SC_CLOSE ;[ clicking on the gui close button ]
			Try{
				Gui, % PopUpWindow.HelperHwnd ":Destroy"
				SoundBeep, 555
			}
		}
	}
	CreateCachedBitmap( pBitmap , Dispose := 0 ){
		local pCachedBitmap
		if( This.CachedBitmap )
			This.DisposeCachedbitmap()
		DllCall( "gdiplus\GdipCreateCachedBitmap" , "Ptr" , pBitmap , "Ptr" , this.G , "PtrP" , pCachedBitmap )
		This.CachedBitmap := pCachedBitmap
		if( Dispose )
			Gdip_DisposeImage( pBitmap )
	}
	DrawCachedBitmap( AutoUpdate := 0 ){
		DllCall( "gdiplus\GdipDrawCachedBitmap" , "Ptr" , this.G , "Ptr" , This.CachedBitmap , "Int" , 0 , "Int" , 0 )
		if( AutoUpdate )
			This.UpdateWindow()
	}
	DisposeCachedbitmap(){
		DllCall( "gdiplus\GdipDeleteCachedBitmap" , "Ptr" , This.CachedBitmap )
	}
	Helper(){
		local hwnd , MethodList := ["__New","UpdateSettings","ShowWindow","HideWindow","UpdateWindow","ClearWindow","DrawBitmap","PaintBackground","DeleteWindow" , "AddTrigger" , "DrawTriggers", "CreateCachedBitmap" , "DrawCachedBitmap" , "DisposeCachedbitmap" ]
		Gui, New, +AlwaysOnTop +ToolWindow +HwndHwnd
		PopUpWindow.HelperHwnd := hwnd
		Gui, Add, Edit, xm ym w250 r1 Center hwndhwnd, Gui1
		PopUpWindow.EditHwnd := hwnd
		loop, % MethodList.Length()	
			Gui, Add, Button, xm y+1 w250 r1 gPopUpWindow._HelperClip, % MethodList[ A_Index ]
		Gui, Show,,
		OnMessage( 0x112 , This._OnClose.Bind( hwnd ) )
	}
	_HelperClip(){
		local ClipList 
		
		GuiControlGet, out, % PopUpWindow.HelperHwnd ":", % PopUpWindow.EditHwnd	
		
		ClipList := 		{ 	__New: 					" := New PopUpWindow( { X: 0 , Y: 0 , W: A_ScreenWidth , H: A_ScreenHeight , Options: "" -DPIScale +AlwaysOnTop "" } )"
							,	UpdateSettings:			".UpdateSettings( { X: """" , Y: """" , W: """" , H: """" } , UpdateGraphics := 0 )"
							,	ShowWindow:				".ShowWindow( Title := """" )"
							,	HideWindow:				".HideWindow()"
							,	UpdateWindow:			".UpdateWindow()"
							,	ClearWindow:			".ClearWindow( AutoUpdate := 0 )"
							,	DrawBitmap:				".DrawBitmap( pBitmap := """" , { X: 0 , Y: 0 , W: " Out ".W , H: " Out ".H } , dispose := 1 )"
							,	PaintBackground:		".PaintBackground( color := ""0xFF000000"" )  "  ";{ Color: ""0xFF000000"" , X: 2 , Y: 2 , W: " Out ".W - 4 , H: " Out ".H - 4 , Round: 10 }"
							,	DeleteWindow:			".DeleteWindow( GDIPShutdown := 0 )"
							,	AddTrigger:				".AddTrigger( { X: """" , Y: """" , W: """" , H: """" , Value: """" , Label: """" , BoundClass: """" , BoundMethod: """" } )"	
							,	DrawTriggers:			".DrawTriggers( color := ""0xFFFF0000"" , AutoUpdate := 0 )"	
							,	CreateCachedBitmap:		".CreateCachedBitmap( pBitmap , Dispose := 0 )"	
							,	DrawCachedBitmap: 		".DrawCachedBitmap( AutoUpdate := 0 )"	
							,	DisposeCachedbitmap:	".DisposeCachedbitmap()"	}
							
		clipboard := Out ClipList[ A_GuiControl ]
		
	}
}
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window into a LayeredWindow?

Post by Chappier » 16 Jan 2022, 15:27

Tried the exact script you post above.

The second GUI doesn't contain the same transparency.
image.png
image.png (44.31 KiB) Viewed 870 times

User avatar
Hellbent
Posts: 2102
Joined: 23 Sep 2017, 13:34

Re: How to capture a transparent window into a LayeredWindow?

Post by Hellbent » 16 Jan 2022, 15:41

Chappier wrote:
16 Jan 2022, 15:27
Tried the exact script you post above.
Your image isn't from the "exact" script I posted. Please share your revised code.

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window into a LayeredWindow?

Post by Chappier » 19 Jan 2022, 13:03

@Hellbent do you know any other way than Gdip_BitmapFromScreen? because this way will not work when the window is covered by another window (activating the window before capturing will not help).

User avatar
boiler
Posts: 16767
Joined: 21 Dec 2014, 02:44

Re: How to capture a transparent window into a LayeredWindow?

Post by boiler » 19 Jan 2022, 13:14

You can use Gdip_BitmapFromHWND to capture from a specific window even if it's covered.

If it doesn't work with a particular window, you may need to replace that function in your Gdip library with this fix:

Code: Select all

Gdip_BitmapFromHWND(hwnd)
{
	WinGetPos,,, Width, Height, ahk_id %hwnd%
	hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
	RegExMatch(A_OsVersion, "\d+", Version)
	PrintWindow(hwnd, hdc, Version >= 8 ? 2 : 0)
	pBitmap := Gdip_CreateBitmapFromHBITMAP(hbm)
	SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
	return pBitmap
}

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window into a LayeredWindow?

Post by Chappier » 19 Jan 2022, 13:31

Gdip_BitmapFromHWND dont store the transparency.

User avatar
boiler
Posts: 16767
Joined: 21 Dec 2014, 02:44

Re: How to capture a transparent window into a LayeredWindow?

Post by boiler » 19 Jan 2022, 13:33

Oh, sorry. Should have read the earlier posts more closely.

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window into a LayeredWindow?

Post by Chappier » 19 Jan 2022, 13:43

Np, i see that the function Gdip_BitmapFromScreen supports capturing a given hwnd, even when its covered, with:

Code: Select all

pBitmap := Gdip_BitmapFromScreen("hwnd:" HWND)
In the function there is:

Code: Select all

   Else If (SubStr(Screen, 1, 5) = "hwnd:") {
      hwnd := SubStr(Screen, 6) 
      If !WinExist("ahk_id " hwnd) 
         Return -2 

      GetWindowRect(hwnd, _w, _h) 
      _x := _y := 0 
      hhdc := GetDCEx(hwnd, 3) 
   } 
However the bitmap saved also doesn't contain transparency, but I see this at the ending
BitBlt(chdc, 0, 0, _w, _h, hhdc, _x, _y, Raster)
Maybe there's a raster to be specified that could save the transparency information?

Chappier
Posts: 44
Joined: 21 Aug 2021, 21:58

Re: How to capture a transparent window covered by another?

Post by Chappier » 22 Jan 2022, 13:01

Tried to use BitBlt with the rasters CAPTUREBLT and SRCCOPY,

tried the function Gdip_CreateBitmapFromHBITMAP() with transparency. from @iseahound
viewtopic.php?t=63345

tried Gdip_DrawImage, but looks like the hbm is not storing the transparency information.

All bitmaps were saved without transparency.

Code: Select all

pToken := Gdip_Startup()


WinGet, hWnd, Id, Untitled - Notepad
WinActivate, ahk_id %hWnd%
WinSet, Transparent, 150, Untitled - Notepad
CaptureTransparentWindow(hWnd)
Return



CaptureTransparentWindow(hWnd) { 
   
   Static Ptr := "UPtr" 

   hhdc := 0 


   If !WinExist("ahk_id " hwnd) 
      Return -2 

   GetWindowRect(hwnd, _w, _h) 
   _x := _y := 0 
   hhdc := GetDCEx(hwnd, 3) 



   chdc := CreateCompatibleDC()
   hbm  := CreateDIBSection(_w, _h, chdc)
   obm  := SelectObject(chdc, hbm)
   hhdc := hhdc ? hhdc : GetDC()



   ; Raster operation codes:
   ; BLACKNESS          = 0x00000042
   ; NOTSRCERASE        = 0x001100A6
   ; NOTSRCCOPY         = 0x00330008
   ; SRCERASE           = 0x00440328
   ; DSTINVERT          = 0x00550009
   ; PATINVERT          = 0x005A0049
   ; SRCINVERT          = 0x00660046
   ; SRCAND             = 0x008800C6
   ; MERGEPAINT         = 0x00BB0226
   ; MERGECOPY          = 0x00C000CA
   ; SRCCOPY            = 0x00CC0020
   ; SRCPAINT           = 0x00EE0086
   ; PATCOPY            = 0x00F00021
   ; PATPAINT           = 0x00FB0A09
   ; WHITENESS          = 0x00FF0062
   ; CAPTUREBLT         = 0x40000000
   ; NOMIRRORBITMAP     = 0x80000000
   raster := 0x40000000|0x00CC0020
   BitBlt(chdc, 0, 0, _w, _h, hhdc, _x, _y, raster) 
   ReleaseDC(hhdc) 

 
   SelectObject(chdc, obm)



   pBitmap1 := CreateBitmap("", _w, _h)
   G        := Gdip_GraphicsFromHDC(chdc)
   Gdip_DrawImage(G, pBitmap1, 0, 0, _w, _h, 0, 0, _w, _h)

   Gdip_SaveBitmapToFile(pBitmap1, "w_1.png", 100)


   pBitmap2 := Gdip_CreateARGBBitmapFromHBITMAP(hbm)
   Gdip_SaveBitmapToFile(pBitmap2, "w_2.png", 100)



   pBitmap3  := Gdip_CreateBitmapFromHBITMAP(hbm)
   Gdip_SaveBitmapToFile(pBitmap3, "w_3.png", 100)



   DeleteObject(hbm)
   DeleteDC(hhdc)
   DeleteDC(chdc) 

}


Gdip_CreateARGBBitmapFromHBITMAP(hImage) {
; function by iseahound found on:
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=63345
; part of https://github.com/iseahound/Graphics/blob/master/lib/Graphics.ahk
   If !hImage
      Return

   ; struct BITMAP - https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-tagbitmap
   E := DllCall("GetObject", "ptr", hImage
            , "int", VarSetCapacity(dib, 76+2*(A_PtrSize=8?4:0)+2*A_PtrSize)
            , "ptr", &dib) ; sizeof(DIBSECTION) = x86:84, x64:104
   If !E
      Return

   width  := NumGet(dib, 4, "uint")
   height := NumGet(dib, 8, "uint")
   bpp    := NumGet(dib, 18, "ushort")

   ; Fallback to built-in method if pixels are not ARGB.
   if (bpp!=32)
      return Gdip_CreateBitmapFromHBITMAP(hImage)

   ; Create a handle to a device context and associate the hImage.
   hdc := CreateCompatibleDC()
   If !hdc
      Return

   obm := SelectObject(hdc, hImage)
   ; Buffer the hImage with a top-down device independent bitmap via negative height.
   ; Note that a DIB is an hBitmap, pixels are formatted as pARGB, and has a pointer to the bits.
   cdc := CreateCompatibleDC(hdc)
   If !cdc
   {
      SelectObject(hdc, obm), DeleteDC(hdc)
      Return
   }

   hbm := CreateDIBSection(width, -height, hdc, 32, pBits)
   If !hbm
   {
      DeleteDC(cdc), SelectObject(hdc, obm), DeleteDC(hdc)
      Return
   }

   ob2 := SelectObject(cdc, hbm)
   ; Create a new Bitmap (different from an hBitmap) which holds ARGB pixel values.
   pBitmap := Gdip_CreateBitmap(width, height)
   If !pBitmap
   {
      SelectObject(cdc, ob2)
      DeleteObject(hbm), DeleteDC(cdc)
      SelectObject(hdc, obm), DeleteDC(hdc)
      Return
   }

   ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB.
   CreateRectF(Rect, 0, 0, width, height, "uint")
   VarSetCapacity(BitmapData, 16+2*A_PtrSize, 0)
      , NumPut(       width, BitmapData,  0,  "uint") ; Width
      , NumPut(      height, BitmapData,  4,  "uint") ; Height
      , NumPut(   4 * width, BitmapData,  8,   "int") ; Stride
      , NumPut(     0xE200B, BitmapData, 12,   "int") ; PixelFormat
      , NumPut(       pBits, BitmapData, 16,   "ptr") ; Scan0

   E := DllCall("gdiplus\GdipBitmapLockBits"
            ,   "ptr", pBitmap
            ,   "ptr", &Rect
            ,  "uint", 6            ; ImageLockMode.UserInputBuffer | ImageLockMode.WriteOnly
            ,   "int", 0xE200B      ; Format32bppPArgb
            ,   "ptr", &BitmapData)

   ; Ensure that our hBitmap (hImage) is top-down by copying it to a top-down bitmap.
   BitBlt(cdc, 0, 0, width, height, hdc, 0, 0)

   ; Convert the pARGB pixels copied into the device independent bitmap (hbm) to ARGB.
   If !E
      DllCall("gdiplus\GdipBitmapUnlockBits", "ptr",pBitmap, "ptr",&BitmapData)

   ; Cleanup the buffer and device contexts.
   SelectObject(cdc, ob2)
   DeleteObject(hbm), DeleteDC(cdc)
   SelectObject(hdc, obm), DeleteDC(hdc)

   return pBitmap
}


Post Reply

Return to “Ask for Help (v1)”