Сохраните содержимое шаблона Gtk.DrawingArea или Cairo в изображение на диске - PullRequest
1 голос
/ 17 января 2012

У меня есть небольшой проект PyGI, в котором используется Каирская поверхность изображения , которую я затем масштабирую с рисунком поверхности и визуализирую на Gtk.DrawingArea.

Я хотел бы записать масштабированную версию в файл PNG. Я пытался писать с исходной поверхности с помощью Surface.write_to_png () , но он пишет только в исходном (т.е. немасштабированном) размере, поэтому я застрял там.

Тогда я подумал, что, возможно, смогу получить отрендеренное изображение из Gtk.DrawingArea и записать его на диск, но я не выяснил, как это сделать в PyGI (это возможно только в GTK + 2 - сохранить gtk. Рисование области в файл ). Поэтому я пытаюсь понять, как я могу записать мое масштабированное изображение на диск.

Вот код, который создает поверхность, масштабирует ее и отображает:

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()

А вот код для записи поверхности в файл 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')

Таким образом, запись поверхности создает немасштабированное изображение, и в cairo.SurfacePattern также нет метода записи.

Мое последнее средство - извлечь масштабированное изображение, отображаемое в gtk.DrawingArea, поместить его в GtkPixbuf.Pixbuf или на новую поверхность, а затем записать это на диск. Подход pixbuf, похоже, работал в GTK + 2, но не в GTK + 3.

Так кто-нибудь знает, как я могу записать масштабированное изображение на диск?

Ответы [ 2 ]

4 голосов
/ 18 января 2012

Хорошо, я нашел способ:

Помня, что Gtk.DrawingArea происходит от Gtk.Window , я мог бы использовать функцию Gdk.pixbuf_get_from_window(), чтобы получить содержимое области рисования в GdkPixbuf.Pixbuf. , а затем используйте функцию GdkPixbuf.Pixbuf.savev(), чтобы записать pixbuf как изображение на диск.

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', [], [])

Несмотря на то, что это работает, было бы неплохо посмотреть, сможет ли кто-нибудь подтвердить, что это правильный путь, или посмотреть, есть ли другая альтернатива.

0 голосов
/ 20 января 2015

Я нашел другой подход, использующий контекст Cairo, переданный в обработчик событий рисования, но он привел к захвату области родительского окна, которая была больше, чем DrawingArea.

Для меня сработало использование PixBuf, как вы показали, но сначала вызов метода queue_draw () для DrawingArea, чтобы вызвать полный рендеринг, и ожидание обработки события (достаточно просто, у меня уже было обработчик розыгрыша). В противном случае результирующие изображения могут быть частично неиспользованы.

...