How to get a bitmap from a hdc?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
kauan014
Posts: 55
Joined: 18 Feb 2021, 20:03

How to get a bitmap from a hdc?

Post by kauan014 » 26 Jan 2022, 09:01

Code: Select all

pToken := Gdip_Startup()

pBitmap := Gdip_CreateBitmapFromFile("home.png")
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)

Gdip_GetImageDimension(pBitmap, W, H)
Gui, +HwndLW +E0x80000 
Gui, Show, w%W% h%H%

UpdateLayeredWindow(LW, hdc,,, W, H)


pGraphics := Gdip_GraphicsFromHDC(hdc)
pBitmap := Gdip_CreateBitmapFromGraphics(pGraphics , W, H)
Gdip_SaveBitmapToFile(pBitmap , "home2.png", 100)
Return
The bitmap saved is empty.

Im using this function:

Code: Select all

Gdip_CreateBitmapFromGraphics(pGraphics, Width, Height) {
   pBitmap := 0
   E := DllCall("gdiplus\GdipCreateBitmapFromGraphics", "int", Width, "int", Height, "Ptr", pGraphics, "Ptr*", pBitmap)
   MsgBox, E: %E% ErrorLevel: %ErrorLevel% A_LastError: %A_LastError%   
Return pBitmap
}
Error level shows 0.

Is this function the same as this one?
https://docs.microsoft.com/en-us/windows/win32/api/gdiplusheaders/nf-gdiplusheaders-bitmap-bitmap(int_int_graphics)

I tested on AutoIt the same function and it does work:

Code: Select all

Func _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $hGraphics)
	Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipCreateBitmapFromGraphics", "int", $iWidth, "int", $iHeight, "handle", $hGraphics, _
			"handle*", 0)
	If @error Then Return SetError(@error, @extended, 0)
	If $aResult[0] Then Return SetError(10, $aResult[0], 0)

	Return $aResult[4]
EndFunc   ;==>_GDIPlus_BitmapCreateFromGraphics
Last edited by kauan014 on 26 Jan 2022, 12:02, edited 2 times in total.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to create a bitmap from graphics?

Post by iseahound » 26 Jan 2022, 10:32

Please check the return value of DllCall and not the ErrorLevel. If it is not zero then there is an error.

A Graphics object is a write only surface. To my understanding what you are doing makes no sense, as the created Bitmap should also be a write only surface and does not support reads.

To accomplish what you are trying to do, why not use the CreatebitmapfromHbitmap function?

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: How to create a bitmap from graphics?

Post by swagfag » 26 Jan 2022, 11:38

the GDI+ Graphics object is empty, and so too is the resulting GDI+ Bitmap object ure extracting from it. u arent drawing on the Graphics anywhere in the code. all uve done is create one based on some Device Context's properties

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

Re: How to create a bitmap from graphics?

Post by Hellbent » 26 Jan 2022, 11:54

Perhaps something like this.

**Note** I use my own class to create my layered window, you can use your own code to create / update your layered window and get the same results.

Code: Select all


;***************************************************************************************************
#Include, GDIP.ahk
;***************************************************************************************************
#SingleInstance, Force
pToken := Gdip_Startup()

;create a bitmap from a file
pBitmap := Gdip_CreateBitmapFromFile("home.png")

;Create a layered window and draw the image bitmap on to it.
Gui1 := New PopUpWindow( { AutoShow: 1 , X: "Center" , Y: "Center" , W: GDIP_GETIMAGEWIDTH( pBitmap ) , H: GDIP_GETIMAGEHeight( pBitmap ) , Options: " -DPIScale +AlwaysOnTop " } )
Gui1.DrawBitmap( pBitmap , { X: 0 , Y: 0 , W: Gui1.W , H: Gui1.H } , 1 , 1 )

;create a pBitmap from the layered window hBitmap 
pBitmap := GDIP_CreatebitmapfromHbitmap( Gui1.HBM )

;Save the new pBitmap to file.
Gdip_SaveBitmapToFile(pBitmap , "home2.png", 100)

return
GuiClose:
GuiContextMenu:
*ESC::ExitApp

;~ RALT::PopUpWindow.Helper() 	;A tool that contains a clip for every function in the class.

