2012-01-17 50 views
1

我有一個使用Cairo image surface的小型PyGI項目,然後使用surface pattern進行縮放並在Gtk.DrawingArea上呈現。將Gtk.DrawingArea或Cairo模式的內容保存到磁盤上的圖像

我想寫縮放的版本到PNG文件。我試圖用Surface.write_to_png()從原始表面寫入,但它只寫入原始(即未縮放)的大小,所以我卡在那裏。

然後我想我也許可以從Gtk.DrawingArea中獲取渲染圖像並將其寫入磁盤,但我還沒有發現如何在PyGI中執行此操作(這似乎只在GTK + 2中可用 - save gtk.DrawingArea to file )。所以我想弄清楚如何將縮放後的圖像寫入磁盤。

下面是一個創建表面的代碼,擴展它,使得它:

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

好吧,我發現了一種方法:

記住,Gtk.DrawingAreaGtk.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

我發現了另一種方法,使用傳遞給繪製事件處理程序的Cairo上下文,但它導致捕獲大於DrawingArea的父窗口區域。

對我來說有效的是使用PixBuf,正如你所示,但首先調用DrawingArea的queue_draw()方法,強制完成渲染,並等待事件被處理(很簡單,我已經有一個繪圖處理程序)。否則,最終的圖像可能會被部分取消。