【发布时间】:2017-02-01 20:29:34
【问题描述】:
我有 PIL 图像,我正在尝试将其转换为 ctypes 中的灰度 HBitmap。我对 ctypes、C 或处理 HBITMAP 知之甚少。我拼凑了来自各种来源的代码,例如
这是我目前所拥有的。首先,我初始化了所需的标头:
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
然后,我创建了我的 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
我正在通过 Python 中的单独代码行将这些 HBITMAP 上传到某些投影仪。我创建的 HBITMAP 似乎部分起作用,因为我可以成功定义要投影的空间模式。我有问题,而不是获得分级像素强度。具体来说,如果我将值设置为 0-127,像素将显示为黑色,如果我将值设置为 128-255,则像素显示为白色,没有渐变。这些让我怀疑这是设置 RGB 调色板的问题。
我已将 PIL 图像文件直接保存为 .bmp 并验证它们具有分级强度值。如果我有办法将最后的 HBITMAP 输出保存到 .bmp,也许会更容易排除故障,但在这个阶段,我只是通过直接上传到我的投影仪来检查这些 HBITMAP。
我也尝试过修改定义调色板的代码,例如:
bmi.bmiColors[i].rgbRed=9999
或:
bmi.bmiColors[i].rgbsRed=i
但这些似乎都对我的投影仪的输出没有任何影响。我仍然可以准确地设置图像,只是没有分级像素强度。
【问题讨论】:
-
HBITMAP是一种结构数据类型,它不是一种文件格式。你能举一些例子或链接吗? -
抱歉,我只想说 HBITMAP 句柄,我通过 python 将它传递给我的投影仪系统。
-
“我无法分配调色板值” - 具体如何?它在运行时失败了吗?它成功了,但没有产生预期的结果吗?代码存在一些问题:您没有将 biCompression 成员设置为
BI_RGB(这是必需的)。您将 biSizeImage 设置为非零值,但它是错误的值,因为它没有考虑到扫描线与DWORD边界的对齐。然后,BITMAPINFO的大小是可变的(请参阅Why do some structures end with an array of size 1? 以获得解释)。 -
@IInspectable 我现在已将 biCompression 和 biSizeImage 都设置为 0。但是,我对 C++ 的了解太少,不知道如何继续:
BITMAPINFO。我知道 BITMAPINFO 由于 bmiColors 的大小可变(正确吗?)。这是否意味着我必须为 BITMAPINFO 正确分配内存?我不知道如何在 ctypes 中执行此操作,我找不到与 alloca() 或 offsetof() 对应的函数,正如我在您在 stackoverflow.com/questions/3142349/… 上的回答中看到的那样
标签: python winapi bitmap ctypes gdi