;####################################################################################################################################################################################
;####################################################################################################################################################################################
;###############################################################	  Layered Window Class	    #####################################################################################
;####################################################################################################################################################################################
;####################################################################################################################################################################################
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
		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 ]
		
	}
}/code]

kauan014
Posts: 55
Joined: 18 Feb 2021, 20:03

Re: How to get a bitmap from a hdc?

Post by kauan014 » 26 Jan 2022, 11:57

iseahound
Tthe Dllcal returned 0.

swagfag
It was a typo in the name of the variable, I fixed it

Code: Select all

pGraphics := Gdip_GraphicsFromHDC(hdc)
pBitmap := Gdip_CreateBitmapFromGraphics(pGraphics , W, H)
There is a value in the pBitmap .

I also tried:

Code: Select all

pGraphics := Gdip_GraphicsFromHDC(hdc)
hBitmap   := Gdip_CreateBitmapFromGraphics(G, W, H)
pBitmap   := Gdip_CreateBitmapFromHBITMAP(hBitmap)
But in this case pBitmap becames 0.


If i dont have the hBitmap anymore and just the hdc, how I could get the hBitmapthat's inside of this hdc?

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get a bitmap from a hdc?

Post by iseahound » 26 Jan 2022, 12:09

If you have a device context you can retrieve the hBitmap with GetCurrentObject.

Code: Select all

from_dc(image) {
      if !(hbm := DllCall("GetCurrentObject", "ptr", image, "uint", 7))
         throw Exception("The device context has no bitmap selected.")
      return this.from_hBitmap(hbm)
   }
Some other ideas: Save the pBits from CreateDIBSection and create a bitmap from Scan0.

kauan014
Posts: 55
Joined: 18 Feb 2021, 20:03

Re: How to get a bitmap from a hdc?

Post by kauan014 » 26 Jan 2022, 12:13

The function from_hBitmap is just converting the hbitmap to bitmap?
Last edited by kauan014 on 26 Jan 2022, 12:38, edited 1 time in total.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get a bitmap from a hdc?

Post by iseahound » 26 Jan 2022, 12:25

eh. Here's a working version:

Code: Select all

#include <Gdip_ALL>

pToken := Gdip_Startup()

pBitmap := Gdip_CreateBitmapFromFile("media\Lenna.png")
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hBitmap)

Gdip_GetImageDimensions(pBitmap, W, H)
Gui, +HwndLW +E0x80000 
Gui, Show, w%W% h%H%

UpdateLayeredWindow(LW, hdc,,, W, H)

hBitmap2 := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap2)
Gdip_SaveBitmapToFile(pBitmap, "home2.png", 100)
Return

kauan014
Posts: 55
Joined: 18 Feb 2021, 20:03

Re: How to get a bitmap from a hdc?

Post by kauan014 » 26 Jan 2022, 12:28

The hbm returned from GetCurrentObject doesn't store transparency? (i tested with a hBitmap containing transparency)

Code: Select all

hbm2    := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7)
;pBitmap :=Gdip_CreateBitmapFromHBITMAP(hbm2)              ; <---- works
pBitmap := Gdip_CreateARGBBitmapFromHBITMAP(hbm2)      ; <------ dont
Gdip_SaveBitmapToFile(pBitmap, "home2.png", 100)
I tried to run your Gdip_CreateARGBBitmapFromHBITMAP to convert the hbm to pbitmap but it saved a blank bitmap.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get a bitmap from a hdc?

Post by iseahound » 26 Jan 2022, 12:31

This one should fix the memory leaks

Code: Select all


#include <Gdip_ALL>

pToken := Gdip_Startup()

; Part 1 - Display image
pBitmap := Gdip_CreateBitmapFromFile("media\Lenna.png")
hBitmap := Gdip_CreateHBITMAPFromBitmap(pBitmap)
hdc := CreateCompatibleDC()
SelectObject(hdc, hBitmap)
Gdip_DisposeImage(pBitmap)

Gdip_GetImageDimensions(pBitmap, W, H)
Gui, +HwndLW +E0x80000 
Gui, Show, w%W% h%H%

UpdateLayeredWindow(LW, hdc,,, W, H)

; Part 2 - Save File and clean up.

