Guarde el contenido de un patrón Gtk.DrawingArea o Cairo en una imagen en el disco

Tengo un pequeño proyecto PyGI que utiliza una superficie de imagen de El Cairo , que luego escala con un patrón de superficie y renderizo en un Gtk.DrawingArea.

Me gustaría escribir la versión escalada en un archivo PNG. He intentado escribir desde la superficie original con Surface.write_to_png () , pero solo escribe en el tamaño original (es decir, sin escala), así que estoy atascado allí.

Entonces pensé que tal vez podría obtener la imagen renderizada de Gtk.DrawingArea y escribirla en el disco, pero no he descubierto cómo hacerlo en PyGI (esto parece ser solo posible en GTK + 2; guarde gtk.DrawingArea to archivo ). Así que estoy tratando de averiguar cómo puedo escribir mi imagen escalada en el disco.

Aquí está el código que crea la superficie, la escala y la representa:

def on_drawingarea1_draw (self, widget, ctx, data=None): # 'widget' is a Gtk.DrawingArea # 'ctx' is the Cairo context text = self.ui.entry1.get_text() if text == '': return # Get the data and encode it into the image version, size, im = qrencode.encode(text) im = im.convert('RGBA') # Cairo expects RGB # Create a pixel array from the PIL image bytearr = array.array('B', im.tostring()) height, width = im.size # Convert the PIL image to a Cairo surface self.surface = cairo.ImageSurface.create_for_data(bytearr, cairo.FORMAT_ARGB32, width, height, width * 4) # Scale the image imgpat = cairo.SurfacePattern(self.surface) scaler = cairo.Matrix() scaler.scale(1.0/self.scale_factor, 1.0/self.scale_factor) imgpat.set_matrix(scaler) ctx.set_source(imgpat) # Render the image ctx.paint() 

Y aquí está el código para escribir la superficie en un archivo PNG:

 def on_toolbuttonSave_clicked(self, widget, data=None): if not self.surface: return # The following two lines did not seem to work # ctx = cairo.Context(self.surface) # ctx.scale(self.scale_factor, self.scale_factor) self.surface.write_to_png('/tmp/test.png') 

Así que escribir la superficie crea una imagen sin escala, y tampoco hay ningún método de escritura en el cairo.SurfacePattern.

Mi último recurso es buscar la imagen escalada como se representa en gtk.DrawingArea, colocarla en un GtkPixbuf.Pixbuf o en una nueva superficie, y luego escribirla en el disco. El enfoque pixbuf pareció funcionar en GTK + 2, pero no en GTK + 3.

Entonces, ¿alguien sabe cómo puedo escribir la imagen escalada en el disco?

Ok, encontré una manera:

Recordando que Gtk.DrawingArea deriva de Gtk.Window , podría usar la función Gdk.pixbuf_get_from_window() para obtener el contenido del área de dibujo en una función GdkPixbuf.Pixbuf y luego usar la función GdkPixbuf.Pixbuf.savev() como una imagen en el disco.

 def drawing_area_write(self): # drawingarea1 is a Gtk.DrawingArea window = self.ui.drawingarea1.get_window() # Some code to get the coordinates for the image, which is centered in the # in the drawing area. You can ignore it for the purpose of this example src_x, src_y = self.get_centered_coordinates(self.ui.drawingarea1, self.surface) image_height = self.surface.get_height() * self.scale_factor image_width = self.surface.get_width() * self.scale_factor # Fetch what we rendered on the drawing area into a pixbuf pixbuf = Gdk.pixbuf_get_from_window(window, src_x, src_y, image_width, image_height) # Write the pixbuf as a PNG image to disk pixbuf.savev('/tmp/testimage.png', 'png', [], []) 

Si bien esto funciona, aún sería bueno ver si alguien podría confirmar que esta es la forma correcta o si hay alguna otra alternativa.

Encontré otro enfoque, usando el contexto de El Cairo pasado al controlador de eventos de dibujo, pero resultó en la captura de una región de la ventana principal que era más grande que el DrawingArea.

Lo que funcionó para mí fue utilizar PixBuf como lo has mostrado, pero primero debes llamar al método queue_draw () para DrawingArea, para forzar una representación completa y esperar a que se procese el evento (lo suficientemente fácil, ya tenía un controlador de dibujo ). De lo contrario, las imágenes resultantes pueden estar parcialmente sin dibujar.