如何使用Python在OS剪贴板中添加/获取图像数据?

6 投票
5 回答
9629 浏览
提问于 2025-04-18 11:28

我有一些Python代码可以编辑图像文件,我想知道如何把图像数据放到操作系统的剪贴板上,并且从剪贴板中获取这些数据。

在寻找一个跨平台的解决方案来替换或获取剪贴板中的文本时,发现有很多简单的方法可以做到这一点(比如使用内置的Tkinter模块,配合一些代码)。
但是,这些方法只能处理纯文本,不能处理其他剪贴板数据,比如图像。

我使用的Python版本是3.x,操作系统是Windows,但我希望这个解决方案是跨平台的(可以在不同的操作系统上运行),而且也要支持其他Python版本,比如2.x。
我觉得应该只用Python内置的模块,代码也不应该太复杂(或者需要有解释说明它的功能)。可以做成一个Python模块,因为文件可以和可移植的程序代码放在同一个文件夹里,这样就不用安装了。

还有一些和这个问题相关的其他问题,可能适用于图像,但它们只支持特定的操作系统。比较好的有在Python3中复制图像到剪贴板用PIL和win32clipboard在Python中写入图像到Windows剪贴板
这些方法(仅适用于Windows)似乎使用了以下步骤:

  • 获取图像的原始二进制数据 - 这个方法使用Python图像库(PIL/Pillow)加载图像文件,因为它有其他后续处理功能,使用起来简单且流行。这也可以用其他模块来实现(比如Pygame)。
  • 创建一个文件对象变量(用于内存中的输入/输出流),使用内置的io模块。对于Python 2.x,使用from cStringIO import StringIO,而在Python 3中,使用更好的io.BytesIO二进制流对象类型 - 旧的只支持文本。
  • 将图像数据以BMP(Windows位图/设备无关位图)文件格式保存到上一步的文件对象变量中。使用PIL/Pillow的方法首先通过.convert("RGB")将数据转换到包含它的变量中。
  • 获取文件对象变量内存缓冲区的完整内容作为二进制数据(bytes对象),从位置14开始切片,以去掉BMP/DIB文件格式的14字节头,然后将其保存为一个变量。这个方法说这种数据切片在32位或64位系统上都有效,但需要Windows剪贴板API,所以不适用于其他文件格式。
  • 关闭内存缓冲区,并将上一步的图像数据复制到剪贴板。这个方法在Windows上使用win32clipboard扩展模块来实现 - 它打开剪贴板以供使用,清空剪贴板,将其值设置为来自上一步的图像数据变量(使用BMP/DIB类型),然后关闭打开的剪贴板。

另外,还有一个简单的跨平台剪贴板文本模块叫做Pyperclip,它只有一个文件,版本是1.5.6,可能有处理图像数据的代码。

5 个回答

-2

正如马丁所说——

Pyperclip绝对是个不错的选择,使用起来非常顺手。

我不知道为什么你不应该使用它。

它的用法简单到只需要下面的三行代码,

import pyperclip
pyperclip.copy('The text to be copied to the clipboard.')
paste= pyperclip.paste()
0

这里有一个基于这个回答的Python函数,它可以用来替换或返回剪贴板上的文本。

def use_clipboard(paste_text=None):
    import tkinter # For Python 2, replace with "import Tkinter as tkinter".
    tk = tkinter.Tk()
    tk.withdraw()
    if type(paste_text) == str: # Set clipboard text.
        tk.clipboard_clear()
        tk.clipboard_append(paste_text)
    try:
        clipboard_text = tk.clipboard_get()
    except tkinter.TclError:
        clipboard_text = ''
    r.update() # Stops a few errors (clipboard text unchanged, command line program unresponsive, window not destroyed).
    tk.destroy()
    return clipboard_text

这个方法会创建一个快速隐藏的窗口,然后很快关闭,所以这应该不是个问题。此外,它只支持在剪贴板中使用纯文本,而不支持我在上面问题中提到的图片。

0

xerox库既简单又强大。

0

我觉得你不能直接和剪贴板互动,必须用外部模块。

不同的操作系统有不同的剪贴板接口。

我建议你使用剪贴板模块。

https://pypi.python.org/pypi/clipboard/0.0.4

1

问题: 如何使用Python在操作系统的剪贴板中添加或获取图片数据?

这里我只展示获取的部分:
这个例子使用了内置的Tkinter模块来从CLIPBOARD获取图片数据。
只在Linux上测试过,但应该可以在不同平台上使用。

在这里输入图片描述 在这里输入图片描述

注意:显示的387x388 GIF的第一次粘贴需要4秒。


核心要点: 你需要使用MIME类型来请求图片。

.clipboard_get(type='image/png')

经过验证,使用'GIF''PNG''JPEG'作为源图片数据,应用程序包括GIMPPyCharm。使用type='image/png'时,如果源应用程序支持,你总是能获取到'PNG'类型的图片数据。


参考资料:

  • clippboard_get(type=<string>)

    从剪贴板中获取数据。类型指定数据返回的形式,应该是像STRING或FILE_NAME这样的原子名称。在现代X11系统中,类型默认是UTF8_STRING。


数据格式:

0x89 0x50 0x4e 0x47 0xd 0xa 0x1a 0xa 0x0 0x0 0x0 0xd 0x49 0x48 0x44

数据被分成用空格分隔的字段;每个字段被转换为其原子值,传输的是32位的原子值,而不是原子名称。

在去掉空格并用int(<field>, 0)转换后:

bytearray(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHD...')
<PIL.PngImagePlugin.PngImageFile image mode=P size=387x388 at 0xF555E20C>

异常情况: 如果没有任何选择,或者源应用程序不提供'image/png'

TclError:CLIPBOARD selection doesn't exist or form "image/png" not defined


import tkinter as tk
from PIL import Image, ImageTk
import io


class App(tk.Tk):
    def __init__(self):
        super().__init__()  # options=(tk.Menu,))
        self.menubar = tk.Menu()
        self.config(menu=self.menubar)
        self.menubar.add_command(label='paste', command=self.on_paste)
        
        self.label = tk.Label(self, text="CLIPBOARD image", font=("David", 18),
                              image='', compound='center')
        self.label.grid(row=0, column=0, sticky='w')

    def on_paste(self):
        self.label.configure(image='')
        self.update_idletasks()
        
        try:
            b = bytearray()
            h = ''
            for c in self.clipboard_get(type='image/png'):
                if c == ' ':
                    try:
                        b.append(int(h, 0))
                    except Exception as e:
                        print('Exception:{}'.format(e))
                    h = ''
                else:
                    h += c

        except tk.TclError as e:
            b = None
            print('TclError:{}'.format(e))
        finally:
            if b is not None:
                with Image.open(io.BytesIO(b)) as img:
                    print('{}'.format(img))
                    self.label.image = ImageTk.PhotoImage(img.resize((100, 100), Image.LANCZOS))
                    self.label.configure(image=self.label.image)

在Python 3.5中测试:'TclVersion': 8.6 'TkVersion': 8.6

撰写回答