6

I have some Python code that edits image files and would like to know how
to add image data to the Operating System clipboard and get it from there.

When searching for a cross-platform solution to replace or get clipboard text in Python,
there were many simple answers to do it (e.g. using the built-in Tkinter module with some code).
However, these methods could only use plain text, not other clipboard data like images.

My version of Python is 3.x on Windows but the answer needs to be cross-platform
(work on different operating systems) and should also support other Python versions like 2.x.
I think it should only use built-in Python modules and the code shouldn't be too complex (or have an explanation of what it does). It can be a Python module because the files can be included in the same folder as portable program code to avoid installing.

There are some other related questions to this one that probably work for images but they only support an individual operating system. The best were Copy image to clipboard in Python3 and Write image to Windows clipboard in python with PIL and win32clipboard?.
The methods described there (for Windows only) appear to use the following steps:

  • Get raw binary data of the image - the method loads an image file with the Python Imaging
    Library (PIL/Pillow) module because this has other processing features used later, in a simple
    and popular standard API. This could be done with a different module instead (e.g. Pygame).
  • Create a file object variable (for in-memory input/output streaming), using the built-in io
    module. For Python 2.x, from cStringIO import StringIO is used but with Python 3, the
    better io.BytesIO binary stream object type is used - the older ones now only allow text.
  • Save the image data, in the BMP (Windows Bitmap/Device Independent Bitmap) file format,
    to the file object variable from the previous step. The method using PIL/Pillow first converts
    this data with .convert("RGB") on the variable containing it.
  • Get the full contents of the file object variable memory buffer as binary data (bytes object),
    slice it from position 14 to remove the 14-byte header of the BMP/DIB file format, then save it
    as a variable. The method says the slicing of this data works on 32 or 64 bit systems but
    needs the Windows clipboard API so doesn't work for a different file format.
  • Close the memory buffer and copy the image data from the previous step to the clipboard.
    The method does this on Windows using the win32clipboard part of an extension module -
    it opens the clipboard for use, clears it, sets its value to the image data variable from the
    previous step (using the BMP/DIB type) then closes the open clipboard.

Also, there's a simple cross-platform clipboard text module called Pyperclip, which is
only a single file for version 1.5.6 and maybe has code that could process image data.

Edward
  • 1,062
  • 1
  • 17
  • 39
  • 1
    What OS are you trying to do this on? – Martijn Pieters Jun 29 '14 at 08:58
  • Does [this](http://coffeeghost.net/src/pyperclip.py) not work for you? – Burhan Khalid Jun 29 '14 at 09:57
  • Have you even *tried* the [tkinter-based solution](http://stackoverflow.com/questions/579687/how-do-i-copy-a-string-to-the-clipboard-on-windows-using-python)? If you put it in a script and run the script, the window is not open long enough to even notice. – John Y Jun 29 '14 at 21:34
  • @BurhanKhalid Pyperclip is "A cross-platform clipboard module" and is a single file that can be included in the same folder as program code to avoid installing it, however the Tkinter solution uses code built-in with Python. Also it only handles plain text currently so can't be used for images in the clipboard (my second request). – Edward Sep 28 '17 at 15:51
  • @JohnY I looked at your comment a year or two ago and have accepted the Tkinter-based solution for replacing/returning clipboard text. See my answer below for a simple Python function using that built-in module. However, it only handles plain text currently so can't be used for images in the clipboard (my second request). – Edward Oct 22 '17 at 12:03
  • There's now a few feature requests for *pyperclip* like [*Save bitmap to clipboard*](https://github.com/asweigart/pyperclip/issues/48) to add support for different data formats. Also, referenced there is [another module](https://pypi.org/project/jaraco.clipboard/), based on *pyperclip* and *xerox*, that supports other formats but only for MacOS (HTML) and Windows (HTML and images). – Edward Nov 16 '17 at 22:35

5 Answers5

1

Question: How to add/get image data in the OS clipboard using Python?

I show only get:
This example is using the built-in Tkinter module to get image data from CLIPBOARD.
Tested only on Linux, but should be a cross-platform solution.

enter image description here enter image description here

Note: The first paste of the shown 387x388 GIF, takes 4 seconds.


Core point: You have to use a MIME-Type, to requests a image.

.clipboard_get(type='image/png')

Verfied with, 'GIF', 'PNG' and 'JPEG', as source image data, using application, GIMP and PyCharm. With type='image/png' you allways get image data of type 'PNG' if the source app support this.


Reference:

  • clippboard_get(type=<string>)

    Retrieve data from the clipboard. Type specifies the form in which the data is to be returned and should be an atom name such as STRING or FILE_NAME. Type defaults on modern X11 systems to UTF8_STRING.


Data format:

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

The data is divided into fields separated by white space; each field is converted to its atom value, and the 32-bit atom value is transmitted instead of the atom name.

After removing the white space and casting with int(<field>, 0):

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

Exception: If no selection at all or the source app does not provide '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)

Tested with Python: 3.5 - 'TclVersion': 8.6 'TkVersion': 8.6

Community
  • 1
  • 1
stovfl
  • 14,998
  • 7
  • 24
  • 51
0

I don't think you could interact with the clipboard without external module.

Clipboard APIs are different from different Operating systems.

I suggest you to use the clipboard module.

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

fluke
  • 660
  • 8
  • 16
  • 1
    Yet `clipboard` and `pyperclip` manage it without external modules. Sure, a library can help you wrap the details, but that doesn't mean you cannot do this without one. – Martijn Pieters Jun 29 '14 at 08:59
  • As far as I know the only cross-platform solution comes with python is in TK, but the question asker don't want to use it. If you want to implement the clipboard feature manually you may use some technique to communicate with the OS such as system(), win32api, pyqt etc. If don't want to download external module when deploying, try to include then within the source code. – fluke Jun 29 '14 at 09:06
  • Yes, I would like a no module answer please. – Edward Oct 10 '14 at 16:35
  • 1
    Distribute the necessary modules with your code, or if you insist, copy the relevant portion of the xerox module and sub-modules it uses to your source code. – Chris Johnson Oct 10 '14 at 21:04
0

The xerox library is simple and capable.

Chris Johnson
  • 20,650
  • 6
  • 81
  • 80
0

Here's a Python function based on this answer that replaces/returns clipboard text using 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

This method creates a quickly hidden window which is closed quickly so
that shouldn't be a problem. Also, it only supports using plain text in the
clipboard, not images which I asked for in the question above.

Edward
  • 1,062
  • 1
  • 17
  • 39
-2

As stated by Martin---

Pyperclip is definitely a good option and works like a charm.

I don't know why you shouldn't be using it.

Its as simple as 3 lines below,

import pyperclip
pyperclip.copy('The text to be copied to the clipboard.')
paste= pyperclip.paste()
Md. Mohsin
  • 1,822
  • 3
  • 19
  • 34
  • 1
    Pyperclip is "A cross-platform clipboard module" and is a single file that can be included in the same folder as program code to avoid installing it, however the Tkinter solution uses code built-in with Python. Also it only handles plain text currently so can't be used for images in the clipboard (my second request). – Edward Sep 28 '17 at 15:54