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にも書き込みメソッドはありません。

私の最後の手段は、gtk.DrawingAreaでレンダリングされたスケーリングされた画像をフェッチし、それをGtkPixbuf.Pixbufまたは新しいサーフェスに配置して、それをディスクに書き込むことです。pixbufアプローチはGTK+2で機能するように見えましたが、GTK+3では機能しませんでした。

では、スケーリングされた画像をディスクに書き込む方法を知っている人はいますか?

4

2 に答える 2

5

わかりました、私は方法を見つけました:

Gtk.DrawingAreaはGtk.Windowから派生していることを思い出して、この関数を使用して描画領域のコンテンツをGdkPixbuf.Pixbufに取り込み、この関数を使用してpixbufをディスク上の画像として書き込むことができます。Gdk.pixbuf_get_from_window()GdkPixbuf.Pixbuf.savev()

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 に答える