Page 1 of 1

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

Posted: 13 Jun 2020, 13:04
by iseahound
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.