You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ctypes将HBITMAP句柄转换为PIL或其他格式图像?

将HBITMAP转换为PIL图像

你拿到的整数是Windows的HBITMAP句柄,要转换成PIL图像,需要调用Windows GDI API提取位图的像素数据,再转成PIL支持的格式。以下是完整实现代码:

import ctypes
from ctypes import wintypes
from PIL import Image

# 定义Windows API所需的结构体
class BITMAP(ctypes.Structure):
    _fields_ = [
        ("bmType", wintypes.LONG),
        ("bmWidth", wintypes.LONG),
        ("bmHeight", wintypes.LONG),
        ("bmWidthBytes", wintypes.LONG),
        ("bmPlanes", wintypes.WORD),
        ("bmBitsPixel", wintypes.WORD),
        ("bmBits", wintypes.LPVOID)
    ]

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 BITMAPINFO(ctypes.Structure):
    _fields_ = [
        ("bmiHeader", BITMAPINFOHEADER),
        ("bmiColors", wintypes.DWORD * 3)  # 24位真彩色无需调色板,此处占位
    ]

# 加载Windows系统库
gdi32 = ctypes.WinDLL("gdi32")
user32 = ctypes.WinDLL("user32")

# 声明函数参数与返回值类型
gdi32.GetObjectW.argtypes = [wintypes.HBITMAP, wintypes.INT, ctypes.LPVOID]
gdi32.GetObjectW.restype = wintypes.INT

gdi32.GetDIBits.argtypes = [
    wintypes.HDC, wintypes.HBITMAP, wintypes.UINT, wintypes.UINT,
    ctypes.LPVOID, ctypes.LPVOID, wintypes.UINT
]
gdi32.GetDIBits.restype = wintypes.INT

gdi32.DeleteObject.argtypes = [wintypes.HGDIOBJ]
gdi32.DeleteObject.restype = wintypes.BOOL

user32.GetDC.argtypes = [wintypes.HWND]
user32.GetDC.restype = wintypes.HDC

user32.ReleaseDC.argtypes = [wintypes.HWND, wintypes.HDC]
user32.ReleaseDC.restype = wintypes.INT

# 加载目标DLL并调用接口
dllPath = "你的DLL路径"  # 替换为实际DLL路径
dll = ctypes.windll.LoadLibrary(dllPath)
dll.lmc1_GetPrevBitmap2.restype = wintypes.HBITMAP

hbitmap = dll.lmc1_GetPrevBitmap2(400, 400)
if not hbitmap:
    raise RuntimeError("获取位图失败")

try:
    # 获取位图基础信息
    bmp = BITMAP()
    if gdi32.GetObjectW(hbitmap, ctypes.sizeof(BITMAP), ctypes.byref(bmp)) == 0:
        raise RuntimeError("无法读取位图信息")

    width = bmp.bmWidth
    height = bmp.bmHeight
    bit_count = bmp.bmBitsPixel

    # 配置BITMAPINFO结构体
    bmi = BITMAPINFO()
    bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
    bmi.bmiHeader.biWidth = width
    bmi.bmiHeader.biHeight = -height  # 设为负数让像素数据从上到下排列,匹配PIL格式
    bmi.bmiHeader.biPlanes = 1
    bmi.bmiHeader.biBitCount = bit_count
    bmi.bmiHeader.biCompression = 0  # BI_RGB无压缩格式

    # 计算像素数据缓冲区大小
    buffer_size = ((width * bit_count + 31) // 32) * 4 * height
    pixel_buffer = ctypes.create_string_buffer(buffer_size)

    # 获取屏幕DC(GetDIBits需要DC上下文)
    hdc = user32.GetDC(None)
    if not hdc:
        raise RuntimeError("无法获取设备上下文")

    try:
        # 提取位图像素数据
        bits_copied = gdi32.GetDIBits(
            hdc, hbitmap, 0, height, pixel_buffer, ctypes.byref(bmi), 0
        )
        if bits_copied == 0:
            raise RuntimeError("无法提取像素数据")

        # 根据位深转换为PIL图像
        if bit_count == 24:
            # Windows 24位位图为BGR格式,需转换为PIL的RGB格式
            img = Image.frombuffer("RGB", (width, height), pixel_buffer, "raw", "BGR", 0, 1)
        elif bit_count == 32:
            # 32位位图为BGRA格式,转换为PIL的RGBA格式
            img = Image.frombuffer("RGBA", (width, height), pixel_buffer, "raw", "BGRA", 0, 1)
        else:
            raise NotImplementedError(f"暂不支持{bit_count}位的位图格式")

        # 可直接显示或保存图像
        img.show()
        # img.save("output.png")

    finally:
        # 释放DC上下文
        user32.ReleaseDC(None, hdc)

finally:
    # 释放HBITMAP句柄,避免内存泄漏
    gdi32.DeleteObject(hbitmap)

关键说明

  • 通过GetObjectW获取位图的宽、高、位深等核心参数
  • 使用GetDIBits将HBITMAP中的像素数据提取到内存缓冲区
  • Windows位图默认采用BGR/BGRA颜色顺序,而PIL使用RGB/RGBA,转换时需指定格式
  • 必须调用DeleteObject释放HBITMAP句柄,防止内存泄漏
  • 若位图为8位灰度等其他位深,需调整BITMAPINFO的调色板配置及PIL转换逻辑

内容的提问来源于stack exchange,提问作者jett chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 07:25:27