obm := DllCall("CreateBitmap", "int", 0, "int", 0, "uint", 1, "uint", 1, "ptr", 0, "ptr")
hBitmap2 := SelectObject(hdc, obm)
pBitmap2 := Gdip_CreateBitmapFromHBITMAP(hBitmap2)
Gdip_SaveBitmapToFile(pBitmap2, "home2.png", 100)
Gdip_DisposeImage(pBitmap2)
DeleteObject(hBitmap2)
DeleteDC(hdc)
Return
I think I wrote two functions: CreateARGBBitmapfromhbitmap and createargbhbitmapfrombitmap. I don't have the latest copy of Gdip_all with my additions (LOL) so make sure you create a ARGB HBITMAP by replacing Gdip_CreateHBITMAPFromBitmap and Gdip_CreateBitmapFromHBITMAP with my versions.

kauan014
Posts: 55
Joined: 18 Feb 2021, 20:03

Re: How to get a bitmap from a hdc?

Post by kauan014 » 26 Jan 2022, 13:07

The hbitmap stored in the hdc was created with the function below hBitmapTrans.
Gdip_CreateARGBBitmapFromHBITMAP runs ok and return a bitmap, however its blank.


I'm storing somehBitmaps in memory as this way reduce the use o CPU when playing some animations as I skip the entire process of loading again, converting, adding effects, etc
Do you know any way to reduce the size of them when stored in the memory? It's using too much ram.

Code: Select all

hbm2 := DllCall("GetCurrentObject", "ptr", hdc, "uint", 7)
pBitmap := Gdip_CreateARGBBitmapFromHBITMAP(hbm2)
Gdip_SaveBitmapToFile(pBitmap, "wtf444.png", 100)

