【问题标题】:Copy PIL/PILLOW Image to Windows Clipboard将 PIL/PILLOW 图像复制到 Windows 剪贴板
【发布时间】:2014-01-23 21:16:28
【问题描述】:

我见过this question,我遵循每一步,更改代码以满足我的要求,即 Python3、Pillow 和 ctypes。库越少越好。

import ctypes
from PIL import ImageGrab, Image
from io import BytesIO

user32 = ctypes.windll.user32

img = ImageGrab.grab()
output = BytesIO()
img.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]
output.close()

user32.OpenClipboard()
user32.EmptyClipboard()
user32.SetClipboardData(user32.CF_DIB, data)
user32.CloseClipboard()

这是从我的脚本中剥离的代码,我认为,与移植到我的要求的问题中的代码相同。执行时,它应该将当前桌面复制到剪贴板。我得到了这个:

File "C:\Users\Gcq\Documents\python\Screen\Screen.py", line 132, in shot
    user32.OpenClipboard()
ValueError: Procedure probably called with not enough arguments (4 bytes missing)

很抱歉,我在这里问了这么一个(可能)简单的问题,但我真的不知道什么是失败的,ctypes 不是我的事。

【问题讨论】:

    标签: python winapi python-imaging-library ctypes pillow


    【解决方案1】:

    该示例使用pywin32,它是围绕 Win32 API 的 Python 包装器,它隐藏了一些低级别的细节,如果你想使用 ctypes,你需要自己注意。

    这是使用ctypes 的方法,它添加了创建全局分配缓冲区并将data 复制到该缓冲区的功能:

    #!python
    
    from PIL import Image
    #from cStringIO import StringIO
    from io import BytesIO
    from ctypes import *
    from ctypes.wintypes import *
    
    HGLOBAL = HANDLE
    SIZE_T = c_size_t
    GHND = 0x0042
    GMEM_SHARE = 0x2000
    
    GlobalAlloc = windll.kernel32.GlobalAlloc
    GlobalAlloc.restype = HGLOBAL
    GlobalAlloc.argtypes = [UINT, SIZE_T]
    
    GlobalLock = windll.kernel32.GlobalLock
    GlobalLock.restype = LPVOID
    GlobalLock.argtypes = [HGLOBAL]
    
    GlobalUnlock = windll.kernel32.GlobalUnlock
    GlobalUnlock.restype = BOOL
    GlobalUnlock.argtypes = [HGLOBAL]
    
    CF_DIB = 8
    
    OpenClipboard = windll.user32.OpenClipboard
    OpenClipboard.restype = BOOL 
    OpenClipboard.argtypes = [HWND]
    
    EmptyClipboard = windll.user32.EmptyClipboard
    EmptyClipboard.restype = BOOL
    EmptyClipboard.argtypes = None
    
    SetClipboardData = windll.user32.SetClipboardData
    SetClipboardData.restype = HANDLE
    SetClipboardData.argtypes = [UINT, HANDLE]
    
    CloseClipboard = windll.user32.CloseClipboard
    CloseClipboard.restype = BOOL
    CloseClipboard.argtypes = None
    
    #################################################
    
    image = Image.new("RGB", (200, 200), (255, 0, 0))
    
    #output = StringIO()
    output = BytesIO()
    image.convert("RGB").save(output, "BMP")
    data = output.getvalue()[14:]
    output.close()
    
    hData = GlobalAlloc(GHND | GMEM_SHARE, len(data))
    pData = GlobalLock(hData)
    memmove(pData, data, len(data))
    GlobalUnlock(hData)
    
    OpenClipboard(None)
    EmptyClipboard()
    SetClipboardData(CF_DIB, pData)
    CloseClipboard()
    

    【讨论】:

      【解决方案2】:

      哇。显然,与ctypes 相比,win32clipboard 库确实简化了一些事情。你试图简单地用另一个替换一个是很不正确的。

      所以我启动了我的 Windows 虚拟机,安装了 Pillow 并重写了你的程序,向两个 other answers 学习:

      import io
      
      import ctypes
      msvcrt = ctypes.cdll.msvcrt
      kernel32 = ctypes.windll.kernel32
      user32 = ctypes.windll.user32
      
      from PIL import ImageGrab
      
      img = ImageGrab.grab()
      output = io.BytesIO()
      img.convert('RGB').save(output, 'BMP')
      data = output.getvalue()[14:]
      output.close()
      
      CF_DIB = 8
      GMEM_MOVEABLE = 0x0002
      
      global_mem = kernel32.GlobalAlloc(GMEM_MOVEABLE, len(data))
      global_data = kernel32.GlobalLock(global_mem)
      msvcrt.memcpy(ctypes.c_char_p(global_data), data, len(data))
      kernel32.GlobalUnlock(global_mem)
      user32.OpenClipboard(None)
      user32.EmptyClipboard()
      user32.SetClipboardData(CF_DIB, global_mem)
      user32.CloseClipboard()
      

      【讨论】:

      • +1。更一般地说,只是盲目地从 Win32 DLL 中调用函数绝不是一个好主意。至少它实际上不会像在 POSIX 上那样经常崩溃……但你确实需要在 MSDN 上查看函数,发送正确的参数,并经常设置argtypes 和/或restype,在你之前可以用。
      • 是的,我现在觉得自己很愚蠢。有用!现在我有另一个问题:我无法粘贴图像。至少 Word 不接受。
      • @gcq 仍在尝试解决。显然它比你想象的要困难得多。
      • global_data 是一个指针,句柄 global_mem 也是一个指针(指向内部数据结构;它不是句柄表的小索引)。您需要为这些声明restype,否则您的代码在 Win64 上不正确。 ctypes 默认将数字转换为 C int。另外,如果你不使用c_void_p手动换行,你也需要设置argtypes
      • 嗯,我绝对不是这方面的专家。 @gcq,您可能应该使用其他答案(现在已针对 Python 3 修复)。
      猜你喜欢
      • 2016-03-29
      • 2019-10-30
      • 2023-03-11
      • 1970-01-01
      • 2011-04-19
      • 2019-12-26
      • 2021-07-27
      • 2013-07-14
      • 1970-01-01
      相关资源
      最近更新 更多