¿Cómo convertir un archivo PostScript de canvas tkinter de Python en un archivo de imagen legible por el PIL?

Así que he creado una función en mi progtwig que le permite al usuario guardar lo que dibuja en el canvas de Turtle como un archivo Postscript con su propio nombre. Sin embargo, ha habido problemas con algunos colores que no aparecen en la salida según la naturaleza de los archivos Postscript y, además, los archivos Postscript simplemente no se abren en otras plataformas. Así que he decidido guardar el archivo postscript como una imagen JPEG ya que el archivo JPEG debería poder abrirse en muchas plataformas, ojalá pueda mostrar todos los colores del canvas, y debería tener una resolución más alta que el archivo postscript. Entonces, para hacer eso, he intentado, usando la PIL, lo siguiente en mi función de guardar:

def savefirst(): cnv = getscreen().getcanvas() global hen fev = cnv.postscript(file = 'InitialFile.ps', colormode = 'color') hen = filedialog.asksaveasfilename(defaultextension = '.jpg') im = Image.open(fev) print(im) im.save(hen + '.jpg') 

Sin embargo, cada vez que ejecuto esto, obtengo este error:

 line 2391, in savefirst im = Image.open(fev) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/PIL/Image.py", line 2263, in open fp = io.BytesIO(fp.read()) AttributeError: 'str' object has no attribute 'read' 

Aparentemente, no puede leer el archivo postscript ya que no es , según lo que sé, una imagen en sí misma, por lo que primero debe convertirse en una imagen, ENTONCES se lee como una imagen, y luego finalmente se convierte y se guarda como un archivo JPEG. La pregunta es, ¿cómo podría convertir primero el archivo postscript en un archivo de imagen DENTRO del progtwig posiblemente utilizando la biblioteca de imágenes de Python? Mirando a su alrededor SO y Google no han sido de ayuda, por lo que cualquier ayuda de los usuarios de SO es muy apreciada.

EDITAR: Siguiendo unubuntu's consejos unubuntu's , ahora tengo esto para mi función de guardar:

 def savefirst(): cnv = getscreen().getcanvas() global hen ps = cnv.postscript(colormode = 'color') hen = filedialog.asksaveasfilename(defaultextension = '.jpg') im = Image.open(io.BytesIO(ps.encode('utf-8'))) im.save(hen + '.jpg') 

Sin embargo, ahora, cuando ejecuto eso, me sale este error:

 line 2395, in savefirst im.save(hen + '.jpg') File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/PIL/Image.py", line 1646, in save self.load() File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/PIL/EpsImagePlugin.py", line 337, in load self.im = Ghostscript(self.tile, self.size, self.fp, scale) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/PIL/EpsImagePlugin.py", line 143, in Ghostscript stdout=subprocess.PIPE) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 950, in __init__ restre_signals, start_new_session) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 1544, in _execute_child raise child_exception_type(errno_num, err_msg) FileNotFoundError: [Errno 2] No such file or directory: 'gs' 

¿Qué es 'gs' y por qué me da este error ahora?

Si no proporciona el parámetro de archivo en la llamada a cnv.postscript , entonces cnv.postscript devuelve el PostScript como una cadena (unicode). Luego, puede convertir el io.BytesIO Unicode en bytes y io.BytesIO a io.BytesIO y Image.open a Image.open . Image.open puede aceptar como primer argumento cualquier objeto similar a un archivo que implemente métodos de read , seek y tell .

 import io def savefirst(): cnv = getscreen().getcanvas() global hen ps = cnv.postscript(colormode = 'color') hen = filedialog.asksaveasfilename(defaultextension = '.jpg') im = Image.open(io.BytesIO(ps.encode('utf-8'))) im.save(hen + '.jpg') 

Por ejemplo, tomando mucho del código de A. Rodas ,

 import Tkinter as tk import subprocess import os import io from PIL import Image class App(tk.Tk): def __init__(self): tk.Tk.__init__(self) self.line_start = None self.canvas = tk.Canvas(self, width=300, height=300, bg="white") self.canvas.bind("", lambda e: self.draw(ex, ey)) self.button = tk.Button(self, text="save", command=self.save) self.canvas.pack() self.button.pack(pady=10) def draw(self, x, y): if self.line_start: x_origin, y_origin = self.line_start self.canvas.create_line(x_origin, y_origin, x, y) self.line_start = x, y def save(self): ps = self.canvas.postscript(colormode='color') img = Image.open(io.BytesIO(ps.encode('utf-8'))) img.save('/tmp/test.jpg') app = App() app.mainloop() 

Agregando a la respuesta de Unutbu, también puede escribir los datos nuevamente en un objeto BytesIO, pero debe buscar el principio del búfer después de hacerlo. Aquí hay un ejemplo de matraz que muestra la imagen en el navegador:

 @app.route('/image.png', methods=['GET']) def image(): """Return png of current canvas""" ps = tkapp.canvas.postscript(colormode='color') out = BytesIO() Image.open(BytesIO(ps.encode('utf-8'))).save(out, format="PNG") out.seek(0) return send_file(out, mimetype='image/png')