BitmapToBuffer() - Encapsulate a pBitmap to allow pixel := Bitmap[x,y]

Share the finished AutoHotkey v2 Scripts and libraries you made here. Please put the current version of AutoHotkey v2 you used in Square Brackets at the start of the topic title.
iseahound
Posts: 610
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

BitmapToBuffer() - Encapsulate a pBitmap to allow pixel := Bitmap[x,y]

Post by iseahound » 13 Jun 2020, 13:04

Gdip_All is broken at the moment, but all you need is a pToken and a pBitmap

Code: Select all

/*
pToken := gdip_startup()
*/

#include ImagePut.txt

ImagePut.gdiplusstartup()
pBitmap := ImagePutBitmap([0,0,100,100])

buffer := BitmapToBuffer(pBitmap)
MsgBox buffer.Lock()
MsgBox buffer[0, 50]
MsgBox buffer.UnLock()

BitmapToBuffer(pBitmap) {
   DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0)
   DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0)

   buffer := BufferAlloc(4 * width * height)
   buffer.pBitmap := pBitmap

   buffer.DefineMethod("Lock", (self) => (
      DllCall("gdiplus\GdipGetImageWidth", "ptr", pBitmap, "uint*", width:=0),
      DllCall("gdiplus\GdipGetImageHeight", "ptr", pBitmap, "uint*", height:=0),

      self.width := width, self.height := height,

      Rect := BufferAlloc(16, 0),             ; sizeof(Rect) = 16
         NumPut(  "uint",   width, Rect,  8), ; Width
         NumPut(  "uint",  height, Rect, 12), ; Height

      self.BitmapData := BufferAlloc(16+2*A_PtrSize, 0),    ; sizeof(BitmapData) = 24, 32
         NumPut(  "uint",      width, self.BitmapData,  0), ; Width
         NumPut(  "uint",     height, self.BitmapData,  4), ; Height
         NumPut(   "int",  4 * width, self.BitmapData,  8), ; Stride
         NumPut(   "int",   0x26200A, self.BitmapData, 12), ; PixelFormat
         NumPut(   "ptr",   self.ptr, self.BitmapData, 16), ; Scan0

      DllCall("gdiplus\GdipBitmapLockBits"
               ,    "ptr", self.pBitmap
               ,    "ptr", Rect
               ,   "uint", 7               ; ImageLockMode.UserInputBuffer | ImageLockMode.ReadOnly
               ,    "int", 0x26200A        ; Format32bppArgb
               ,    "ptr", self.BitmapData)
   ))

   buffer.DefineMethod("Unlock", (self) => (
      _error := DllCall("gdiplus\GdipBitmapUnlockBits", "ptr", self.pBitmap, "ptr", self.BitmapData),
      self.BitmapData := "",
      _error
   ))

   buffer.DefineProp("__Item", {get: (self, x:=0, y:=0) => (
      Format("{:x}", NumGet(self.ptr + 4*(y*width + x), "uint"))
   )})

   return buffer
}
This code currently takes a pBitmap and returns a Buffer object with
  • a Lock() function equal to Gdip_LockBits
  • a Unlock() function equal to Gdip_UnlockBits
    and the ability to
  • get a pixel := Bitmap[x, y]
Currently it doesn't have smart switching properties, meaning calling bitmap.ptr or bitmap[x,y] doesn't automatically call Lock(). The user has to do that manually. Likewise calling Bitmap.pBitmap should call Unlock() if BitmapData is set.

This is proof-of-concept at this point, feel free to adapt it. I will be away for some time.

Return to “AutoHotkey v2 Scripts and Functions”