xpt
xpt

Reputation: 23084

Copy image to clipboard?

First of all, the question on SO copy image to clipboard in python leads to answer Write image to Windows clipboard in python with PIL and win32clipboard?, which was only good for Python 2.x. -- I tried it and it didn't work. I overcame one problem: StringIO and cStringIO modules are gone in Python 3.0:, but bumped into another one:

TypeError: string argument expected, got 'bytes'

Hence, re-asking the same question again for Python 3 -- How to copy image to clipboard in Python 3? Here is the code I've got so far:

from io import StringIO
import win32clipboard
from PIL import Image

def send_to_clipboard(clip_type, data):
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(clip_type, data)
    win32clipboard.CloseClipboard()

filepath = 'image.jpg'
image = Image.open(filepath)

output = StringIO()
image.convert("RGB").save(output, "BMP")
data = output.getvalue()[14:]
output.close()

send_to_clipboard(win32clipboard.CF_DIB, data)

Thanks

Upvotes: 18

Views: 26093

Answers (8)

Controller816
Controller816

Reputation: 11

from io import BytesIO
import win32clipboard
from PIL import Image
import pyperclip


def copy_img(filepath):
    def send_to_clipboard(clip_type, data):
        win32clipboard.OpenClipboard()
        # win32clipboard.EmptyClipboard()
        win32clipboard.SetClipboardData(clip_type, data)
        win32clipboard.CloseClipboard()

    image = Image.open(filepath)

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

    send_to_clipboard(win32clipboard.CF_DIB, data)
    return None

def copy_text(filepath):
    with open(filepath, "r") as file:
        st = file.read()
        pyperclip.copy(st)
        file.close()
    return None

Will this break anything on windows?

I commented out the empty clipboard part because I have pinned thing in my clipboard, will it delete them?

Upvotes: 0

catichenor
catichenor

Reputation: 121

The winclip32 suggestion doesn't work by itself, but works pretty well combined with the other answers:

from io import BytesIO

import winclip32

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

winclip32.set_clipboard_data(winclip32.BITMAPINFO_STD_STRUCTURE, data)

Upvotes: 1

Joao Victor
Joao Victor

Reputation: 600

With those imports above, a masterpiece

def send_to_clipboard(clip_type, filepath):
    
    image = Image.open(filepath)

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

    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(clip_type, data)
    win32clipboard.CloseClipboard()

send_to_clipboard(win32clipboard.CF_DIB, 'imagem.png')

Upvotes: 3

ShadowRanger
ShadowRanger

Reputation: 155704

You don't want StringIO here. Images are raw binary data, and in Py3, str is purely for text; bytes and bytes-like objects (bytearray, contiguous memoryviews, mmaps) are for binary data. To replace Py2's StringIO.StringIO for binary data, you want to use io.BytesIO in Python 3, not io.StringIO.

Upvotes: 12

PythonProgrammi
PythonProgrammi

Reputation: 23463

This is a working app to grab part of the screen as images, once you click on the yellow button it appears in a window made with tkinter, you have to click on top left and then bottom down of an imaginary rectangle that will be the portion of the screen captured. Once you clicked ont the bottom down part of this imaginary rectangle the portion of the screen will be captured. Now open some app like work and press control + v to see the image that has been copied pasted on the app.

# grabscreen.py

import pyscreenshot as ImageGrab
import os
from pynput.mouse import Listener
import sys
import tkinter as tk
from PIL import Image

from io import BytesIO
import win32clipboard


''' Derives from my script grab (use this to show text in a pic and
transform in audio)


'''

def send_to_clipboard(clip_type, data):
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(clip_type, data)
    win32clipboard.CloseClipboard()

def grab(x, y, w, h):
    im = ImageGrab.grab(bbox=(x, y, w, h))
    im.save('im.png')
    image = Image.open("im.png")
    output = BytesIO()
    image.convert("RGB").save(output, "BMP")
    data = output.getvalue()[14:]
    output.close()
    send_to_clipboard(win32clipboard.CF_DIB, data)


click1 = 0
x1 = 0
y1 = 0
def on_click(x, y, button, pressed):
    global click1, x1, y1, listener
    
    if pressed:
        if click1 == 0:
            x1 = x
            y1 = y
            click1 = 1
        else:
            grab(x1, y1, x, y)
            listener.stop()
            sys.exit()
def start():
    global listener

    # root.destroy()
    print("Click once on top left and once on bottom right")
    # with Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:
    with Listener(on_click=on_click) as listener:
        listener.join()
        # listener.stop()
        # sys.exit()

root = tk.Tk()
root.geometry("400x200")
'''
when you click on this button goes to start
in start there i a listener and when you click it sends you to on_click
in on_click it makes you click twice and then goes to grab
in grab it uses pyscreenshot functions to grab the image and save it
we do not use ocr here, to do it use the grab.py file
'''
but = tk.Button(root, text="GRAB GET IMAGE", command=start, width=20,height=10, bg="gold")
but.pack()

root.mainloop()

See ya

Upvotes: 2

Luis Villamil
Luis Villamil

Reputation: 166

I did copy the code and replace the StringIO with BytesIO and it worked! (with *.jpg and *.png files) Thank you so much!

from io import BytesIO
import win32clipboard
from PIL import Image

def send_to_clipboard(clip_type, data):
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(clip_type, data)
    win32clipboard.CloseClipboard()

filepath = 'Ico2.png'
image = Image.open(filepath)

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

send_to_clipboard(win32clipboard.CF_DIB, data)

Upvotes: 15

canbax
canbax

Reputation: 3856

For those who want to copy-paste

# parameter must be a PIL image 
def send_to_clipboard(image):
    output = BytesIO()
    image.convert('RGB').save(output, 'BMP')
    data = output.getvalue()[14:]
    output.close()

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

Upvotes: 5

pypcdev
pypcdev

Reputation: 11

You can copy bitmap image to clipboard using winclip32 install:

pip install winclip32

copy:

import winclip32
winclip32.set_clipboard_data(winclip32.BITMAPINFO_STD_STRUCTURE, your_binary_here)

Upvotes: 1

Related Questions