I have PIL images that I am trying to convert to grayscale HBitmap in ctypes. I have minimal knowledge of ctypes, C, or dealing with HBITMAPs. I cobbled together code from various sources, such as
This is what I have so far. First, I initialized the required headers:
import ctypes
from ctypes import wintypes
class BITMAPINFOHEADER(ctypes.Structure):
_fields_ = [
('biSize', wintypes.DWORD),
('biWidth', wintypes.LONG),
('biHeight', wintypes.LONG),
('biPlanes', wintypes.WORD),
('biBitCount', wintypes.WORD),
('biCompression', wintypes.DWORD),
('biSizeImage', wintypes.DWORD),
('biXPelsPerMeter', wintypes.LONG),
('biYPelsPerMeter', wintypes.LONG),
('biClrUsed', wintypes.DWORD),
('biClrImportant', wintypes.DWORD),
]
class RGBQUAD(ctypes.Structure):
_fields_ = [
('rgbRed', ctypes.c_byte),
('rgbGreen', ctypes.c_byte),
('rgbBlue', ctypes.c_byte),
('rgbReserved', ctypes.c_byte),
]
class BITMAPINFO(ctypes.Structure):
_fields_ = [
('bmiHeader', BITMAPINFOHEADER),
('bmiColors', ctypes.POINTER(RGBQUAD))
]
w,h=image.size
bmi = BITMAPINFO()
bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
bmi.bmiHeader.biWidth = w
bmi.bmiHeader.biHeight = h
bmi.bmiHeader.biPlanes = 1
bmi.bmiHeader.biBitCount = 8
bmi.bmiHeader.biCompression = 0
bmi.bmiHeader.biSizeImage = 0
elems=(RGBQUAD*256)()
bmi.bmiColors=ctypes.cast(elems,ctypes.POINTER(RGBQUAD))
for i in range(256):
bmi.bmiColors[i].rgbRed=i
bmi.bmiColors[i].rgbGreen=i
bmi.bmiColors[i].rgbBlue=i
bmi.bmiColors[i].rgbReserved=0
Then, I created my hbitmap:
ctypes.windll.LoadLibrary('C:\Windows\System32\gdi32.dll')
gdi=ctypes.WinDLL('C:\Windows\System32\gdi32.dll')
hDC = gdi.CreateCompatibleDC(0)
try:
dataptr = ctypes.c_void_p()
result = gdi.CreateDIBSection(hDC, ctypes.byref(bmi), 0,
ctypes.byref(dataptr), None, 0)
hOldBitmap = gdi.SelectObject(hDC, result)
try:
buf = imagebytes
wintypes.memmove(dataptr, buf, len(buf))
finally:
gdi.SelectObject(hDC, hOldBitmap)
finally:
gdi.DeleteDC(hDC)
hbitmap = result
I am uploading these HBITMAPs to some projector via separate lines of code in Python. The HBITMAPs I created seem to work partially, in that I can successfully define spatial patterns to be projected. I have problems instead with getting graded pixel intensity. Specifically, pixels show up as black if I set values from 0-127, and white if I set values from 128-255, with no gradations. These lead to me suspect that it is a problem with setting the RGB color palette.
I have directly saved the PIL image files to .bmp and verified that they have graded intensity values. Perhaps it would be easier to troubleshoot if I had a way to also save the HBITMAP output at the end to .bmp, but at this stage I am only checking these HBITMAPs by directly uploading to my projector.
I have also tried screwing with the code that defines the color palette, for example:
bmi.bmiColors[i].rgbRed=9999
or:
bmi.bmiColors[i].rgbsRed=i
But none of these seem to have any effect on the output of my projector. I can still set images accurately, just with no graded pixel intensities.