I want to get the raw bytes of a BITMAPINFO
in python. This is my complete code:
import ctypes
from ctypes import wintypes
windll = ctypes.windll
user32 = windll.user32
gdi32 = windll.gdi32
class RECT(ctypes.Structure):
_fields_ = [
('left', ctypes.c_long),
('top', ctypes.c_long),
('right', ctypes.c_long),
('bottom', ctypes.c_long)
]
class BITMAPINFOHEADER(ctypes.Structure):
_fields_ = [
("biSize", wintypes.DWORD),
("biWidth", ctypes.c_long),
("biHeight", ctypes.c_long),
("biPlanes", wintypes.WORD),
("biBitCount", wintypes.WORD),
("biCompression", wintypes.DWORD),
("biSizeImage", wintypes.DWORD),
("biXPelsPerMeter", ctypes.c_long),
("biYPelsPerMeter", ctypes.c_long),
("biClrUsed", wintypes.DWORD),
("biClrImportant", wintypes.DWORD)
]
class RGBQUAD(ctypes.Structure):
_fields_ = [
("rgbBlue", wintypes.BYTE),
("rgbGreen", wintypes.BYTE),
("rgbRed", wintypes.BYTE),
("rgbReserved", ctypes.c_void_p)
]
class BITMAP(ctypes.Structure):
_fields_ = [
("bmType", ctypes.c_long),
("bmWidth", ctypes.c_long),
("bmHeight", ctypes.c_long),
("bmWidthBytes", ctypes.c_long),
("bmPlanes", wintypes.DWORD),
("bmBitsPixel", wintypes.DWORD),
("bmBits", ctypes.c_void_p)
]
whandle = 327756 # Just a handle of an open application
rect = RECT()
user32.GetClientRect(whandle, ctypes.byref(rect))
# bbox = (rect.left, rect.top, rect.right, rect.bottom)
hdcScreen = user32.GetDC(None)
hdc = gdi32.CreateCompatibleDC(hdcScreen)
hbmp = gdi32.CreateCompatibleBitmap(
hdcScreen,
rect.right - rect.left,
rect.bottom - rect.top
)
gdi32.SelectObject(hdc, hbmp)
PW_CLIENTONLY = 1
if not user32.PrintWindow(whandle, hdc, PW_CLIENTONLY):
raise Exception("PrintWindow failed")
bmap = BITMAP()
if not gdi32.GetObjectW(hbmp, ctypes.sizeof(BITMAP), ctypes.byref(bmap)):
raise Exception("GetObject failed")
class BITMAPINFO(ctypes.Structure):
_fields_ = [
("BITMAPINFOHEADER", BITMAPINFOHEADER),
("RGBQUAD", RGBQUAD * 1000)
]
bminfo = BITMAPINFO()
bminfo.BITMAPINFOHEADER.biSize = ctypes.sizeof(BITMAPINFOHEADER)
bminfo.BITMAPINFOHEADER.biWidth = bmap.bmWidth
bminfo.BITMAPINFOHEADER.biHeight = bmap.bmHeight
bminfo.BITMAPINFOHEADER.biPlanes = bmap.bmPlanes
bminfo.BITMAPINFOHEADER.biBitCount = bmap.bmBitsPixel
bminfo.BITMAPINFOHEADER.biCompression = 0
bminfo.BITMAPINFOHEADER.biClrImportant = 0
out = ctypes.create_string_buffer(1000)
if not gdi32.GetDIBits(hdc, hbmp, 0, bmap.bmHeight, None, bminfo, 0):
raise Exception("GetDIBits failed")
I need a way to know how long the array of RGBQUADS
has to be in the BITMAPINFO
struct and also the lenght of the out
buffer. The 1000
is in there as a placeholder.
gdi32.GetDIBits
fails with an access violation. I guess it's because i have to have the array and buffer with the correct lenght.
I post the whole source, because i don't know what's failing. Any help is appreciated.
UPDATE
- corrected
DWORD
s inBITMAP
beingWORD
s and a void pointer inRGBQUAD
to beBYTE
getting the size of image data:
def round_up32(n): multiple = 32 while multiple < n: multiple += 32 return multiple data_len = round_up32(bmap.bmWidth * bmap.bmBitsPixel) * bmap.bmHeight
Still getting access violation.
I also saw that there is no RGBQUAD array for 32-bit-per-pixel bitmaps. Is that true?