1

我有一个使用Cairo 图像表面的小型 PyGI 项目,然后我使用表面图案对其进行缩放并在 Gtk.DrawingArea 上进行渲染。

我想将缩放版本写入 PNG 文件。我尝试使用Surface.write_to_png()从原始表面写入,但它只写入原始(即非缩放)大小,所以我被困在那里。

然后我想我也许可以从 Gtk.DrawingArea 获取渲染图像并将其写入磁盘,但我还没有找到如何在 PyGI 中做到这一点(这似乎只有在 GTK+ 2 中才有可能 -将 gtk.DrawingArea 保存到文件)。所以我试图弄清楚如何将我的缩放图像写入磁盘。

下面是创建表面、放大和渲染表面的代码:

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 中也没有 write 方法。

我最后的手段是获取在 gtk.DrawingArea 中呈现的缩放图像,将其放入 GtkPixbuf.Pixbuf 或新表面,然后将其写入磁盘。pixbuf 方法似乎适用于 GTK+ 2,但不适用于 GTK+ 3。

那么有谁知道我如何将缩放后的图像写入磁盘?

4

2 回答 2

5

好的,我找到了一种方法:

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

虽然这可行,但仍然很高兴看到有人可以确认这是正确的方法,或者看看是否有其他选择。

于 2012-01-18T19:04:20.573 回答
0

我找到了另一种方法,使用传递给绘图事件处理程序的 Cairo 上下文,但它导致捕获的父窗口区域大于 DrawingArea。

对我有用的是使用您所展示的 PixBuf,但首先为 DrawingArea 调用 queue_draw() 方法,强制进行完整渲染,并等待处理事件(很简单,我已经有了一个绘图处理程序)。否则,生成的图像可能部分未绘制。

于 2015-01-20T06:06:15.513 回答