hBitmapTrans(pBitmap) {

   Gdip_GetImageDimension(pBitmap, CW, CH)
   FileAppend, CW: %CW% CH: %CH% `n,*

   VarSetCapacity(BITMAPINFO, 40, 0)
   pBMI   := &BITMAPINFO
   Stride := CW*4
   Bpp    := 32
   PARGB  := 925707

   NumPut(Bpp, NumPut(1,NumPut(CH,NumPut(CW,NumPut(40,pBMI+0,"Int"),"Int"),   "Int"),"Short"),"Short")
   hBM := DllCall("gdi32.dll\CreateDIBSection", "Ptr",0, "Ptr",pBMI, "Int",0,    "PtrP",pBits, "Ptr",0, "Int", 0, "Ptr")

   VarSetCapacity( BitmapData, A_PtrSize = 8 ? 32 : 24, 0 )
   NumPut( 0 - Stride, BitmapData, 8, "Int" )
   NumPut( pBits + ( Stride * CH ) - Stride, BitmapData, 16, "Ptr" ) 
   ; 0x5    =ImageLockModeRead|ImageLockModeUserInputBuf
   DllCall("gdiplus.dll\GdipBitmapLockBits", "Ptr", pBitmap, "Ptr",0, "Int",0x5,  "Int", PARGB, "Ptr", &BitmapData)
   DllCall("gdiplus.dll\GdipBitmapUnlockBits", "Ptr", pBitmap, "Ptr",&BitmapData)

   ; Free resource.
   CM := BITMAPINFO := BitmapData := ""

   return hBm
}

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
}

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get a bitmap from a hdc?

Post by iseahound » 26 Jan 2022, 14:49

Perhaps you should just use ImagePut I wrote it to avoid headaches like this. It looks like hBitmapTrans is written by SKAN, since I recognize his style, and the CreateARGB is probably a modified version of my original by robodesign.

https://github.com/iseahound/ImagePut

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get a bitmap from a hdc?

Post by iseahound » 26 Jan 2022, 19:22

Yeah I'm going to have a word with whoever butchered my function - they foolishly replaced

Code: Select all

      ; Create a Scan0 buffer pointing to pBits. The buffer has pixel format pARGB.
      VarSetCapacity(Rect, 16, 0)            ; sizeof(Rect) = 16
         NumPut(  width, Rect,  8,   "uint") ; Width
         NumPut( height, Rect, 12,   "uint") ; Height
with CreateRectF, which causes the function to fail, because I've specified an unsigned int, not a float. This makes me sad. :cry:

In addition, you cannot use GetCurrentObject and should use SelectObject instead, as a hbitmap cannot be selected onto more than one device context. This is the first time I've seen someone do such a thing, so I've added an error message to ImagePut.

If you used ImagePut, all this dealing with GDI+ just goes away and becomes:

Code: Select all

#include ImagePut.ahk
hdc := ImagePutDC("cats.jpg")
ImagePutFile(hdc, "output\")
ImageDestory(hdc)
This is the proper Gdip_CreateARGBBitmapFromHBITMAP.
This is the proper Gdip_CreateARGBHBITMAPFromBitmap.

You can also find an older version here https://github.com/mmikeww/AHKv2-Gdip/blob/master/Gdip_All.ahk

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: How to get a bitmap from a hdc?

Post by robodesign » 29 Jan 2022, 04:57

Hello!

I am that guy and apologies for the bug.

But I am not yet sure if everyone has the latest version:

https://github.com/marius-sucan/AHK-GDIp-Library-Compilation/blob/master/ahk-v1-1/Gdip_All.ahk

Code: Select all

CreateRectF(ByRef RectF, x, y, w, h, dtype:="float", ds:=4) {
   VarSetCapacity(RectF, ds*4)
   NumPut(x, RectF, 0,    dtype), NumPut(y, RectF, ds,   dtype)
   NumPut(w, RectF, ds*2, dtype), NumPut(h, RectF, ds*3, dtype)
}
I call that function using these params: CreateRectF(Rect, 0, 0, width, height, "uint") from Gdip_CreateARGBBitmapFromHBITMAP(). I am not using float, but uint.

I do not see any problem. It should yield the same thing as in the original function, same rect.

Please correct me if I am wrong. Thank you .

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: How to get a bitmap from a hdc?

Post by robodesign » 30 Jan 2022, 13:56

@iseahound . I see you are not replying. But, at least, I have the courtesy to get back to you. I have tested both functions as they are in my GDI+ library edition , and both work. Please do not haste next time. I have not broken your functions. Your claim is unfounded, perhaps you were just tired, and i hope you are doing better now.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

iseahound
Posts: 1434
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get a bitmap from a hdc?

Post by iseahound » 30 Jan 2022, 14:34

You do realize the F in CreateRectF stands for float? Why are you renaming functions?

Why isn't CreateRect being used? Why delete and overload existing functions from your version of GDI+, when you advertise it as an extended version of the original?

Code: Select all

; Function           CreateRectF
; Description        Creates a RectF object, containing a the coordinates and dimensions of a rectangle
The Gdip_all.ahk file for AHK v1.1 should be compatible with projects already relying on the original edition. In other words, it is backwards compatible.
If the original CreateRect is gone, how is that backwards compatible?

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: How to get a bitmap from a hdc?

Post by robodesign » 30 Jan 2022, 15:29

I am glad you are quick to reply now, even if you diverge from the initial problem ;-). I find it commendable and laudable you have found the source of your initial faulty statements regarding my library/code.

However , the initial Gdip_All.ahk had only one call to CreateRect(), in the LockBits function. I took the liberty of removing it , because it is a helper function, used only once, in the entirety of the initial code. I challenge you find that one person who used it a lot ;-).

And yes, I overloaded the CreateRectF() function, to make it more reusable. It does not break backwards compatibility. Unless, we define backwards compatibility as «no new parameters allowed for old functions». But, in my world, i do not use that definition ;-).

And yes, the F stood for Float, but I feel it could stand for more, however I assume it would be indecorous of me to spell it out.

Best regards, Marius.




iseahound wrote:
30 Jan 2022, 14:34
You do realize the F in CreateRectF stands for float? Why are you renaming functions?

Why isn't CreateRect being used? Why delete and overload existing functions from your version of GDI+, when you advertise it as an extended version of the original?

Code: Select all

; Function           CreateRectF
; Description        Creates a RectF object, containing a the coordinates and dimensions of a rectangle
The Gdip_all.ahk file for AHK v1.1 should be compatible with projects already relying on the original edition. In other words, it is backwards compatible.
If the original CreateRect is gone, how is that backwards compatible?
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

Post Reply

Return to “Ask for Help (v1)”