繁体   English   中英

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

[英]How to add/get image data in the OS clipboard using Python?

我有一些编辑图像文件的 Python 代码,想知道如何
将图像数据添加到操作系统剪贴板并从那里获取。

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

我的 Python 版本是 Windows 上的 3.x 但答案需要是跨平台的
(适用于不同的操作系统)并且还应该支持其他 Python 版本,如 2.x。
我认为它应该只使用内置的 Python 模块,并且代码不应太复杂(或对其作用进行解释)。 它可以是 Python 模块,因为这些文件可以包含在与可移植程序代码相同的文件夹中以避免安装。

还有一些与此相关的问题可能适用于图像,但它们仅支持单个操作系统。 最好的是在 Python3 中将图像复制到剪贴板,使用 PIL 和 win32clipboard 在 python 中将图像写入 Windows 剪贴板? .
那里描述的方法(仅适用于 Windows)似乎使用以下步骤:

  • 获取图像的原始二进制数据 - 该方法使用 Python Imaging 加载图像文件
    库 ( PIL/Pillow ) 模块,因为它具有稍后使用的其他处理功能,在一个简单的
    和流行的标准 API。 这可以用不同的模块来完成(例如Pygame )。
  • 使用内置io创建文件对象变量(用于内存输入/输出流)
    模块。 对于 Python 2.x,使用from cStringIO import StringIO但对于 Python 3,
    使用了更好的io.BytesIO二进制流对象类型 - 旧的现在只允许文本。
  • 以BMP(Windows Bitmap/Device Independent Bitmap)文件格式保存图像数据,
    到上一步中的文件对象变量。 使用PIL/Pillow先转换的方法
    此数据与包含它的变量上的.convert("RGB")
  • 获取文件对象变量内存缓冲区的全部内容作为二进制数据( bytes对象),
    从14位开始切片,去掉BMP/DIB文件格式的14字节头,然后保存
    作为变量。 该方法表示此数据的切片适用于 32 位或 64 位系统,但
    需要 Windows 剪贴板 API,因此不适用于不同的文件格式。
  • 关闭内存缓冲区并将上一步的图像数据复制到剪贴板。
    该方法使用扩展模块的win32clipboard部分在 Windows 上执行此操作 -
    它打开剪贴板以供使用,清除它,将其值设置为来自
    上一步(使用 BMP/DIB 类型)然后关闭打开的剪贴板。

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

我不认为你可以在没有外部模块的情况下与剪贴板进行交互。

剪贴板 API 与不同的操作系统不同。

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

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

xerox库简单且功能强大。

这是一个基于此答案的 Python 函数, 使用Tkinter替换/返回剪贴板文本。

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

此方法创建一个快速隐藏的窗口,该窗口很快关闭,因此
那应该不是问题。 此外,它只支持在
剪贴板,而不是我在上面的问题中要求的图像。

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

我只显示得到
此示例使用内置的 Tkinter 模块从CLIPBOARD获取图像数据。
仅在Linux上测试,但应该是跨平台解决方案。

在此处输入图片说明 在此处输入图片说明

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


核心点:您必须使用 MIME-Type 来请求图像。

.clipboard_get(type='image/png')

使用应用程序、 GIMPPyCharm 'GIF''PNG''JPEG'作为源图像数据。 如果源应用程序支持,则使用type='image/png'您始终可以获得'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

正如马丁所说——

Pyperclip 绝对是一个不错的选择,而且效果很好。

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

它就像下面的 3 行一样简单,

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM