BITMAP class? Topic is solved

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
iseahound
Posts: 1444
Joined: 13 Aug 2016, 21:04
Contact:

BITMAP class?

Post by iseahound » 23 May 2020, 18:19

Would it be possible to create a bitmap class using the new BufferAlloc syntax? I'd imagine that a GDI+ Bitmap class could be done. Would probably require:
  • Calling BufferAlloc() first and returning a pointer.
  • Using that pointer as the Scan0 inside the BitmapData (16) of a GdipBitmapLockBits call. (0x7)
  • And overriding the meta functions such as __Item to perform NumGet on bitmap[x, y] pixel values.
The weird part is the whack-a-mole between LockBits and UnlockBits. Because when the object is transported into a GDI+ function it should unlock the bits, and when it is being used in AHK it should lock the bits. So perhaps calling bitmap.ptr (Scan0, or the top left pixel of the bitmap) would lock the bits and calling bitmap.pBitmap would unlock the bits. Likewise overriding __Item would be needed to enable pixel access in the form of bitmap[x][y].

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

Re: BITMAP class?  Topic is solved

Post by swagfag » 01 May 2021, 16:00

im rusty on gdi and i dont recall what exactly goes into locking bits, but the following pattern should be applicable either way

Code: Select all

#Requires AutoHotkey v2.0-a133-9819cb2d

class Bitmap
{
	; statics are for internal use only; dont call.
	; these are here to provide a place for fetching
	; method references and reduce duplication
	; but u could implement something else instead, too

	; assume .LockBits() has been called
	static __Item_Get_Locked(x, y) {
		return 0xFF00FF ; some color ud get from running NumGet
	}

	; assume .LockBits() has been called
	static __Item_Set_Locked(value, x, y) {
		return value ; some color ud set NumPut
	}

	; assume bits are unlocked
	static __Item_Get_Unlocked(x, y) {
		; the first time 'Bmp[x, y]' is invoked in AHK code, 
		; "when it is being used in AHK it should lock the bits"
		this.LockBits()

		return this[x, y] ; invokes the now-replaced, unchecked procedure
	}

	; assume bits are unlocked
	static __Item_Set_Unlocked(value, x, y) {
		this.LockBits()
		
		return this[x, y] := value
	}

	__New(w, h) {
		this.Buf := Buffer(w * h * 32)
		this.IsLocked := false

		; have to set up metaitem in the constructor here,
		; since the object doesnt yet have one
		static PropDesc := {Get: Bitmap.__Item_Get_Unlocked, Set: Bitmap.__Item_Set_Unlocked}
		this.DefineProp('__Item', PropDesc)
	}

	; assume "when the object is transported into a GDI+ function it should unlock the bits"
	; to be true, since something(eg DllCall) is querying the .Ptr property
	Ptr {
		get {
			if this.IsLocked
				this.UnlockBits()

			return this.Buf.Ptr ; return the ptr of the internal buffer backing the bitmap
		}

		set {
			if this.IsLocked
				this.UnlockBits()

			return this.Buf.Ptr := value
		}

	; same pattern as for __Item can be applied instead to get rid of the if-checking
	}

	; avoid defining Bitmap.Prototype.__Item
	; __Item[x, y] {
	; 	...
	; }

	LockBits() {
		if this.IsLocked ; do nothing if already locked
			return

		this.IsLocked := true

		; replace metaitem with an unchecked version of the method
		; this saves u having to check a flag(eg .IsLocked) every time
		; which would result in reduced performance, since __Item would
		; most often be used in hotloops and ud be wasting cycles on what
		; u already know to be true
		static PropDesc := {Get: Bitmap.__Item_Get_Locked, Set: Bitmap.__Item_Set_Locked}

		; important to define the instance method on the instance itself!,
		; instead of on Bitmap.Prototype (ie 'this.Base.DefineProp...'), 
		; since multiple bitmaps could be instantiated at a time and we 
		; want them to keep track of their locked/unlock states themselves
		this.DefineProp('__Item', PropDesc)

		MsgBox 'bits are LOCKED'
	}

	UnlockBits() {
		if !this.IsLocked ; do nothing if already unlocked
			return

		this.IsLocked := false

		static PropDesc := {Get: Bitmap.__Item_Get_Unlocked, Set: Bitmap.__Item_Set_Unlocked}
		this.DefineProp('__Item', PropDesc)
		
		MsgBox 'bits are UNlocked'
	}
}

Bmp := Bitmap(100, 200)
MsgBox Bmp[15, 60] ; automatically locks
MsgBox Bmp[15, 60] := 0x0000FF ; automatically locks(unless already locked)
MsgBox gdiplusFunction(Bmp) ; automatically unlocks
MsgBox Bmp[15, 60] ; automatically re-locks

gdiplusFunction(BitmapInstance) {
	; dllcalls taking Ptr types, accept Object and query their .Ptr property automatically
	; DllCall(.., 'Ptr', BitmapInstance, ...)

	return BitmapInstance.Ptr ; so simulate that behavior here
}

Post Reply

Return to “Ask for Help (v2)”