I'm working with a canvas in Tkinter, and I'm trying to copy the contents of that canvas to the clipboard.
I am able to solve this by creating a file, and then copy the content of that file into the clipboard with xclip -selection clipboard -t image/png -i temp_file.png
, but I want to use a buffer instead, allowing the user to copy it directly to the clipboard without touching the filesystem of the user.
To use xclip
's input function, I require to give a filename, and not a string.
I can circumvent this with echo/cat as cat temp_file.png < echo | xclip -selection clipboard -t image/png -i
or cat file_name.png | xclip -selection clipboard -t image/png -i
in the bash-line.
I have successfully been able to use the buffer to store the canvas, as such:
memory = io.BytesIO()
img.save(memory, format="png")
return memory
and can save the picture to a file as this:
img = pil.Image.open(memory)
img.save("file_name.png", format="png")
As far as I have understood, from pil's documentation, pil.Image.open
is the same as the built-in open()
function. Nevertheless, when trying to use open() to read the file, it claims BytesIO is not a valid file. Not a major problem, I guess.
I can read the contents of the buffer with memory.getvalue()
, and then strip the surrouding b'...'
with [2:-1]. I then replace all the '
in the string with \'
, so I can surround it with single quotation marks, and end up echoing said string with the command I used on a file earlier.
img_data = str(img_memory.getvalue())[2:-1]
img_data = img_data.replace("'", "\'")#.replace("`", "\`")
img_data = "'" + img_data + "'"
The output of cat file_name.png
is pretty much the same as the output of the string I'm giving echo
in my subprocess, but the following doesn't seem to do the job for me, as my clipboard remains untouched:
bash_cmd = f"echo -n {img_data} | xclip -selection clipboard -t image/png -i"
p = sp.Popen(bash_cmd, shell=True, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
but
bash_cmd = f"xclip -selection clipboard -t image/png -i file_name.png"
p = sp.Popen(bash_cmd, shell=True, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
does work.
tl;dr
What am I doing wrong? Am I altering the contents of the file, and creating a corrupt image, which is then copied?
How can I properly output the contents of a io.BufferIO
into my clipboard (mainly on Unix/Linux, but also on MacOS/Windows)?