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)
Answer from Luis Villamil on Stack OverflowI 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)
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.
After I found out my original answer doesn't work for most images, I did some research and constructed a working solution. Unfortunately, it has a few drawbacks:
- It may not work for all apps (it does work for Discord, though).
- It can't be used to copy images from memory, only from an existing file.
- It is definitely not cross-platform (I doubt it works on older versions of Windows, even. It seems to work fine on Windows 10, at least).
The solution utilizes pywin32 and is as follows:
import os
import win32clipboard as clp
file_path = 'test.png'
clp.OpenClipboard()
clp.EmptyClipboard()
# This works for Discord, but not for Paint.NET:
wide_path = os.path.abspath(file_path).encode('utf-16-le') + b'\0'
clp.SetClipboardData(clp.RegisterClipboardFormat('FileNameW'), wide_path)
# This works for Paint.NET, but not for Discord:
file = open(file_path, 'rb')
clp.SetClipboardData(clp.RegisterClipboardFormat('image/png'), file.read())
clp.CloseClipboard()
I encountered the same issue today. I found out it's possible to use Python bindings for Magick++ (I used Wand) to copy an image with transparency. You can then paste it into Discord, Paint.NET and probably other apps as well.
Here's how you can do it with Wand:
from wand.image import Image
Image(filename='test.png').save(filename='clipboard:')
Edit: Doesn't work for all images.
Edit 2: I found another solution that could work better in your case. I posted it in a separate answer.
How to copy an image to clipboard with python
pywin32 - How do I read a jpg or png from the windows clipboard in python and vice versa? - Stack Overflow
Is it possible to use Python to copy an image to the Windows clipboard without losing its transparency in the process? - Stack Overflow
Write image to Windows clipboard in python with PIL and win32clipboard? - Stack Overflow
» pip install pyperclipimg
Hi,
I am making a program that copies the an images from the downloads folder as soon as I download something from the internet. I am using watchdogs module for observing the folder but the problem is I don’t know how to copy an image to clipboard. There is no good solution on the internet for this problem. PLEASE HELP GUYS ! I Will award the best answer 😇
I would just use Pillow:
from PIL import ImageGrab
im = ImageGrab.grabclipboard()
im.save('somefile.png','PNG')
You need to pass a parameter to GetClipboardData specifying the format of the data you're looking for. You can use EnumClipboardFormats to see the formats that are available - when I copy something in Explorer there are 15 formats available to me.
Edit 2: Here's the code to get a filename after you've copied a file in Explorer. The answer will be completely different if you've copied an image from within a program, a browser for example.
import win32clipboard
win32clipboard.OpenClipboard()
filename_format = win32clipboard.RegisterClipboardFormat('FileName')
if win32clipboard.IsClipboardFormatAvailable(filename_format):
input_filename = win32clipboard.GetClipboardData(filename_format)
win32clipboard.CloseClipboard()
Edit 3: From the comments it's clear you have an actual image in the clipboard, not the filename of an image file. You've stated that you can't use PIL, so:
import win32clipboard
win32clipboard.OpenClipboard()
if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_DIB):
data = win32clipboard.GetClipboardData(win32clipboard.CF_DIB)
win32clipboard.CloseClipboard()
At this point you have a string (in Python 2) or bytes (in Python 3) that contains the image data. The only format you'll be able to save is .BMP, and you'll have to decode the BITMAPINFOHEADER to get the parameters for a BITMAPFILEHEADER that needs to be written to the front of the file.
» pip install jaraco.clipboard
scrot + xclip
You can use scrot with xclip to take a screenshot and copy it to clipboard.
scrot '/tmp/%F_%T_$wx$h.png' -e 'xclip -selection clipboard -target image/png -i $f'
It will capture whole of your screen and copy the image to clipboard. If you want to capture current window then use -u flag. For selection of particular area, you can add -s flag. See $ man scrot for more options.
It will store your screenshot in /tmp directory. You can change that directory wherever you want it to get stored. Files from /tmp directory usually gets deleted after each reboot. If you want to immediately remove the stored file, then do something like:
scrot -w '/tmp/%F_%T_$wx$h.png' -e 'xclip -selection clipboard -target image/png -i $f && rm $f'
As I read in other comments, you need it for copying a screenshot to the clipboard. I hope this answers your question.
If you just need to copy an already existing image file to clipboard:
cat 2018-06-16-224938_670x730_scrot.png | xclip -selection clipboard -target image/png -i
You can set keyboard shortcuts/keybindings according to your current Desktop Environment/window manager.
Bonus
Explanation of /tmp/%F_%T_$wx$h.png:
It's being used as the file name. These are called format specifiers. They are of two type: starting with % or $.
%F Equivalent to %Y-%m-%d (the ISO 8601 date format). %T The time in 24-hour notation (%H:%M:%S).
%F_%T_ will print something like: 2018-06-17_02:52:19_ i.e. your current timestamp. You can customize the format as per your requirements. See $ man strftime for more help.
$wx$h are part of the scrot's internal specifiers.
$w image width $h image height
So the final file name will look something like 2018-06-17_02:52:19_1365x384.png.
First, install python, and pygtk
sudo apt-get install python pygtk
Now save the following script somewhere as imgclip.py (see https://stackoverflow.com/questions/3571855/pasting-image-to-clipboard-in-python-in-linux)
#! /usr/bin/python
import pygtk
pygtk.require('2.0')
import gtk
import os
import sys
def copy_image(f):
assert os.path.exists(f), "file does not exist"
image = gtk.gdk.pixbuf_new_from_file(f)
clipboard = gtk.clipboard_get()
clipboard.set_image(image)
clipboard.store()
copy_image(sys.argv[1]);
To use it:
python /path/to/imgclip.py filename.png
Note: tested pasting in gimp and xournal. Note: this is for gnome desktop (hence gtk). I bet there's something similar for kde
from cStringIO 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)
The file header off-set of BMP is 14 bytes. Well, BMP is also known as the device independent bitmap (DIB) file format, so you don't need to worried about the magic number 14.
FYI, it does need a windows clipboard API. Hence you can use BMP but can't use
image.convert("RGB").save(output, "PNG")
data = output.getvalue()[8:]
even you know the offset is 8 for PNG.